From 4f170f4d40446f5aff5f4bf6c282613e7bb86443 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Wed, 19 May 2021 14:09:07 +0200 Subject: [PATCH 01/42] add support for taxonomies --- README.md | 6 ++- config/eloquent-driver.php | 8 ++++ src/ServiceProvider.php | 28 ++++++++++++ src/Taxonomies/Taxonomy.php | 42 ++++++++++++++++++ src/Taxonomies/TaxonomyModel.php | 22 ++++++++++ src/Taxonomies/TaxonomyRepository.php | 49 +++++++++++++++++++++ src/Taxonomies/Term.php | 61 +++++++++++++++++++++++++++ src/Taxonomies/TermModel.php | 22 ++++++++++ src/Taxonomies/TermQueryBuilder.php | 37 ++++++++++++++++ src/Taxonomies/TermRepository.php | 50 ++++++++++++++++++++++ 10 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 src/Taxonomies/Taxonomy.php create mode 100644 src/Taxonomies/TaxonomyModel.php create mode 100644 src/Taxonomies/TaxonomyRepository.php create mode 100644 src/Taxonomies/Term.php create mode 100644 src/Taxonomies/TermModel.php create mode 100644 src/Taxonomies/TermQueryBuilder.php create mode 100644 src/Taxonomies/TermRepository.php diff --git a/README.md b/README.md index 8acb7faf..db29fa6f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,11 @@ This package provides support for storing your Statamic data in a database rather than the filesystem. -This driver currently supports entries but not taxonomies, navigations, globals, or form submissions. We'll be working on those in the future. +Todo: +- [x] taxonomies +- [ ] navigations +- [ ] globals +- [ ] form submissions ## Installation diff --git a/config/eloquent-driver.php b/config/eloquent-driver.php index 98b04a26..88cd54e3 100644 --- a/config/eloquent-driver.php +++ b/config/eloquent-driver.php @@ -6,4 +6,12 @@ 'model' => \Statamic\Eloquent\Entries\EntryModel::class, ], + 'taxonomies' => [ + 'model' => \Statamic\Eloquent\Taxonomies\TaxonomyModel::class, + ], + + 'terms' => [ + 'model' => \Statamic\Eloquent\Taxonomies\TermModel::class, + ], + ]; diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 44f6cbfd..3bdf3143 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -4,11 +4,16 @@ use Statamic\Contracts\Entries\CollectionRepository as CollectionRepositoryContract; use Statamic\Contracts\Entries\EntryRepository as EntryRepositoryContract; +use Statamic\Contracts\Taxonomies\TaxonomyRepository as TaxonomyRepositoryContract; +use Statamic\Contracts\Taxonomies\TermRepository as TermRepositoryContract; use Statamic\Eloquent\Commands\ImportEntries; use Statamic\Eloquent\Entries\CollectionRepository; use Statamic\Eloquent\Entries\EntryModel; use Statamic\Eloquent\Entries\EntryQueryBuilder; use Statamic\Eloquent\Entries\EntryRepository; +use Statamic\Eloquent\Taxonomies\TaxonomyRepository; +use Statamic\Eloquent\Taxonomies\TermQueryBuilder; +use Statamic\Eloquent\Taxonomies\TermRepository; use Statamic\Providers\AddonServiceProvider; use Statamic\Statamic; @@ -32,6 +37,7 @@ public function boot() public function register() { $this->registerEntries(); + $this->registerTaxonomies(); } protected function registerEntries() @@ -49,4 +55,26 @@ protected function registerEntries() return config('statamic-eloquent-driver.entries.model'); }); } + + public function registerTaxonomies() + { + Statamic::repository(TaxonomyRepositoryContract::class, TaxonomyRepository::class); + Statamic::repository(TermRepositoryContract::class, TermRepository::class); + + $this->app->bind(TermQueryBuilder::class, function ($app) { + return new TermQueryBuilder( + $app['statamic.eloquent.terms.model']::query() + ); + }); + + $this->app->bind('statamic.eloquent.terms.model', function () { + return config('statamic-eloquent-driver.terms.model'); + }); + + $this->app->bind('statamic.eloquent.taxonomies.model', function () { + return config('statamic-eloquent-driver.taxonomies.model'); + }); + + + } } diff --git a/src/Taxonomies/Taxonomy.php b/src/Taxonomies/Taxonomy.php new file mode 100644 index 00000000..58af216b --- /dev/null +++ b/src/Taxonomies/Taxonomy.php @@ -0,0 +1,42 @@ +handle($model->handle) + ->title($model->title) + ->model($model); + } + + public function toModel() + { + $class = app('statamic.eloquent.taxonomies.model'); + + return $class::findOrNew($this->id())->fill([ + 'handle' => $this->handle(), + 'title' => $this->title(), + ]); + } + + public function model($model = null) + { + if (func_num_args() === 0) { + return $this->model; + } + + $this->model = $model; + + $this->id($model->id); + + return $this; + } +} diff --git a/src/Taxonomies/TaxonomyModel.php b/src/Taxonomies/TaxonomyModel.php new file mode 100644 index 00000000..f3c4bc3b --- /dev/null +++ b/src/Taxonomies/TaxonomyModel.php @@ -0,0 +1,22 @@ +getAttributeValue('data'), $key, parent::getAttribute($key)); + } +} diff --git a/src/Taxonomies/TaxonomyRepository.php b/src/Taxonomies/TaxonomyRepository.php new file mode 100644 index 00000000..b6cc7623 --- /dev/null +++ b/src/Taxonomies/TaxonomyRepository.php @@ -0,0 +1,49 @@ +map(function ($model) { + return Taxonomy::fromModel($model); + }); + } + + public static function bindings(): array + { + return [ + TaxonomyContract::class => Taxonomy::class, + ]; + } + + public function all(): Collection + { + return $this->transform(TaxonomyModel::all()); + } + + + public function findByHandle($handle): ?TaxonomyContract + { + return app(TaxonomyContract::class)->fromModel(TaxonomyModel::whereHandle($handle)->firstOrFail()); + } + + public function save($entry) + { + $model = $entry->toModel(); + + $model->save(); + + $entry->model($model->fresh()); + } + + public function delete($entry) + { + $entry->model()->delete(); + } +} diff --git a/src/Taxonomies/Term.php b/src/Taxonomies/Term.php new file mode 100644 index 00000000..a68e9631 --- /dev/null +++ b/src/Taxonomies/Term.php @@ -0,0 +1,61 @@ +slug($model->slug); + $term = $term->taxonomy($model->taxonomy); + $term = $term->data($model->data); + $term = $term->model($model); + $term = $term->blueprint($model->data['blueprint'] ?? null); + + + return $term; + } + + public function toModel() + { + $class = app('statamic.eloquent.terms.model'); + + $data = $this->data(); + + if ($this->blueprint && $this->taxonomy()->termBlueprints()->count() > 1) { + $data['blueprint'] = $this->blueprint; + } + return $class::findOrNew($this->model?->id)->fill([ + 'site' => $this->locale(), + 'slug' => $this->slug(), + 'uri' => $this->uri(), + 'taxonomy' => $this->taxonomy(), + 'data' => $data, + ]); + } + + public function model($model = null) + { + if (func_num_args() === 0) { + return $this->model; + } + + $this->model = $model; + + $this->id($model->id); + + return $this; + } + + public function lastModified() + { + return $this->model->updated_at; + } +} diff --git a/src/Taxonomies/TermModel.php b/src/Taxonomies/TermModel.php new file mode 100644 index 00000000..09f922d1 --- /dev/null +++ b/src/Taxonomies/TermModel.php @@ -0,0 +1,22 @@ + 'json', + ]; + + public function getAttribute($key) + { + return Arr::get($this->getAttributeValue('data'), $key, parent::getAttribute($key)); + } +} diff --git a/src/Taxonomies/TermQueryBuilder.php b/src/Taxonomies/TermQueryBuilder.php new file mode 100644 index 00000000..ef7978e2 --- /dev/null +++ b/src/Taxonomies/TermQueryBuilder.php @@ -0,0 +1,37 @@ +map(function ($model) { + return Term::fromModel($model); + }); + } + + protected function column($column) + { + if ($column == 'origin') { + $column = 'origin_id'; + } + + if (! in_array($column, $this->columns)) { + $column = 'data->'.$column; + } + + return $column; + } +} diff --git a/src/Taxonomies/TermRepository.php b/src/Taxonomies/TermRepository.php new file mode 100644 index 00000000..5289fa8d --- /dev/null +++ b/src/Taxonomies/TermRepository.php @@ -0,0 +1,50 @@ +ensureAssociations(); + + return app(TermQueryBuilder::class); + } + + public function find($id): ?Term + { + [$handle, $slug] = explode('::', $id); + + $term = $this->query() + ->where('taxonomy', $handle) + ->where('slug', $slug); + $term = $term->first(); + + return $term; + } + + public function save($entry) + { + $model = $entry->toModel(); + + $model->save(); + + $entry->model($model->fresh()); + } + + public function delete($entry) + { + $entry->model()->delete(); + } + + public static function bindings(): array + { + return [ + TermContract::class => Term::class, + ]; + } +} From b166029d3fbae0bf0221920d831d0a11a32eb337 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Wed, 19 May 2021 16:05:57 +0200 Subject: [PATCH 02/42] add db support for globals --- config/eloquent-driver.php | 8 ++++ src/Globals/GlobalRepository.php | 61 +++++++++++++++++++++++++++++++ src/Globals/GlobalSet.php | 63 ++++++++++++++++++++++++++++++++ src/Globals/GlobalSetModel.php | 24 ++++++++++++ src/Globals/Variables.php | 30 +++++++++++++++ src/Globals/VariablesModel.php | 24 ++++++++++++ src/ServiceProvider.php | 16 ++++++++ 7 files changed, 226 insertions(+) create mode 100644 src/Globals/GlobalRepository.php create mode 100644 src/Globals/GlobalSet.php create mode 100644 src/Globals/GlobalSetModel.php create mode 100644 src/Globals/Variables.php create mode 100644 src/Globals/VariablesModel.php diff --git a/config/eloquent-driver.php b/config/eloquent-driver.php index 88cd54e3..943df524 100644 --- a/config/eloquent-driver.php +++ b/config/eloquent-driver.php @@ -14,4 +14,12 @@ 'model' => \Statamic\Eloquent\Taxonomies\TermModel::class, ], + 'global-sets' => [ + 'model' => \Statamic\Eloquent\Globals\GlobalSetModel::class, + ], + + 'variables' => [ + 'model' => \Statamic\Eloquent\Globals\VariablesModel::class, + ], + ]; diff --git a/src/Globals/GlobalRepository.php b/src/Globals/GlobalRepository.php new file mode 100644 index 00000000..4e24b8dc --- /dev/null +++ b/src/Globals/GlobalRepository.php @@ -0,0 +1,61 @@ +map(function ($model) { + return GlobalSet::fromModel($model); + }); + } + + + public static function bindings(): array + { + return [ + GlobalSetContract::class => GlobalSet::class, + ]; + } + + public function find($handle): ?GlobalSetContract + { + return app(GlobalSetContract::class)->fromModel(GlobalSetModel::whereHandle($handle)->firstOrFail()); + } + + public function findByHandle($handle): ?GlobalSetContract + { + return app(GlobalSetContract::class)->fromModel(GlobalSetModel::whereHandle($handle)->firstOrFail()); + } + + public function all(): GlobalCollection + { + return $this->transform(GlobalSetModel::all()); + } + + + public function save($entry) + { + $model = $entry->toModel(); + + $model->save(); + + $entry->model($model->fresh()); + } + + public function delete($entry) + { + $entry->model()->delete(); + } +} diff --git a/src/Globals/GlobalSet.php b/src/Globals/GlobalSet.php new file mode 100644 index 00000000..c650b68a --- /dev/null +++ b/src/Globals/GlobalSet.php @@ -0,0 +1,63 @@ +handle($model->handle) + ->title($model->title) + ->model($model); + + foreach($model->localizations as $localization) { + $global->addLocalization(Variables::fromModel(VariablesModel::make($localization))); + } + + return $global; + } + + public function toModel() + { + $class = app('statamic.eloquent.global-sets.model'); + + $localizations = $this->localizations()->map(function($value, $key) { + return $value->toModel()->toArray(); + }); + + return $class::findOrNew($this->model?->id)->fill([ + 'handle' => $this->handle(), + 'title' => $this->title(), + 'localizations' => $localizations, + ]); + } + + public function makeLocalization($site) + { + return (new Variables) + ->globalSet($this) + ->locale($site); + } + + public function model($model = null) + { + if (func_num_args() === 0) { + return $this->model; + } + + $this->model = $model; + + $this->id($model->id); + + return $this; + } +} diff --git a/src/Globals/GlobalSetModel.php b/src/Globals/GlobalSetModel.php new file mode 100644 index 00000000..6896fd58 --- /dev/null +++ b/src/Globals/GlobalSetModel.php @@ -0,0 +1,24 @@ + 'json' + ]; + + public function getAttribute($key) + { + return Arr::get($this->getAttributeValue('data'), $key, parent::getAttribute($key)); + } +} diff --git a/src/Globals/Variables.php b/src/Globals/Variables.php new file mode 100644 index 00000000..5228d1b3 --- /dev/null +++ b/src/Globals/Variables.php @@ -0,0 +1,30 @@ +locale($model->locale) + ->data($model->data); + } + + public function toModel() + { + $class = app('statamic.eloquent.variables.model'); + + $data = $this->data(); + + return $class::make([ + 'locale' => $this->locale, + 'data' => $data , + ]); + } + +} diff --git a/src/Globals/VariablesModel.php b/src/Globals/VariablesModel.php new file mode 100644 index 00000000..178df0d6 --- /dev/null +++ b/src/Globals/VariablesModel.php @@ -0,0 +1,24 @@ +getAttributeValue('data'), $key, parent::getAttribute($key)); + } +} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 3bdf3143..428b0006 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -6,11 +6,13 @@ use Statamic\Contracts\Entries\EntryRepository as EntryRepositoryContract; use Statamic\Contracts\Taxonomies\TaxonomyRepository as TaxonomyRepositoryContract; use Statamic\Contracts\Taxonomies\TermRepository as TermRepositoryContract; +use Statamic\Contracts\Globals\GlobalRepository as GlobalRepositoryContract; use Statamic\Eloquent\Commands\ImportEntries; use Statamic\Eloquent\Entries\CollectionRepository; use Statamic\Eloquent\Entries\EntryModel; use Statamic\Eloquent\Entries\EntryQueryBuilder; use Statamic\Eloquent\Entries\EntryRepository; +use Statamic\Eloquent\Globals\GlobalRepository; use Statamic\Eloquent\Taxonomies\TaxonomyRepository; use Statamic\Eloquent\Taxonomies\TermQueryBuilder; use Statamic\Eloquent\Taxonomies\TermRepository; @@ -38,6 +40,7 @@ public function register() { $this->registerEntries(); $this->registerTaxonomies(); + $this->registerGlobals(); } protected function registerEntries() @@ -77,4 +80,17 @@ public function registerTaxonomies() } + + private function registerGlobals() + { + Statamic::repository(GlobalRepositoryContract::class, GlobalRepository::class); + + $this->app->bind('statamic.eloquent.global-sets.model', function () { + return config('statamic-eloquent-driver.global-sets.model'); + }); + + $this->app->bind('statamic.eloquent.variables.model', function () { + return config('statamic-eloquent-driver.variables.model'); + }); + } } From 19830acd2184b4ed50025d02f7065dfef5251c89 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Wed, 19 May 2021 16:06:09 +0200 Subject: [PATCH 03/42] rename terms table --- src/Taxonomies/TermModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Taxonomies/TermModel.php b/src/Taxonomies/TermModel.php index 09f922d1..35f17548 100644 --- a/src/Taxonomies/TermModel.php +++ b/src/Taxonomies/TermModel.php @@ -9,7 +9,7 @@ class TermModel extends Eloquent { protected $guarded = []; - protected $table = 'terms'; + protected $table = 'taxonomy_terms'; protected $casts = [ 'data' => 'json', From 9a21d896866346e8c9fa923a05b6f30149050f75 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Wed, 19 May 2021 16:10:29 +0200 Subject: [PATCH 04/42] fix taxonomy id --- src/Taxonomies/Taxonomy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Taxonomies/Taxonomy.php b/src/Taxonomies/Taxonomy.php index 58af216b..739ac833 100644 --- a/src/Taxonomies/Taxonomy.php +++ b/src/Taxonomies/Taxonomy.php @@ -21,7 +21,7 @@ public function toModel() { $class = app('statamic.eloquent.taxonomies.model'); - return $class::findOrNew($this->id())->fill([ + return $class::findOrNew($this->model?->id)->fill([ 'handle' => $this->handle(), 'title' => $this->title(), ]); From 3d5e4f131884fbb960a7ccee59ac0afbd693e6f7 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Wed, 19 May 2021 16:11:59 +0200 Subject: [PATCH 05/42] add migrations --- ...1_05_18_160811_create_taxonomies_table.php | 33 +++++++++++++++++ .../2021_05_19_082853_create_terms_table.php | 36 +++++++++++++++++++ ...2021_05_19_122354_create_globals_table.php | 34 ++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 database/migrations/2021_05_18_160811_create_taxonomies_table.php create mode 100644 database/migrations/2021_05_19_082853_create_terms_table.php create mode 100644 database/migrations/2021_05_19_122354_create_globals_table.php diff --git a/database/migrations/2021_05_18_160811_create_taxonomies_table.php b/database/migrations/2021_05_18_160811_create_taxonomies_table.php new file mode 100644 index 00000000..42a89579 --- /dev/null +++ b/database/migrations/2021_05_18_160811_create_taxonomies_table.php @@ -0,0 +1,33 @@ +increments('id'); + $table->string('handle'); + $table->string('title'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('taxonomies'); + } +} diff --git a/database/migrations/2021_05_19_082853_create_terms_table.php b/database/migrations/2021_05_19_082853_create_terms_table.php new file mode 100644 index 00000000..d9800956 --- /dev/null +++ b/database/migrations/2021_05_19_082853_create_terms_table.php @@ -0,0 +1,36 @@ +id(); + $table->string('site'); + $table->string('slug'); + $table->string('uri')->nullable(); + $table->string('taxonomy'); + $table->json('data'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('taxonomy_terms'); + } +} diff --git a/database/migrations/2021_05_19_122354_create_globals_table.php b/database/migrations/2021_05_19_122354_create_globals_table.php new file mode 100644 index 00000000..c9740310 --- /dev/null +++ b/database/migrations/2021_05_19_122354_create_globals_table.php @@ -0,0 +1,34 @@ +id(); + $table->string('handle'); + $table->string('title'); + $table->json('localizations'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('global_sets'); + } +} From f4559d91e47a73caf9a1250108de6e07bed36d4f Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Wed, 19 May 2021 16:12:18 +0200 Subject: [PATCH 06/42] update readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index db29fa6f..ccce7511 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,9 @@ This package provides support for storing your Statamic data in a database rathe Todo: - [x] taxonomies - [ ] navigations -- [ ] globals +- [x] globals - [ ] form submissions +- [ ] collections ## Installation From b1988f44a0c28d9ccfdd52f7024b851080ad2448 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Thu, 27 May 2021 09:29:58 +0200 Subject: [PATCH 07/42] allow taxonomy to be null --- src/Taxonomies/TaxonomyRepository.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Taxonomies/TaxonomyRepository.php b/src/Taxonomies/TaxonomyRepository.php index b6cc7623..17cfe4d7 100644 --- a/src/Taxonomies/TaxonomyRepository.php +++ b/src/Taxonomies/TaxonomyRepository.php @@ -6,6 +6,7 @@ use Illuminate\Support\Collection; use Statamic\Contracts\Taxonomies\Taxonomy as TaxonomyContract; use \Statamic\Stache\Repositories\TaxonomyRepository as StacheRepository; + class TaxonomyRepository extends StacheRepository { protected function transform($items, $columns = []) @@ -27,10 +28,12 @@ public function all(): Collection return $this->transform(TaxonomyModel::all()); } - public function findByHandle($handle): ?TaxonomyContract { - return app(TaxonomyContract::class)->fromModel(TaxonomyModel::whereHandle($handle)->firstOrFail()); + $taxonomyModel = TaxonomyModel::whereHandle($handle)->first(); + return $taxonomyModel + ? app(TaxonomyContract::class)->fromModel($taxonomyModel) + : null; } public function save($entry) From b34be341de5561db2833c69776864078b87f4143 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Thu, 27 May 2021 09:30:13 +0200 Subject: [PATCH 08/42] bring back global transform --- src/Globals/GlobalRepository.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Globals/GlobalRepository.php b/src/Globals/GlobalRepository.php index 4e24b8dc..b6597e59 100644 --- a/src/Globals/GlobalRepository.php +++ b/src/Globals/GlobalRepository.php @@ -13,7 +13,6 @@ class GlobalRepository extends StacheRepository { - protected function transform($items, $columns = []) { return GlobalCollection::make($items)->map(function ($model) { @@ -22,13 +21,6 @@ protected function transform($items, $columns = []) } - public static function bindings(): array - { - return [ - GlobalSetContract::class => GlobalSet::class, - ]; - } - public function find($handle): ?GlobalSetContract { return app(GlobalSetContract::class)->fromModel(GlobalSetModel::whereHandle($handle)->firstOrFail()); @@ -58,4 +50,11 @@ public function delete($entry) { $entry->model()->delete(); } + + public static function bindings(): array + { + return [ + GlobalSetContract::class => GlobalSet::class, + ]; + } } From 7bc9d423dbb6c6dbe2d68eb487f9b43674bb2079 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Thu, 27 May 2021 11:37:08 +0200 Subject: [PATCH 09/42] add db support for navigations --- README.md | 2 +- config/eloquent-driver.php | 8 +++ ..._05_19_143631_create_navigations_table.php | 37 ++++++++++++ ...7_082335_create_navigation_trees_table.php | 35 ++++++++++++ src/ServiceProvider.php | 22 +++++++- src/Structures/Nav.php | 56 +++++++++++++++++++ src/Structures/NavModel.php | 20 +++++++ src/Structures/NavTree.php | 46 +++++++++++++++ src/Structures/NavTreeModel.php | 18 ++++++ src/Structures/NavTreeRepository.php | 39 +++++++++++++ src/Structures/NavigationRepository.php | 55 ++++++++++++++++++ 11 files changed, 334 insertions(+), 4 deletions(-) create mode 100644 database/migrations/2021_05_19_143631_create_navigations_table.php create mode 100644 database/migrations/2021_05_27_082335_create_navigation_trees_table.php create mode 100644 src/Structures/Nav.php create mode 100644 src/Structures/NavModel.php create mode 100644 src/Structures/NavTree.php create mode 100644 src/Structures/NavTreeModel.php create mode 100644 src/Structures/NavTreeRepository.php create mode 100644 src/Structures/NavigationRepository.php diff --git a/README.md b/README.md index ccce7511..7d87975e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This package provides support for storing your Statamic data in a database rathe Todo: - [x] taxonomies -- [ ] navigations +- [x] navigations - [x] globals - [ ] form submissions - [ ] collections diff --git a/config/eloquent-driver.php b/config/eloquent-driver.php index 943df524..69a01a8d 100644 --- a/config/eloquent-driver.php +++ b/config/eloquent-driver.php @@ -22,4 +22,12 @@ 'model' => \Statamic\Eloquent\Globals\VariablesModel::class, ], + 'navigations' => [ + 'model' => \Statamic\Eloquent\Structures\NavModel::class, + ], + + 'nav-trees' => [ + 'model' => \Statamic\Eloquent\Structures\NavTreeModel::class, + ], + ]; diff --git a/database/migrations/2021_05_19_143631_create_navigations_table.php b/database/migrations/2021_05_19_143631_create_navigations_table.php new file mode 100644 index 00000000..a07b1fb2 --- /dev/null +++ b/database/migrations/2021_05_19_143631_create_navigations_table.php @@ -0,0 +1,37 @@ +id(); + $table->string('handle'); + $table->string('title'); + $table->json('collections')->nullable(); + $table->integer('maxDepth')->nullable(); + $table->boolean('expectsRoot')->default(false); + $table->string('initialPath')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('navigations'); + } +} diff --git a/database/migrations/2021_05_27_082335_create_navigation_trees_table.php b/database/migrations/2021_05_27_082335_create_navigation_trees_table.php new file mode 100644 index 00000000..e904826a --- /dev/null +++ b/database/migrations/2021_05_27_082335_create_navigation_trees_table.php @@ -0,0 +1,35 @@ +id(); + $table->string('handle'); + $table->string('initialPath')->nullable(); + $table->string('locale')->nullable(); + $table->json('tree')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('navigation_trees'); + } +} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 428b0006..eaadbc65 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -7,12 +7,15 @@ use Statamic\Contracts\Taxonomies\TaxonomyRepository as TaxonomyRepositoryContract; use Statamic\Contracts\Taxonomies\TermRepository as TermRepositoryContract; use Statamic\Contracts\Globals\GlobalRepository as GlobalRepositoryContract; +use Statamic\Contracts\Structures\NavigationRepository as NavigationRepositoryContract; +use Statamic\Contracts\Structures\NavTreeRepository as NavTreeRepositoryContract; use Statamic\Eloquent\Commands\ImportEntries; use Statamic\Eloquent\Entries\CollectionRepository; -use Statamic\Eloquent\Entries\EntryModel; use Statamic\Eloquent\Entries\EntryQueryBuilder; use Statamic\Eloquent\Entries\EntryRepository; use Statamic\Eloquent\Globals\GlobalRepository; +use Statamic\Eloquent\Structures\NavigationRepository; +use Statamic\Eloquent\Structures\NavTreeRepository; use Statamic\Eloquent\Taxonomies\TaxonomyRepository; use Statamic\Eloquent\Taxonomies\TermQueryBuilder; use Statamic\Eloquent\Taxonomies\TermRepository; @@ -41,6 +44,7 @@ public function register() $this->registerEntries(); $this->registerTaxonomies(); $this->registerGlobals(); + $this->registerStructures(); } protected function registerEntries() @@ -77,8 +81,6 @@ public function registerTaxonomies() $this->app->bind('statamic.eloquent.taxonomies.model', function () { return config('statamic-eloquent-driver.taxonomies.model'); }); - - } private function registerGlobals() @@ -93,4 +95,18 @@ private function registerGlobals() return config('statamic-eloquent-driver.variables.model'); }); } + + private function registerStructures() + { + Statamic::repository(NavigationRepositoryContract::class, NavigationRepository::class); + Statamic::repository(NavTreeRepositoryContract::class, NavTreeRepository::class); + + $this->app->bind('statamic.eloquent.navigations.model', function () { + return config('statamic-eloquent-driver.navigations.model'); + }); + + $this->app->bind('statamic.eloquent.nav-trees.model', function () { + return config('statamic-eloquent-driver.nav-trees.model'); + }); + } } diff --git a/src/Structures/Nav.php b/src/Structures/Nav.php new file mode 100644 index 00000000..811ca6b9 --- /dev/null +++ b/src/Structures/Nav.php @@ -0,0 +1,56 @@ +handle($model->handle) + ->title($model->title) + ->collections($model->collections) + ->maxDepth($model->maxDepth) + ->expectsRoot($model->expectsRoot) + ->initialPath($model->initialPath) + ->model($model); + } + + public function newTreeInstance() + { + return new NavTree; + } + + public function toModel() + { + $class = app('statamic.eloquent.navigations.model'); + + return $class::findOrNew($this->model?->id)->fill([ + 'handle' => $this->handle(), + 'title' => $this->title(), + 'collections' => $this->collections()->map->handle(), + 'maxDepth' => $this->maxDepth(), + 'expectsRoot' => $this->expectsRoot(), + 'initialPath' => $this->initialPath(), + ]); + } + + public function model($model = null) + { + if (func_num_args() === 0) { + return $this->model; + } + + $this->model = $model; + + $this->id($model->id); + + return $this; + } +} diff --git a/src/Structures/NavModel.php b/src/Structures/NavModel.php new file mode 100644 index 00000000..e0a8b8cc --- /dev/null +++ b/src/Structures/NavModel.php @@ -0,0 +1,20 @@ + 'json', + 'expectsRoot' => 'boolean', + 'maxDepth' => 'integer', + ]; +} diff --git a/src/Structures/NavTree.php b/src/Structures/NavTree.php new file mode 100644 index 00000000..bb23f81a --- /dev/null +++ b/src/Structures/NavTree.php @@ -0,0 +1,46 @@ +tree($model->tree) + ->handle($model->handle) + ->locale($model->locale) + ->initialPath($model->initialPath) + ->model($model); + } + + public function toModel() + { + $class = app('statamic.eloquent.nav-trees.model'); + + return $class::findOrNew($this->model?->id)->fill([ + 'handle' => $this->handle(), + 'initialPath' => $this->initialPath(), + 'locale' => $this->locale(), + 'tree' => $this->tree, + ]); + } + + public function model($model = null) + { + if (func_num_args() === 0) { + return $this->model; + } + + $this->model = $model; + + return $this; + } + +} diff --git a/src/Structures/NavTreeModel.php b/src/Structures/NavTreeModel.php new file mode 100644 index 00000000..49b48791 --- /dev/null +++ b/src/Structures/NavTreeModel.php @@ -0,0 +1,18 @@ + 'json', + ]; +} diff --git a/src/Structures/NavTreeRepository.php b/src/Structures/NavTreeRepository.php new file mode 100644 index 00000000..e40cab31 --- /dev/null +++ b/src/Structures/NavTreeRepository.php @@ -0,0 +1,39 @@ +first(); + return $model + ? app(TreeContract::class)->fromModel($model) + : null; + } + + public function save($entry) + { + $model = $entry->toModel(); + + $model->save(); + + $entry->model($model->fresh()); + } + + public function delete($entry) + { + $entry->model()->delete(); + } + + public static function bindings() + { + return [ + TreeContract::class => NavTree::class, + ]; + } +} diff --git a/src/Structures/NavigationRepository.php b/src/Structures/NavigationRepository.php new file mode 100644 index 00000000..62085c5f --- /dev/null +++ b/src/Structures/NavigationRepository.php @@ -0,0 +1,55 @@ +map(function ($model) { + return Nav::fromModel($model); + }); + } + + public static function bindings(): array + { + return [ + NavContract::class => Nav::class, + ]; + } + + public function all(): Collection + { + return $this->transform(NavModel::all()); + } + + public function findByHandle($handle): ?NavContract + { + $model = NavModel::whereHandle($handle)->first(); + return $model + ? app(NavContract::class)->fromModel($model) + : null; + } + + public function save($entry) + { + $model = $entry->toModel(); + + $model->save(); + + $entry->model($model->fresh()); + } + + public function delete($entry) + { + $entry->model()->delete(); + } +} From 68bafd2a85df5dd9a314e4ee054dbd95225b2cdb Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Thu, 27 May 2021 15:29:23 +0200 Subject: [PATCH 10/42] add db support for collections --- config/eloquent-driver.php | 4 ++ src/Entries/Collection.php | 73 ++++++++++++++++++++++++++++ src/Entries/CollectionModel.php | 25 ++++++++++ src/Entries/CollectionRepository.php | 53 ++++++++++++++++++++ src/ServiceProvider.php | 4 ++ src/Taxonomies/Term.php | 1 + 6 files changed, 160 insertions(+) create mode 100644 src/Entries/Collection.php create mode 100644 src/Entries/CollectionModel.php diff --git a/config/eloquent-driver.php b/config/eloquent-driver.php index 69a01a8d..558d0382 100644 --- a/config/eloquent-driver.php +++ b/config/eloquent-driver.php @@ -6,6 +6,10 @@ 'model' => \Statamic\Eloquent\Entries\EntryModel::class, ], + 'collections' => [ + 'model' => \Statamic\Eloquent\Entries\CollectionModel::class, + ], + 'taxonomies' => [ 'model' => \Statamic\Eloquent\Taxonomies\TaxonomyModel::class, ], diff --git a/src/Entries/Collection.php b/src/Entries/Collection.php new file mode 100644 index 00000000..5d801d98 --- /dev/null +++ b/src/Entries/Collection.php @@ -0,0 +1,73 @@ +structure($model->structure) + ->sortDirection($model->sort_dir) + ->sortField($model->sort_field) + ->layout($model->layout) + ->template($model->template) + ->sites($model->sites) + ->futureDateBehavior($model->future_date_behavior) + ->pastDateBehavior($model->past_date_behavior) + ->ampable($model->ampable) + ->dated($model->dated) + ->title($model->title) + ->handle($model->handle) + ->routes($model->routes) + ->taxonomies($model->taxonomies) + ->mount($model->mount) + ->model($model); + } + + public function toModel() + { + $class = app('statamic.eloquent.collections.model'); + + return $class::findOrNew($this->model?->id)->fill([ + 'title' => $this->title, + 'handle' => $this->handle, + 'routes' => $this->routes, + 'dated' => $this->dated, + 'past_date_behavior' => $this->pastDateBehavior(), + 'future_date_behavior' => $this->futureDateBehavior(), + 'default_publish_state' => $this->defaultPublishState, + 'ampable' => $this->ampable, + 'sites' => $this->sites, + 'template' => $this->template, + 'layout' => $this->layout, + 'sort_dir' => $this->sortDirection(), + 'sort_field' => $this->sortField(), + 'mount' => $this->mount, + 'taxonomies' => $this->taxonomies, + 'revisions' => $this->revisions, + 'inject' => $this->cascade, + 'structure' => $this->hasStructure() ? $this->structureContents() : null, + ]); + } + + public function model($model = null) + { + if (func_num_args() === 0) { + return $this->model; + } + + $this->model = $model; + + $this->id($model->id); + + return $this; + } +} diff --git a/src/Entries/CollectionModel.php b/src/Entries/CollectionModel.php new file mode 100644 index 00000000..55143cdc --- /dev/null +++ b/src/Entries/CollectionModel.php @@ -0,0 +1,25 @@ + 'json', + 'inject' => 'json', + 'taxonomies' => 'json', + 'structure' => 'json', + 'revisions' => 'bool', + 'dated' => 'bool', + 'default_publish_state' => 'bool', + 'ampable' => 'bool', + ]; + +} diff --git a/src/Entries/CollectionRepository.php b/src/Entries/CollectionRepository.php index 3a4c3326..48777386 100644 --- a/src/Entries/CollectionRepository.php +++ b/src/Entries/CollectionRepository.php @@ -2,7 +2,9 @@ namespace Statamic\Eloquent\Entries; +use Statamic\Contracts\Entries\Collection as CollectionContract; use Statamic\Stache\Repositories\CollectionRepository as StacheRepository; +use Illuminate\Support\Collection as IlluminateCollection; class CollectionRepository extends StacheRepository { @@ -18,4 +20,55 @@ public function updateEntryUris($collection, $ids = null) EntryModel::where('id', $entry->id())->update(['uri' => $entry->uri()]); }); } + + public function all(): IlluminateCollection + { + return $this->transform(CollectionModel::all()); + } + + public function find($handle): ?CollectionContract + { + $model = CollectionModel::whereHandle($handle)->first(); + + return $model + ? app(CollectionContract::class)->fromModel($model) + : null; + } + + public function findByHandle($handle): ?CollectionContract + { + $model = CollectionModel::whereHandle($handle)->first(); + + return $model + ? app(CollectionContract::class)->fromModel($model) + : null; + } + + public function save($entry) + { + $model = $entry->toModel(); + + $model->save(); + + $entry->model($model->fresh()); + } + + public function delete($entry) + { + $entry->model()->delete(); + } + + protected function transform($items, $columns = []) + { + return IlluminateCollection::make($items)->map(function ($model) { + return Collection::fromModel($model); + }); + } + + public static function bindings(): array + { + return [ + CollectionContract::class => Collection::class, + ]; + } } diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index eaadbc65..419d694b 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -61,6 +61,10 @@ protected function registerEntries() $this->app->bind('statamic.eloquent.entries.model', function () { return config('statamic-eloquent-driver.entries.model'); }); + + $this->app->bind('statamic.eloquent.collections.model', function () { + return config('statamic-eloquent-driver.collections.model'); + }); } public function registerTaxonomies() diff --git a/src/Taxonomies/Term.php b/src/Taxonomies/Term.php index a68e9631..d6458080 100644 --- a/src/Taxonomies/Term.php +++ b/src/Taxonomies/Term.php @@ -32,6 +32,7 @@ public function toModel() if ($this->blueprint && $this->taxonomy()->termBlueprints()->count() > 1) { $data['blueprint'] = $this->blueprint; } + return $class::findOrNew($this->model?->id)->fill([ 'site' => $this->locale(), 'slug' => $this->slug(), From ece0fccf29a8dbfc6851b5b07fff331d38d98dad Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Thu, 27 May 2021 15:40:40 +0200 Subject: [PATCH 11/42] multisite notice --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d87975e..b4888f6f 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,14 @@ This package provides support for storing your Statamic data in a database rather than the filesystem. +**Multisite is not tested yet!** + Todo: - [x] taxonomies - [x] navigations - [x] globals - [ ] form submissions -- [ ] collections +- [x] collections ## Installation From 7b57aab4cda70de3722eb6c7c9a632b93ef6eba5 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Fri, 28 May 2021 13:29:24 +0200 Subject: [PATCH 12/42] cleanup --- README.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/README.md b/README.md index b4888f6f..b07f3591 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,6 @@ This package provides support for storing your Statamic data in a database rather than the filesystem. -**Multisite is not tested yet!** - -Todo: -- [x] taxonomies -- [x] navigations -- [x] globals -- [ ] form submissions -- [x] collections - ## Installation Install using Composer: From 300c05f5e0adbe2c0f9838b43c45b9703c0b7985 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Fri, 28 May 2021 13:49:15 +0200 Subject: [PATCH 13/42] add collections migration --- README.md | 2 +- ..._05_28_114212_create_collections_table.php | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 database/migrations/2021_05_28_114212_create_collections_table.php diff --git a/README.md b/README.md index b07f3591..86a7e5ff 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ If you're starting from scratch, we can use traditional incrementing integers fo - Delete `content/collections/pages/home.md` - Change the structure `tree` in `content/collections/pages.yaml` to `{}`. -- Copy the `create_entries_table` migration into `database/migrations`. +- Copy all migrations into `database/migrations`. - Run `php artisan migrate`. ### Starting from an existing site (using UUIDs) diff --git a/database/migrations/2021_05_28_114212_create_collections_table.php b/database/migrations/2021_05_28_114212_create_collections_table.php new file mode 100644 index 00000000..c76be5b6 --- /dev/null +++ b/database/migrations/2021_05_28_114212_create_collections_table.php @@ -0,0 +1,49 @@ +id(); + $table->string('handle'); + $table->string('title'); + $table->json('routes')->nullable(); + $table->boolean('dated')->default(false); + $table->string('past_date_behavior')->nullable(); + $table->string('future_date_behavior')->nullable(); + $table->boolean('default_publish_state')->default(true); + $table->boolean('ampable')->default(false); + $table->string('sites')->nullable(); + $table->string('template')->nullable(); + $table->string('layout')->nullable(); + $table->string('sort_dir')->nullable(); + $table->string('sort_field')->nullable(); + $table->string('mount')->nullable(); + $table->json('taxonomies')->nullable(); + $table->boolean('revisions')->default(false); + $table->json('inject')->nullable(); + $table->json('structure')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('collections'); + } +} From 26656013aa75494292b0534ab98a912ed080adfe Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Fri, 28 May 2021 14:46:26 +0200 Subject: [PATCH 14/42] fix collection structure field and cleanup --- src/Entries/Collection.php | 4 +--- src/Taxonomies/TermQueryBuilder.php | 8 -------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/Entries/Collection.php b/src/Entries/Collection.php index 5d801d98..467642c9 100644 --- a/src/Entries/Collection.php +++ b/src/Entries/Collection.php @@ -1,12 +1,10 @@ structure($model->structure) + ->structureContents($model->structure) ->sortDirection($model->sort_dir) ->sortField($model->sort_field) ->layout($model->layout) diff --git a/src/Taxonomies/TermQueryBuilder.php b/src/Taxonomies/TermQueryBuilder.php index ef7978e2..6dc4189a 100644 --- a/src/Taxonomies/TermQueryBuilder.php +++ b/src/Taxonomies/TermQueryBuilder.php @@ -1,14 +1,10 @@ columns)) { $column = 'data->'.$column; } From 743e376ab8ea9dbf839ba5559ac98b868d205542 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Mon, 31 May 2021 19:15:25 +0200 Subject: [PATCH 15/42] ingore .php_cs.cache --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e96516be..2d046d18 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ composer.lock vendor .phpunit.result.cache +.php_cs.cache From b6d5085c6ad8c75e58ca5b961756e407523d7eef Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Mon, 31 May 2021 19:15:47 +0200 Subject: [PATCH 16/42] fix code style --- src/Entries/CollectionModel.php | 2 -- src/Entries/CollectionRepository.php | 2 +- src/Globals/GlobalRepository.php | 9 +-------- src/Globals/GlobalSet.php | 7 ++----- src/Globals/GlobalSetModel.php | 4 +--- src/Globals/Variables.php | 4 +--- src/Globals/VariablesModel.php | 2 -- src/ServiceProvider.php | 4 ++-- src/Structures/Nav.php | 5 ++--- src/Structures/NavModel.php | 2 -- src/Structures/NavTree.php | 4 +--- src/Structures/NavTreeModel.php | 2 -- src/Structures/NavTreeRepository.php | 2 +- src/Structures/NavigationRepository.php | 5 +---- src/Taxonomies/TaxonomyRepository.php | 4 ++-- src/Taxonomies/Term.php | 1 - src/Taxonomies/TermRepository.php | 1 - 17 files changed, 15 insertions(+), 45 deletions(-) diff --git a/src/Entries/CollectionModel.php b/src/Entries/CollectionModel.php index 55143cdc..92efdd40 100644 --- a/src/Entries/CollectionModel.php +++ b/src/Entries/CollectionModel.php @@ -3,7 +3,6 @@ namespace Statamic\Eloquent\Entries; use Illuminate\Database\Eloquent\Model as Eloquent; -use Illuminate\Support\Arr; class CollectionModel extends Eloquent { @@ -21,5 +20,4 @@ class CollectionModel extends Eloquent 'default_publish_state' => 'bool', 'ampable' => 'bool', ]; - } diff --git a/src/Entries/CollectionRepository.php b/src/Entries/CollectionRepository.php index 48777386..75be68bf 100644 --- a/src/Entries/CollectionRepository.php +++ b/src/Entries/CollectionRepository.php @@ -2,9 +2,9 @@ namespace Statamic\Eloquent\Entries; +use Illuminate\Support\Collection as IlluminateCollection; use Statamic\Contracts\Entries\Collection as CollectionContract; use Statamic\Stache\Repositories\CollectionRepository as StacheRepository; -use Illuminate\Support\Collection as IlluminateCollection; class CollectionRepository extends StacheRepository { diff --git a/src/Globals/GlobalRepository.php b/src/Globals/GlobalRepository.php index b6597e59..7a72d26a 100644 --- a/src/Globals/GlobalRepository.php +++ b/src/Globals/GlobalRepository.php @@ -1,15 +1,10 @@ fromModel(GlobalSetModel::whereHandle($handle)->firstOrFail()); @@ -36,7 +30,6 @@ public function all(): GlobalCollection return $this->transform(GlobalSetModel::all()); } - public function save($entry) { $model = $entry->toModel(); diff --git a/src/Globals/GlobalSet.php b/src/Globals/GlobalSet.php index c650b68a..a3d28718 100644 --- a/src/Globals/GlobalSet.php +++ b/src/Globals/GlobalSet.php @@ -1,10 +1,7 @@ title($model->title) ->model($model); - foreach($model->localizations as $localization) { + foreach ($model->localizations as $localization) { $global->addLocalization(Variables::fromModel(VariablesModel::make($localization))); } @@ -30,7 +27,7 @@ public function toModel() { $class = app('statamic.eloquent.global-sets.model'); - $localizations = $this->localizations()->map(function($value, $key) { + $localizations = $this->localizations()->map(function ($value, $key) { return $value->toModel()->toArray(); }); diff --git a/src/Globals/GlobalSetModel.php b/src/Globals/GlobalSetModel.php index 6896fd58..44d2db6c 100644 --- a/src/Globals/GlobalSetModel.php +++ b/src/Globals/GlobalSetModel.php @@ -1,9 +1,7 @@ 'json' + 'localizations' => 'json', ]; public function getAttribute($key) diff --git a/src/Globals/Variables.php b/src/Globals/Variables.php index 5228d1b3..628d2947 100644 --- a/src/Globals/Variables.php +++ b/src/Globals/Variables.php @@ -1,6 +1,5 @@ $this->locale, - 'data' => $data , + 'data' => $data, ]); } - } diff --git a/src/Globals/VariablesModel.php b/src/Globals/VariablesModel.php index 178df0d6..fbfca951 100644 --- a/src/Globals/VariablesModel.php +++ b/src/Globals/VariablesModel.php @@ -1,9 +1,7 @@ handle($model->handle) ->title($model->title) ->collections($model->collections) diff --git a/src/Structures/NavModel.php b/src/Structures/NavModel.php index e0a8b8cc..be34352c 100644 --- a/src/Structures/NavModel.php +++ b/src/Structures/NavModel.php @@ -1,9 +1,7 @@ first(); + return $model ? app(TreeContract::class)->fromModel($model) : null; diff --git a/src/Structures/NavigationRepository.php b/src/Structures/NavigationRepository.php index 62085c5f..fd5fd02c 100644 --- a/src/Structures/NavigationRepository.php +++ b/src/Structures/NavigationRepository.php @@ -1,13 +1,9 @@ first(); + return $model ? app(NavContract::class)->fromModel($model) : null; diff --git a/src/Taxonomies/TaxonomyRepository.php b/src/Taxonomies/TaxonomyRepository.php index 17cfe4d7..57497501 100644 --- a/src/Taxonomies/TaxonomyRepository.php +++ b/src/Taxonomies/TaxonomyRepository.php @@ -2,10 +2,9 @@ namespace Statamic\Eloquent\Taxonomies; -use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Collection; use Statamic\Contracts\Taxonomies\Taxonomy as TaxonomyContract; -use \Statamic\Stache\Repositories\TaxonomyRepository as StacheRepository; +use Statamic\Stache\Repositories\TaxonomyRepository as StacheRepository; class TaxonomyRepository extends StacheRepository { @@ -31,6 +30,7 @@ public function all(): Collection public function findByHandle($handle): ?TaxonomyContract { $taxonomyModel = TaxonomyModel::whereHandle($handle)->first(); + return $taxonomyModel ? app(TaxonomyContract::class)->fromModel($taxonomyModel) : null; diff --git a/src/Taxonomies/Term.php b/src/Taxonomies/Term.php index d6458080..af69063b 100644 --- a/src/Taxonomies/Term.php +++ b/src/Taxonomies/Term.php @@ -19,7 +19,6 @@ public static function fromModel(Model $model) $term = $term->model($model); $term = $term->blueprint($model->data['blueprint'] ?? null); - return $term; } diff --git a/src/Taxonomies/TermRepository.php b/src/Taxonomies/TermRepository.php index 5289fa8d..db5f3185 100644 --- a/src/Taxonomies/TermRepository.php +++ b/src/Taxonomies/TermRepository.php @@ -2,7 +2,6 @@ namespace Statamic\Eloquent\Taxonomies; -use Illuminate\Database\Eloquent\Builder; use Statamic\Contracts\Taxonomies\Term as TermContract; use Statamic\Stache\Repositories\TermRepository as StacheRepository; From 8344245f088c684af4175fa717effab7ae90b3a4 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Mon, 31 May 2021 22:45:41 +0200 Subject: [PATCH 17/42] make tree model semi polymorph and move files to appropriate folder --- config/eloquent-driver.php | 2 ++ ...1_05_27_082335_create_navigation_trees_table.php | 5 +++-- src/{Entries => Collections}/Collection.php | 13 +++++++++++-- src/{Entries => Collections}/CollectionModel.php | 2 +- .../CollectionRepository.php | 3 ++- src/Structures/NavTree.php | 5 +++-- src/Structures/NavTreeRepository.php | 4 +++- src/Structures/{NavTreeModel.php => TreeModel.php} | 4 ++-- 8 files changed, 27 insertions(+), 11 deletions(-) rename src/{Entries => Collections}/Collection.php (82%) rename src/{Entries => Collections}/CollectionModel.php (91%) rename src/{Entries => Collections}/CollectionRepository.php (95%) rename src/Structures/{NavTreeModel.php => TreeModel.php} (71%) diff --git a/config/eloquent-driver.php b/config/eloquent-driver.php index 558d0382..3df790da 100644 --- a/config/eloquent-driver.php +++ b/config/eloquent-driver.php @@ -8,6 +8,8 @@ 'collections' => [ 'model' => \Statamic\Eloquent\Entries\CollectionModel::class, + 'trees' => [ + 'model' => \Statamic\Eloquent\Structures\TreeModel::class, ], 'taxonomies' => [ diff --git a/database/migrations/2021_05_27_082335_create_navigation_trees_table.php b/database/migrations/2021_05_27_082335_create_navigation_trees_table.php index e904826a..961bb046 100644 --- a/database/migrations/2021_05_27_082335_create_navigation_trees_table.php +++ b/database/migrations/2021_05_27_082335_create_navigation_trees_table.php @@ -13,9 +13,10 @@ class CreateNavigationTreesTable extends Migration */ public function up() { - Schema::create('navigation_trees', function (Blueprint $table) { + Schema::create('trees', function (Blueprint $table) { $table->id(); $table->string('handle'); + $table->string('type'); $table->string('initialPath')->nullable(); $table->string('locale')->nullable(); $table->json('tree')->nullable(); @@ -30,6 +31,6 @@ public function up() */ public function down() { - Schema::dropIfExists('navigation_trees'); + Schema::dropIfExists('trees'); } } diff --git a/src/Entries/Collection.php b/src/Collections/Collection.php similarity index 82% rename from src/Entries/Collection.php rename to src/Collections/Collection.php index 467642c9..331fdebc 100644 --- a/src/Entries/Collection.php +++ b/src/Collections/Collection.php @@ -1,8 +1,9 @@ handle($this->handle()) + ->expectsRoot($this->structureContents['root'] ?? false) + ->maxDepth($this->structureContents['max_depth'] ?? null); + } } diff --git a/src/Entries/CollectionModel.php b/src/Collections/CollectionModel.php similarity index 91% rename from src/Entries/CollectionModel.php rename to src/Collections/CollectionModel.php index 92efdd40..9efb72a9 100644 --- a/src/Entries/CollectionModel.php +++ b/src/Collections/CollectionModel.php @@ -1,6 +1,6 @@ model?->id)->fill([ 'handle' => $this->handle(), 'initialPath' => $this->initialPath(), 'locale' => $this->locale(), 'tree' => $this->tree, + 'type' => 'navigation', ]); } diff --git a/src/Structures/NavTreeRepository.php b/src/Structures/NavTreeRepository.php index 81a2cfe2..0c99ed6a 100644 --- a/src/Structures/NavTreeRepository.php +++ b/src/Structures/NavTreeRepository.php @@ -9,7 +9,9 @@ class NavTreeRepository extends StacheRepository { public function find(string $handle, string $site): ?TreeContract { - $model = NavTreeModel::whereHandle($handle)->first(); + $model = TreeModel::whereHandle($handle) + ->whereType('navigation') + ->first(); return $model ? app(TreeContract::class)->fromModel($model) diff --git a/src/Structures/NavTreeModel.php b/src/Structures/TreeModel.php similarity index 71% rename from src/Structures/NavTreeModel.php rename to src/Structures/TreeModel.php index 22eac469..9afc4f81 100644 --- a/src/Structures/NavTreeModel.php +++ b/src/Structures/TreeModel.php @@ -4,11 +4,11 @@ use Illuminate\Database\Eloquent\Model as Eloquent; -class NavTreeModel extends Eloquent +class TreeModel extends Eloquent { protected $guarded = []; - protected $table = 'navigation_trees'; + protected $table = 'trees'; protected $casts = [ 'tree' => 'json', From 00db4497467168c25a54985fac033a5d846f14bd Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Mon, 31 May 2021 23:04:33 +0200 Subject: [PATCH 18/42] add support for collection tree --- config/eloquent-driver.php | 4 +- src/ServiceProvider.php | 20 +++++++-- src/Structures/CollectionStructure.php | 13 ++++++ src/Structures/CollectionTree.php | 47 +++++++++++++++++++++ src/Structures/CollectionTreeRepository.php | 29 +++++++++++++ 5 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 src/Structures/CollectionStructure.php create mode 100644 src/Structures/CollectionTree.php create mode 100644 src/Structures/CollectionTreeRepository.php diff --git a/config/eloquent-driver.php b/config/eloquent-driver.php index 3df790da..5fcd892c 100644 --- a/config/eloquent-driver.php +++ b/config/eloquent-driver.php @@ -7,7 +7,9 @@ ], 'collections' => [ - 'model' => \Statamic\Eloquent\Entries\CollectionModel::class, + 'model' => \Statamic\Eloquent\Collections\CollectionModel::class, + ], + 'trees' => [ 'model' => \Statamic\Eloquent\Structures\TreeModel::class, ], diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 2176fdcd..8498be29 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -5,15 +5,17 @@ use Statamic\Contracts\Entries\CollectionRepository as CollectionRepositoryContract; use Statamic\Contracts\Entries\EntryRepository as EntryRepositoryContract; use Statamic\Contracts\Globals\GlobalRepository as GlobalRepositoryContract; +use Statamic\Contracts\Structures\CollectionTreeRepository as CollectionTreeRepositoryContract; use Statamic\Contracts\Structures\NavigationRepository as NavigationRepositoryContract; use Statamic\Contracts\Structures\NavTreeRepository as NavTreeRepositoryContract; use Statamic\Contracts\Taxonomies\TaxonomyRepository as TaxonomyRepositoryContract; use Statamic\Contracts\Taxonomies\TermRepository as TermRepositoryContract; +use Statamic\Eloquent\Collections\CollectionRepository; use Statamic\Eloquent\Commands\ImportEntries; -use Statamic\Eloquent\Entries\CollectionRepository; use Statamic\Eloquent\Entries\EntryQueryBuilder; use Statamic\Eloquent\Entries\EntryRepository; use Statamic\Eloquent\Globals\GlobalRepository; +use Statamic\Eloquent\Structures\CollectionTreeRepository; use Statamic\Eloquent\Structures\NavigationRepository; use Statamic\Eloquent\Structures\NavTreeRepository; use Statamic\Eloquent\Taxonomies\TaxonomyRepository; @@ -42,6 +44,7 @@ public function boot() public function register() { $this->registerEntries(); + $this->registerCollections(); $this->registerTaxonomies(); $this->registerGlobals(); $this->registerStructures(); @@ -50,7 +53,6 @@ public function register() protected function registerEntries() { Statamic::repository(EntryRepositoryContract::class, EntryRepository::class); - Statamic::repository(CollectionRepositoryContract::class, CollectionRepository::class); $this->app->bind(EntryQueryBuilder::class, function ($app) { return new EntryQueryBuilder( @@ -61,10 +63,20 @@ protected function registerEntries() $this->app->bind('statamic.eloquent.entries.model', function () { return config('statamic-eloquent-driver.entries.model'); }); + } + + protected function registerCollections() + { + Statamic::repository(CollectionRepositoryContract::class, CollectionRepository::class); + Statamic::repository(CollectionTreeRepositoryContract::class, CollectionTreeRepository::class); $this->app->bind('statamic.eloquent.collections.model', function () { return config('statamic-eloquent-driver.collections.model'); }); + + $this->app->bind('statamic.eloquent.trees.model', function () { + return config('statamic-eloquent-driver.trees.model'); + }); } public function registerTaxonomies() @@ -109,8 +121,8 @@ private function registerStructures() return config('statamic-eloquent-driver.navigations.model'); }); - $this->app->bind('statamic.eloquent.nav-trees.model', function () { - return config('statamic-eloquent-driver.nav-trees.model'); + $this->app->bind('statamic.eloquent.trees.model', function () { + return config('statamic-eloquent-driver.trees.model'); }); } } diff --git a/src/Structures/CollectionStructure.php b/src/Structures/CollectionStructure.php new file mode 100644 index 00000000..53a82ee9 --- /dev/null +++ b/src/Structures/CollectionStructure.php @@ -0,0 +1,13 @@ +tree($model->tree) + ->handle($model->handle) + ->locale($model->locale) + ->initialPath($model->initialPath) + ->syncOriginal() + ->model($model); + } + + public function toModel() + { + $class = app('statamic.eloquent.trees.model'); + + return $class::findOrNew($this->model?->id)->fill([ + 'handle' => $this->handle(), + 'initialPath' => $this->initialPath(), + 'locale' => $this->locale(), + 'tree' => $this->tree, + 'type' => 'collection', + ]); + } + + public function model($model = null) + { + if (func_num_args() === 0) { + return $this->model; + } + + $this->model = $model; + + return $this; + } +} diff --git a/src/Structures/CollectionTreeRepository.php b/src/Structures/CollectionTreeRepository.php new file mode 100644 index 00000000..187b6001 --- /dev/null +++ b/src/Structures/CollectionTreeRepository.php @@ -0,0 +1,29 @@ +whereType('collection') + ->first(); + + return $model + ? app(CollectionTree::class)->fromModel($model) + : null; + } + + public function save($entry) + { + $model = $entry->toModel(); + + $model->save(); + + $entry->model($model->fresh()); + } +} From f02b53a4187152fd5101f567f695184e96b294b0 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Mon, 31 May 2021 23:36:51 +0200 Subject: [PATCH 19/42] Fix NavTree Model --- src/Structures/NavTree.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Structures/NavTree.php b/src/Structures/NavTree.php index daad72cf..48d22dc5 100644 --- a/src/Structures/NavTree.php +++ b/src/Structures/NavTree.php @@ -2,7 +2,7 @@ namespace Statamic\Eloquent\Structures; -use Statamic\Eloquent\Structures\NavTree as Model; +use Statamic\Eloquent\Structures\TreeModel as Model; use Statamic\Structures\NavTree as FileEntry; class NavTree extends FileEntry From 40186dc6faf281fb15eb3459f14dcb2f8c1f8d82 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Tue, 1 Jun 2021 15:53:45 +0200 Subject: [PATCH 20/42] Fix sites type on collections --- .../migrations/2021_05_28_114212_create_collections_table.php | 2 +- src/Collections/CollectionModel.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/database/migrations/2021_05_28_114212_create_collections_table.php b/database/migrations/2021_05_28_114212_create_collections_table.php index c76be5b6..85e25ff7 100644 --- a/database/migrations/2021_05_28_114212_create_collections_table.php +++ b/database/migrations/2021_05_28_114212_create_collections_table.php @@ -23,7 +23,7 @@ public function up() $table->string('future_date_behavior')->nullable(); $table->boolean('default_publish_state')->default(true); $table->boolean('ampable')->default(false); - $table->string('sites')->nullable(); + $table->json('sites')->nullable(); $table->string('template')->nullable(); $table->string('layout')->nullable(); $table->string('sort_dir')->nullable(); diff --git a/src/Collections/CollectionModel.php b/src/Collections/CollectionModel.php index 9efb72a9..c1f76b3b 100644 --- a/src/Collections/CollectionModel.php +++ b/src/Collections/CollectionModel.php @@ -15,6 +15,7 @@ class CollectionModel extends Eloquent 'inject' => 'json', 'taxonomies' => 'json', 'structure' => 'json', + 'sites' => 'json', 'revisions' => 'bool', 'dated' => 'bool', 'default_publish_state' => 'bool', From 7b5f6622dfb2ce0b5baf5306dbd232b0d7620f6e Mon Sep 17 00:00:00 2001 From: Benaja Hunzinger Date: Tue, 6 Jul 2021 08:55:39 +0200 Subject: [PATCH 21/42] multisite navigations --- src/Structures/NavTreeRepository.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Structures/NavTreeRepository.php b/src/Structures/NavTreeRepository.php index 0c99ed6a..c24d3d73 100644 --- a/src/Structures/NavTreeRepository.php +++ b/src/Structures/NavTreeRepository.php @@ -11,6 +11,7 @@ public function find(string $handle, string $site): ?TreeContract { $model = TreeModel::whereHandle($handle) ->whereType('navigation') + ->where('locale', $site) ->first(); return $model From 71851fb52b189c4a8f3acb8266c7b0b5488e6847 Mon Sep 17 00:00:00 2001 From: Benaja Hunzinger Date: Tue, 6 Jul 2021 20:22:48 +0200 Subject: [PATCH 22/42] add multisite functionality to taxonomies --- .../migrations/2021_05_18_160811_create_taxonomies_table.php | 1 + src/Taxonomies/Taxonomy.php | 2 ++ src/Taxonomies/TaxonomyModel.php | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/database/migrations/2021_05_18_160811_create_taxonomies_table.php b/database/migrations/2021_05_18_160811_create_taxonomies_table.php index 42a89579..5e4e371a 100644 --- a/database/migrations/2021_05_18_160811_create_taxonomies_table.php +++ b/database/migrations/2021_05_18_160811_create_taxonomies_table.php @@ -17,6 +17,7 @@ public function up() $table->increments('id'); $table->string('handle'); $table->string('title'); + $table->json('sites')->nullable(); $table->timestamps(); }); } diff --git a/src/Taxonomies/Taxonomy.php b/src/Taxonomies/Taxonomy.php index 739ac833..35561704 100644 --- a/src/Taxonomies/Taxonomy.php +++ b/src/Taxonomies/Taxonomy.php @@ -14,6 +14,7 @@ public static function fromModel(Model $model) return (new static) ->handle($model->handle) ->title($model->title) + ->sites($model->sites) ->model($model); } @@ -24,6 +25,7 @@ public function toModel() return $class::findOrNew($this->model?->id)->fill([ 'handle' => $this->handle(), 'title' => $this->title(), + 'sites' => $this->sites, ]); } diff --git a/src/Taxonomies/TaxonomyModel.php b/src/Taxonomies/TaxonomyModel.php index f3c4bc3b..a33ec055 100644 --- a/src/Taxonomies/TaxonomyModel.php +++ b/src/Taxonomies/TaxonomyModel.php @@ -12,7 +12,7 @@ class TaxonomyModel extends Eloquent protected $table = 'taxonomies'; protected $casts = [ - + 'sites' => 'json', ]; public function getAttribute($key) From 9402bc6739361e0306c3394f2ab5e6b23b8baf2f Mon Sep 17 00:00:00 2001 From: Benaja Hunzinger Date: Tue, 6 Jul 2021 22:26:53 +0200 Subject: [PATCH 23/42] localize taxonomies --- src/Taxonomies/Term.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Taxonomies/Term.php b/src/Taxonomies/Term.php index af69063b..0faa2f40 100644 --- a/src/Taxonomies/Term.php +++ b/src/Taxonomies/Term.php @@ -19,6 +19,10 @@ public static function fromModel(Model $model) $term = $term->model($model); $term = $term->blueprint($model->data['blueprint'] ?? null); + collect($model->data['localizations'] ?? [])->each(function ($data, $locale) use ($term) { + $term->dataForLocale($locale, $data); + }); + return $term; } @@ -32,6 +36,12 @@ public function toModel() $data['blueprint'] = $this->blueprint; } + $data['localizations'] = $this->localizations()->keys()->reduce(function ($localizations, $locale) { + $localizations[$locale] = $this->dataForLocale($locale)->toArray(); + + return $localizations; + }, []); + return $class::findOrNew($this->model?->id)->fill([ 'site' => $this->locale(), 'slug' => $this->slug(), From d9d92558365503adf4a2b72f6e6d27d609cb978c Mon Sep 17 00:00:00 2001 From: Benaja Hunzinger Date: Mon, 12 Jul 2021 09:23:35 +0200 Subject: [PATCH 24/42] ability to customize entry --- config/eloquent-driver.php | 1 + src/Entries/EntryQueryBuilder.php | 2 +- src/Entries/EntryRepository.php | 2 +- src/ServiceProvider.php | 12 ++++++++---- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/config/eloquent-driver.php b/config/eloquent-driver.php index 5fcd892c..2a447ea6 100644 --- a/config/eloquent-driver.php +++ b/config/eloquent-driver.php @@ -4,6 +4,7 @@ 'entries' => [ 'model' => \Statamic\Eloquent\Entries\EntryModel::class, + 'entry' => \Statamic\Eloquent\Entries\Entry::class, ], 'collections' => [ diff --git a/src/Entries/EntryQueryBuilder.php b/src/Entries/EntryQueryBuilder.php index 863a1c13..373d3adb 100644 --- a/src/Entries/EntryQueryBuilder.php +++ b/src/Entries/EntryQueryBuilder.php @@ -19,7 +19,7 @@ class EntryQueryBuilder extends EloquentQueryBuilder implements QueryBuilder protected function transform($items, $columns = []) { return EntryCollection::make($items)->map(function ($model) { - return Entry::fromModel($model); + return app('statamic.eloquent.entries.entry')::fromModel($model); }); } diff --git a/src/Entries/EntryRepository.php b/src/Entries/EntryRepository.php index 37c2533e..fd57ec55 100644 --- a/src/Entries/EntryRepository.php +++ b/src/Entries/EntryRepository.php @@ -11,7 +11,7 @@ class EntryRepository extends StacheRepository public static function bindings(): array { return [ - EntryContract::class => Entry::class, + EntryContract::class => app('statamic.eloquent.entries.entry'), QueryBuilder::class => EntryQueryBuilder::class, ]; } diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 8498be29..49ce188f 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -52,6 +52,14 @@ public function register() protected function registerEntries() { + $this->app->bind('statamic.eloquent.entries.entry', function () { + return config('statamic-eloquent-driver.entries.entry'); + }); + + $this->app->bind('statamic.eloquent.entries.model', function () { + return config('statamic-eloquent-driver.entries.model'); + }); + Statamic::repository(EntryRepositoryContract::class, EntryRepository::class); $this->app->bind(EntryQueryBuilder::class, function ($app) { @@ -59,10 +67,6 @@ protected function registerEntries() $app['statamic.eloquent.entries.model']::query() ); }); - - $this->app->bind('statamic.eloquent.entries.model', function () { - return config('statamic-eloquent-driver.entries.model'); - }); } protected function registerCollections() From dc29b47bf1f1b7d602d7209ee1af8512b4f01ba6 Mon Sep 17 00:00:00 2001 From: Benaja Hunzinger Date: Tue, 13 Jul 2021 13:35:07 +0200 Subject: [PATCH 25/42] get collection tree by site --- src/Structures/CollectionTreeRepository.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Structures/CollectionTreeRepository.php b/src/Structures/CollectionTreeRepository.php index 187b6001..05c71bf2 100644 --- a/src/Structures/CollectionTreeRepository.php +++ b/src/Structures/CollectionTreeRepository.php @@ -10,6 +10,7 @@ class CollectionTreeRepository extends StacheRepository public function find(string $handle, string $site): ?TreeContract { $model = TreeModel::whereHandle($handle) + ->where('locale', $site) ->whereType('collection') ->first(); From 58b5971094817f033e77faf733361d0592243795 Mon Sep 17 00:00:00 2001 From: Benaja Hunzinger Date: Tue, 27 Jul 2021 13:21:12 +0200 Subject: [PATCH 26/42] return localized field when fetching terms by site --- src/Taxonomies/TermQueryBuilder.php | 15 ++++++++++++++- src/Taxonomies/TermRepository.php | 3 ++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Taxonomies/TermQueryBuilder.php b/src/Taxonomies/TermQueryBuilder.php index 6dc4189a..6c61ffdf 100644 --- a/src/Taxonomies/TermQueryBuilder.php +++ b/src/Taxonomies/TermQueryBuilder.php @@ -7,6 +7,8 @@ class TermQueryBuilder extends EloquentQueryBuilder { + protected $site = null; + protected $columns = [ 'id', 'site', 'slug', 'uri', 'taxonomy', 'created_at', 'updated_at', ]; @@ -14,7 +16,7 @@ class TermQueryBuilder extends EloquentQueryBuilder protected function transform($items, $columns = []) { return TermCollection::make($items)->map(function ($model) { - return Term::fromModel($model); + return Term::fromModel($model)->in($this->site); }); } @@ -26,4 +28,15 @@ protected function column($column) return $column; } + + public function where($column, $operator = null, $value = null) + { + if ($column === 'site') { + $this->site = $operator; + + return $this; + } + + return parent::where($column, $operator, $value); + } } diff --git a/src/Taxonomies/TermRepository.php b/src/Taxonomies/TermRepository.php index db5f3185..db5d2fed 100644 --- a/src/Taxonomies/TermRepository.php +++ b/src/Taxonomies/TermRepository.php @@ -4,6 +4,7 @@ use Statamic\Contracts\Taxonomies\Term as TermContract; use Statamic\Stache\Repositories\TermRepository as StacheRepository; +use Statamic\Taxonomies\LocalizedTerm; class TermRepository extends StacheRepository { @@ -14,7 +15,7 @@ public function query() return app(TermQueryBuilder::class); } - public function find($id): ?Term + public function find($id): LocalizedTerm { [$handle, $slug] = explode('::', $id); From 6be137cf0e1dc83c64e3989b482df658cb0803fb Mon Sep 17 00:00:00 2001 From: Benaja Hunzinger Date: Tue, 27 Jul 2021 14:03:43 +0200 Subject: [PATCH 27/42] optional return --- src/Taxonomies/TermRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Taxonomies/TermRepository.php b/src/Taxonomies/TermRepository.php index db5d2fed..7d2dfc32 100644 --- a/src/Taxonomies/TermRepository.php +++ b/src/Taxonomies/TermRepository.php @@ -15,7 +15,7 @@ public function query() return app(TermQueryBuilder::class); } - public function find($id): LocalizedTerm + public function find($id): ?LocalizedTerm { [$handle, $slug] = explode('::', $id); From 0ee57a199ca87699d374c6dbe66d110f19b1938d Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Tue, 27 Jul 2021 16:32:14 +0200 Subject: [PATCH 28/42] only use updated_at from database column and don't track more than once --- src/Entries/Entry.php | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Entries/Entry.php b/src/Entries/Entry.php index e616c580..035c5381 100644 --- a/src/Entries/Entry.php +++ b/src/Entries/Entry.php @@ -2,6 +2,7 @@ namespace Statamic\Eloquent\Entries; +use Illuminate\Support\Carbon; use Statamic\Eloquent\Entries\EntryModel as Model; use Statamic\Entries\Entry as FileEntry; @@ -58,6 +59,28 @@ public function model($model = null) return $this; } + /** + * This overwrite is needed to prevent Statamic to save updated_at also into the data. We track updated_at already in the database. + * + * @param null $user + * @return $this|Entry|FileEntry|\Statamic\Taxonomies\LocalizedTerm + */ + public function updateLastModified($user = null) + { + if (! config('statamic.system.track_last_update')) { + return $this; + } + + $user + ? $this->set('updated_by', $user->id()) + : $this->remove('updated_by'); + + // ensure 'updated_at' does not exists in the data of the entry. + $this->remove('updated_at'); + + return $this; + } + public function lastModified() { return $this->model->updated_at; @@ -76,7 +99,7 @@ public function origin($origin = null) } if (! $this->model->origin) { - return null; + return; } return self::fromModel($this->model->origin); From 528e1fc21e6670a009c53a0ad368deffdbdb1208 Mon Sep 17 00:00:00 2001 From: Oliver Kaufmann Date: Tue, 3 Aug 2021 02:29:40 +0200 Subject: [PATCH 29/42] save sites to taxonomy and add fallback for terms --- src/Taxonomies/Taxonomy.php | 2 +- src/Taxonomies/TermQueryBuilder.php | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Taxonomies/Taxonomy.php b/src/Taxonomies/Taxonomy.php index 35561704..50bc0a8d 100644 --- a/src/Taxonomies/Taxonomy.php +++ b/src/Taxonomies/Taxonomy.php @@ -25,7 +25,7 @@ public function toModel() return $class::findOrNew($this->model?->id)->fill([ 'handle' => $this->handle(), 'title' => $this->title(), - 'sites' => $this->sites, + 'sites' => $this->sites(), ]); } diff --git a/src/Taxonomies/TermQueryBuilder.php b/src/Taxonomies/TermQueryBuilder.php index 6c61ffdf..a7050d4e 100644 --- a/src/Taxonomies/TermQueryBuilder.php +++ b/src/Taxonomies/TermQueryBuilder.php @@ -2,6 +2,7 @@ namespace Statamic\Eloquent\Taxonomies; +use Statamic\Facades\Site; use Statamic\Query\EloquentQueryBuilder; use Statamic\Taxonomies\TermCollection; @@ -15,8 +16,13 @@ class TermQueryBuilder extends EloquentQueryBuilder protected function transform($items, $columns = []) { - return TermCollection::make($items)->map(function ($model) { - return Term::fromModel($model)->in($this->site); + $site = $this->site; + if(!$site) { + $site = Site::default()->handle(); + } + + return TermCollection::make($items)->map(function ($model) use($site) { + return Term::fromModel($model)->in($site); }); } From fc838a854c0a23c66574305fd4e06880b261df26 Mon Sep 17 00:00:00 2001 From: Julio Carlos Menendez Date: Mon, 20 Sep 2021 12:47:49 -0600 Subject: [PATCH 30/42] Allows customizing the collection entry class. --- config/eloquent-driver.php | 1 + src/Collections/CollectionRepository.php | 2 +- src/ServiceProvider.php | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/config/eloquent-driver.php b/config/eloquent-driver.php index 2a447ea6..ebe9913b 100644 --- a/config/eloquent-driver.php +++ b/config/eloquent-driver.php @@ -9,6 +9,7 @@ 'collections' => [ 'model' => \Statamic\Eloquent\Collections\CollectionModel::class, + 'entry' => \Statamic\Eloquent\Collections\Collection::class, ], 'trees' => [ diff --git a/src/Collections/CollectionRepository.php b/src/Collections/CollectionRepository.php index 463156bd..9b115ca2 100644 --- a/src/Collections/CollectionRepository.php +++ b/src/Collections/CollectionRepository.php @@ -69,7 +69,7 @@ protected function transform($items, $columns = []) public static function bindings(): array { return [ - CollectionContract::class => Collection::class, + CollectionContract::class => app('statamic.eloquent.collections.entry'), ]; } } diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 49ce188f..c3a09828 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -32,7 +32,7 @@ public function boot() { parent::boot(); - $this->mergeConfigFrom($config = __DIR__.'/../config/eloquent-driver.php', 'statamic-eloquent-driver'); + $this->mergeConfigFrom($config = __DIR__ . '/../config/eloquent-driver.php', 'statamic-eloquent-driver'); if ($this->app->runningInConsole()) { $this->publishes([$config => config_path('statamic-eloquent-driver.php')]); @@ -78,6 +78,10 @@ protected function registerCollections() return config('statamic-eloquent-driver.collections.model'); }); + $this->app->bind('statamic.eloquent.collections.entry', function () { + return config('statamic-eloquent-driver.collections.entry'); + }); + $this->app->bind('statamic.eloquent.trees.model', function () { return config('statamic-eloquent-driver.trees.model'); }); From a48b8805a11e002fac32cd2f3098f3b9c8200d95 Mon Sep 17 00:00:00 2001 From: Julio Carlos Menendez Date: Mon, 20 Sep 2021 12:57:01 -0600 Subject: [PATCH 31/42] Defines collection bindings before repositories. --- src/ServiceProvider.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index c3a09828..b6591c91 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -71,9 +71,6 @@ protected function registerEntries() protected function registerCollections() { - Statamic::repository(CollectionRepositoryContract::class, CollectionRepository::class); - Statamic::repository(CollectionTreeRepositoryContract::class, CollectionTreeRepository::class); - $this->app->bind('statamic.eloquent.collections.model', function () { return config('statamic-eloquent-driver.collections.model'); }); @@ -85,6 +82,9 @@ protected function registerCollections() $this->app->bind('statamic.eloquent.trees.model', function () { return config('statamic-eloquent-driver.trees.model'); }); + + Statamic::repository(CollectionRepositoryContract::class, CollectionRepository::class); + Statamic::repository(CollectionTreeRepositoryContract::class, CollectionTreeRepository::class); } public function registerTaxonomies() From 4540612fd42363ee6388410230f5b9a5f4e31e3d Mon Sep 17 00:00:00 2001 From: Julio Carlos Menendez Date: Sun, 26 Sep 2021 21:37:16 -0600 Subject: [PATCH 32/42] Adds blueprints to the database. --- ...1_09_26_213111_create_blueprints_table.php | 37 +++++ database/seeders/DefaultBlueprintSeeder.php | 72 ++++++++++ src/Blueprints/BlueprintModel.php | 24 ++++ src/Blueprints/BlueprintRepository.php | 129 ++++++++++++++++++ src/ServiceProvider.php | 14 ++ 5 files changed, 276 insertions(+) create mode 100644 database/migrations/2021_09_26_213111_create_blueprints_table.php create mode 100644 database/seeders/DefaultBlueprintSeeder.php create mode 100644 src/Blueprints/BlueprintModel.php create mode 100644 src/Blueprints/BlueprintRepository.php diff --git a/database/migrations/2021_09_26_213111_create_blueprints_table.php b/database/migrations/2021_09_26_213111_create_blueprints_table.php new file mode 100644 index 00000000..f2f481fb --- /dev/null +++ b/database/migrations/2021_09_26_213111_create_blueprints_table.php @@ -0,0 +1,37 @@ +id(); + $table->string('namespace')->nullable()->default(null); + $table->string('handle'); + $table->json('data'); + $table->timestamps(); + }); + + (new DefaultBlueprintSeeder())->run(); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('blueprints'); + } +} diff --git a/database/seeders/DefaultBlueprintSeeder.php b/database/seeders/DefaultBlueprintSeeder.php new file mode 100644 index 00000000..23a51147 --- /dev/null +++ b/database/seeders/DefaultBlueprintSeeder.php @@ -0,0 +1,72 @@ + [ + [ + 'field' => [ + 'type' => 'markdown', + 'display' => 'Content', + 'localizable' => true + ], + 'handle' => 'content' + ], + [ + 'field' => [ + 'type' => 'users', + 'display' => 'Author', + 'default' => 'current', + 'localizable' => true, + 'max_items' => 1 + ], + 'handle' => 'author' + ], + [ + 'field' => [ + 'type' => 'template', + 'display' => 'Template', + 'localizable' => true + ], + 'handle' => 'template' + ], + ] + ]; + + /** + * Run the database seeds. + * + * @return void + */ + public function run() + { + DB::table('blueprints')->updateOrInsert( + [ + 'id' => 1 + ], + [ + 'namespace' => null, + 'handle' => 'default', + 'data' => $this->configJson(), + 'created_at' => Carbon::now() + ] + ); + } + + public function configJson() + { + try { + $config = json_encode(self::DEFAULT_BLUEPRINT_CONFIG, JSON_THROW_ON_ERROR); + } catch (\JsonException $e) { + $config = '[]'; + } + + return $config; + } +} diff --git a/src/Blueprints/BlueprintModel.php b/src/Blueprints/BlueprintModel.php new file mode 100644 index 00000000..a518f4f4 --- /dev/null +++ b/src/Blueprints/BlueprintModel.php @@ -0,0 +1,24 @@ + 'json', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; + + public function getAttribute($key) + { + return Arr::get($this->getAttributeValue('data'), $key, parent::getAttribute($key)); + } +} diff --git a/src/Blueprints/BlueprintRepository.php b/src/Blueprints/BlueprintRepository.php new file mode 100644 index 00000000..88ff7a43 --- /dev/null +++ b/src/Blueprints/BlueprintRepository.php @@ -0,0 +1,129 @@ +once($blueprint, function () use ($blueprint) { + [$namespace, $handle] = $this->getNamespaceAndHandle($blueprint); + if (!$blueprint) { + return null; + } + + if (($blueprintModel = BlueprintModel::where('namespace', $namespace)->where('handle', $handle)->first()) === null) { + throw_if( + $namespace === null && $handle === 'default', + Exception::class, + 'Default Blueprint is required but not found. ' + ); + + return null; + } + + return $this->makeBlueprintFromModel($blueprintModel) ?? $this->findFallback($blueprint); + }); + } + + public function save(Blueprint $blueprint) + { + $this->clearBlinkCaches(); + + $this->updateModel($blueprint); + } + + public function delete(Blueprint $blueprint) + { + $this->clearBlinkCaches(); + + $this->deleteModel($blueprint); + } + + private function clearBlinkCaches() + { + Blink::store(self::BLINK_FOUND)->flush(); + Blink::store(self::BLINK_FROM_FILE)->flush(); + Blink::store(self::BLINK_NAMESPACE_PATHS)->flush(); + } + + public function in(string $namespace) + { + return $this + ->filesIn($namespace) + ->map(function ($file) { + return $this->makeBlueprintFromModel($file); + }) + ->sort(function ($a, $b) { + $orderA = $a->order() ?? 99999; + $orderB = $b->order() ?? 99999; + + return $orderA === $orderB + ? $a->title() <=> $b->title() + : $orderA <=> $orderB; + }) + ->keyBy->handle(); + } + + private function filesIn($namespace) + { + return Blink::store(self::BLINK_NAMESPACE_PATHS)->once($namespace, function () use ($namespace) { + $namespace = str_replace('/', '.', $namespace); + + if (count(($blueprintModels = BlueprintModel::where('namespace', $namespace)->get())) == 0) { + return collect(); + } + + return $blueprintModels; + }); + } + + private function makeBlueprintFromModel($model) + { + return Blink::store(self::BLINK_FROM_FILE)->once('database:blueprints:' . $model->id, function () use ($model) { + return (new Blueprint) + ->setHidden(Arr::get($model->data, 'hide')) + ->setOrder(Arr::get($model->data, 'order')) + ->setHandle($model->handle) + ->setNamespace($model->namespace) + ->setContents($model->data); + }); + } + + private function getNamespaceAndHandle($blueprint) + { + $blueprint = str_replace('/', '.', $blueprint); + $parts = explode('.', $blueprint); + $handle = array_pop($parts); + $namespace = implode('.', $parts); + $namespace = empty($namespace) ? null : $namespace; + + return [$namespace, $handle]; + } + + public function updateModel($blueprint) + { + $model = BlueprintModel::firstOrNew([ + 'handle' => $blueprint->handle(), + 'namespace' => $blueprint->namespace() ?? null, + ]); + $model->data = $blueprint->contents(); + $model->save(); + } + + public function deleteModel($blueprint) + { + $model = BlueprintModel::where('namespace', $blueprint->namespace() ?? null)->where('handle', $blueprint->handle())->first(); + $model->delete(); + } +} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index b6591c91..f5de4d16 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -37,12 +37,18 @@ public function boot() if ($this->app->runningInConsole()) { $this->publishes([$config => config_path('statamic-eloquent-driver.php')]); + $this->publishes([ + __DIR__ . '/database/seeders/DefaultBlueprintSeeder.php' => database_path('seeders/DefaultBlueprintSeeder.php'), + ], 'statamic-database-seeders'); + + $this->commands([ImportEntries::class]); } } public function register() { + $this->registerBlueprints(); $this->registerEntries(); $this->registerCollections(); $this->registerTaxonomies(); @@ -50,6 +56,14 @@ public function register() $this->registerStructures(); } + protected function registerBlueprints() + { + $this->app->singleton( + 'Statamic\Fields\BlueprintRepository', + 'Statamic\Eloquent\Blueprints\BlueprintRepository' + ); + } + protected function registerEntries() { $this->app->bind('statamic.eloquent.entries.entry', function () { From 7bc24a7e2399a7b6ea0f318d6e6abd726ec028eb Mon Sep 17 00:00:00 2001 From: Julio Carlos Menendez Date: Mon, 27 Sep 2021 06:21:00 -0600 Subject: [PATCH 33/42] Adds fieldsets to the database. --- ...21_09_26_214356_create_fieldsets_table.php | 33 +++++++++ src/Fieldsets/FieldsetModel.php | 24 ++++++ src/Fieldsets/FieldsetRepository.php | 73 +++++++++++++++++++ src/ServiceProvider.php | 9 +++ 4 files changed, 139 insertions(+) create mode 100644 database/migrations/2021_09_26_214356_create_fieldsets_table.php create mode 100644 src/Fieldsets/FieldsetModel.php create mode 100644 src/Fieldsets/FieldsetRepository.php diff --git a/database/migrations/2021_09_26_214356_create_fieldsets_table.php b/database/migrations/2021_09_26_214356_create_fieldsets_table.php new file mode 100644 index 00000000..2336ce19 --- /dev/null +++ b/database/migrations/2021_09_26_214356_create_fieldsets_table.php @@ -0,0 +1,33 @@ +id(); + $table->string('handle'); + $table->json('data'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('fieldsets'); + } +} diff --git a/src/Fieldsets/FieldsetModel.php b/src/Fieldsets/FieldsetModel.php new file mode 100644 index 00000000..aaa11b75 --- /dev/null +++ b/src/Fieldsets/FieldsetModel.php @@ -0,0 +1,24 @@ + 'json', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; + + public function getAttribute($key) + { + return Arr::get($this->getAttributeValue('data'), $key, parent::getAttribute($key)); + } +} diff --git a/src/Fieldsets/FieldsetRepository.php b/src/Fieldsets/FieldsetRepository.php new file mode 100644 index 00000000..2acf4d21 --- /dev/null +++ b/src/Fieldsets/FieldsetRepository.php @@ -0,0 +1,73 @@ +map(function ($model) { + return (new Fieldset) + ->setHandle($model->handle) + ->setContents($model->data); + }); + }); + } + + public function find($handle): ?Fieldset + { + if ($cached = array_get($this->fieldsets, $handle)) { + return $cached; + } + + $handle = str_replace('/', '.', $handle); + + if (($model = FieldsetModel::where('handle', $handle)->first()) === null) { + return null; + } + + $fieldset = (new Fieldset) + ->setHandle($handle) + ->setContents($model->data); + + $this->fieldsets[$handle] = $fieldset; + + return $fieldset; + } + + public function save(Fieldset $fieldset) + { + $this->updateModel($fieldset); + } + + public function delete(Fieldset $fieldset) + { + $this->deleteModel($fieldset); + } + + public function updateModel($fieldset) + { + $model = FieldsetModel::firstOrNew([ + 'handle' => $fieldset->handle(), + ]); + $model->data = $fieldset->contents(); + $model->save(); + } + + public function deleteModel($fieldset) + { + $model = FieldsetModel::where('handle', $fieldset->handle())->first(); + $model->delete(); + } +} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index f5de4d16..8404b579 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -49,6 +49,7 @@ public function boot() public function register() { $this->registerBlueprints(); + $this->registerFieldsets(); $this->registerEntries(); $this->registerCollections(); $this->registerTaxonomies(); @@ -64,6 +65,14 @@ protected function registerBlueprints() ); } + protected function registerFieldsets() + { + $this->app->singleton( + 'Statamic\Fields\FieldsetRepository', + 'Statamic\Eloquent\Fieldsets\FieldsetRepository' + ); + } + protected function registerEntries() { $this->app->bind('statamic.eloquent.entries.entry', function () { From 415e68da276e99c179cbaea19467e7af2bfb6d14 Mon Sep 17 00:00:00 2001 From: Julio Carlos Menendez Date: Mon, 27 Sep 2021 06:31:46 -0600 Subject: [PATCH 34/42] Loads migrations automatically. --- src/ServiceProvider.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 8404b579..0197ae59 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -41,6 +41,7 @@ public function boot() __DIR__ . '/database/seeders/DefaultBlueprintSeeder.php' => database_path('seeders/DefaultBlueprintSeeder.php'), ], 'statamic-database-seeders'); + $this->loadMigrationsFrom(__DIR__ . '/database/migrations'); $this->commands([ImportEntries::class]); } From 5414910b7cf9ca0f5563b137eda9ed6a90fcb1ea Mon Sep 17 00:00:00 2001 From: Julio Carlos Menendez Date: Mon, 27 Sep 2021 06:38:13 -0600 Subject: [PATCH 35/42] Fixes path to database directory. --- src/ServiceProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 0197ae59..efa865a6 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -38,10 +38,10 @@ public function boot() $this->publishes([$config => config_path('statamic-eloquent-driver.php')]); $this->publishes([ - __DIR__ . '/database/seeders/DefaultBlueprintSeeder.php' => database_path('seeders/DefaultBlueprintSeeder.php'), + __DIR__ . '/../database/seeders/DefaultBlueprintSeeder.php' => database_path('seeders/DefaultBlueprintSeeder.php'), ], 'statamic-database-seeders'); - $this->loadMigrationsFrom(__DIR__ . '/database/migrations'); + $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); $this->commands([ImportEntries::class]); } From 2a1327d2a97b18a54bee0910d21c30048c0d6c40 Mon Sep 17 00:00:00 2001 From: Julio Carlos Menendez Date: Mon, 27 Sep 2021 06:42:17 -0600 Subject: [PATCH 36/42] Removes auto loading migrations. Trying to auto load the migrations causes issues with the 2 migrations for entries --- src/ServiceProvider.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index efa865a6..677de9cc 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -41,8 +41,6 @@ public function boot() __DIR__ . '/../database/seeders/DefaultBlueprintSeeder.php' => database_path('seeders/DefaultBlueprintSeeder.php'), ], 'statamic-database-seeders'); - $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); - $this->commands([ImportEntries::class]); } } From 5bfc2468ea03fcc93b5e6307bba3a6939dd31d0f Mon Sep 17 00:00:00 2001 From: Julio Carlos Menendez Date: Mon, 27 Sep 2021 06:58:46 -0600 Subject: [PATCH 37/42] Sets correct namespace for the seeder. --- .../migrations/2021_09_26_213111_create_blueprints_table.php | 2 +- database/seeders/DefaultBlueprintSeeder.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/database/migrations/2021_09_26_213111_create_blueprints_table.php b/database/migrations/2021_09_26_213111_create_blueprints_table.php index f2f481fb..592fd2c1 100644 --- a/database/migrations/2021_09_26_213111_create_blueprints_table.php +++ b/database/migrations/2021_09_26_213111_create_blueprints_table.php @@ -3,7 +3,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -use Statamic\Eloquent\Database\Seeders\DefaultBlueprintSeeder; +use Database\Seeders\DefaultBlueprintSeeder; class CreateBlueprintsTable extends Migration { diff --git a/database/seeders/DefaultBlueprintSeeder.php b/database/seeders/DefaultBlueprintSeeder.php index 23a51147..a4b65cc9 100644 --- a/database/seeders/DefaultBlueprintSeeder.php +++ b/database/seeders/DefaultBlueprintSeeder.php @@ -1,6 +1,6 @@ Date: Mon, 27 Sep 2021 06:59:23 -0600 Subject: [PATCH 38/42] Stops running the seeder automatically. --- .../migrations/2021_09_26_213111_create_blueprints_table.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/database/migrations/2021_09_26_213111_create_blueprints_table.php b/database/migrations/2021_09_26_213111_create_blueprints_table.php index 592fd2c1..82258451 100644 --- a/database/migrations/2021_09_26_213111_create_blueprints_table.php +++ b/database/migrations/2021_09_26_213111_create_blueprints_table.php @@ -3,7 +3,6 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -use Database\Seeders\DefaultBlueprintSeeder; class CreateBlueprintsTable extends Migration { @@ -21,8 +20,6 @@ public function up() $table->json('data'); $table->timestamps(); }); - - (new DefaultBlueprintSeeder())->run(); } /** From 6cca9e8cfe2751ef87b773303c383427e3ff3aa7 Mon Sep 17 00:00:00 2001 From: Julio Carlos Menendez Date: Mon, 27 Sep 2021 07:12:16 -0600 Subject: [PATCH 39/42] Sets seeder to use handle instead of id for lookup. --- database/seeders/DefaultBlueprintSeeder.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/database/seeders/DefaultBlueprintSeeder.php b/database/seeders/DefaultBlueprintSeeder.php index a4b65cc9..6972904a 100644 --- a/database/seeders/DefaultBlueprintSeeder.php +++ b/database/seeders/DefaultBlueprintSeeder.php @@ -48,11 +48,10 @@ public function run() { DB::table('blueprints')->updateOrInsert( [ - 'id' => 1 + 'handle' => 'default' ], [ 'namespace' => null, - 'handle' => 'default', 'data' => $this->configJson(), 'created_at' => Carbon::now() ] From c83823e4ba066cb415aa6df7c1f28b1f1c851d05 Mon Sep 17 00:00:00 2001 From: Julio Carlos Menendez Date: Wed, 29 Sep 2021 15:57:14 -0600 Subject: [PATCH 40/42] Adds asset containers to the database. --- ...ate_assets_meta_assets_container_table.php | 41 ++++++++++ src/Assets/Asset.php | 77 +++++++++++++++++++ src/Assets/AssetContainer.php | 56 ++++++++++++++ src/Assets/AssetContainerModel.php | 18 +++++ src/Assets/AssetContainerRepository.php | 61 +++++++++++++++ src/Assets/AssetModel.php | 18 +++++ src/Assets/AssetRepository.php | 28 +++++++ src/ServiceProvider.php | 11 +++ 8 files changed, 310 insertions(+) create mode 100644 database/migrations/2021_09_29_155001_create_assets_meta_assets_container_table.php create mode 100644 src/Assets/Asset.php create mode 100644 src/Assets/AssetContainer.php create mode 100644 src/Assets/AssetContainerModel.php create mode 100644 src/Assets/AssetContainerRepository.php create mode 100644 src/Assets/AssetModel.php create mode 100644 src/Assets/AssetRepository.php diff --git a/database/migrations/2021_09_29_155001_create_assets_meta_assets_container_table.php b/database/migrations/2021_09_29_155001_create_assets_meta_assets_container_table.php new file mode 100644 index 00000000..c381e498 --- /dev/null +++ b/database/migrations/2021_09_29_155001_create_assets_meta_assets_container_table.php @@ -0,0 +1,41 @@ +id(); + $table->string('handle'); + $table->json('data'); + $table->timestamps(); + }); + + Schema::create('asset_containers', function (Blueprint $table) { + $table->id(); + $table->string('handle'); + $table->json('data'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('asset_meta'); + Schema::dropIfExists('asset_containers'); + } +} diff --git a/src/Assets/Asset.php b/src/Assets/Asset.php new file mode 100644 index 00000000..970bcb78 --- /dev/null +++ b/src/Assets/Asset.php @@ -0,0 +1,77 @@ +metaValue($key); + } + + if (!config('statamic.assets.cache_meta')) { + return $this->generateMeta(); + } + + if ($this->meta) { + return array_merge($this->meta, ['data' => $this->data->all()]); + } + + return $this->meta = Cache::rememberForever($this->metaCacheKey(), function () { + if ($model = AssetModel::where('handle', $this->container()->handle() . '::' . $this->metaPath())->first()) { + return $model->data; + } + + $this->writeMeta($meta = $this->generateMeta()); + + return $meta; + }); + } + + public function exists() + { + $files = Blink::once($this->container()->handle() . '::files', function () { + return $this->container()->files(); + }); + + if (!$path = $this->path()) { + return false; + } + + return $files->contains($path); + } + + private function metaValue($key) + { + $value = Arr::get($this->meta(), $key); + + if (!is_null($value)) { + return $value; + } + + Cache::forget($this->metaCacheKey()); + + $this->writeMeta($meta = $this->generateMeta()); + + return Arr::get($meta, $key); + } + + public function writeMeta($meta) + { + $meta['data'] = Arr::removeNullValues($meta['data']); + + $model = AssetModel::firstOrNew([ + 'handle' => $this->container()->handle() . '::' . $this->metaPath() + ]); + + $model->data = $meta; + + $model->save(); + } +} diff --git a/src/Assets/AssetContainer.php b/src/Assets/AssetContainer.php new file mode 100644 index 00000000..6e82ba76 --- /dev/null +++ b/src/Assets/AssetContainer.php @@ -0,0 +1,56 @@ +data; + + return AssetContainerFacade::make($model->handle) + ->disk(array_get($data, 'disk')) + ->title(array_get($data, 'title')) + ->allowDownloading(array_get($data, 'allow_downloading')) + ->allowMoving(array_get($data, 'allow_moving')) + ->allowRenaming(array_get($data, 'allow_renaming')) + ->allowUploads(array_get($data, 'allow_uploads')) + ->createFolders(array_get($data, 'create_folders')) + ->searchIndex(array_get($data, 'search_index')); + } + + public function toModel() + { + $model = AssetContainerModel::firstOrNew([ + 'handle' => $this->id(), + ]); + + $model->data = $this->fileData(); + $model->save(); + + return $model; + } + + public function model($model = null) + { + if (func_num_args() === 0) { + return $this->model; + } + + $this->model = $model; + + $this->id($model->handle); + + return $this; + } + + public function lastModified() + { + return $this->model->updated_at; + } +} diff --git a/src/Assets/AssetContainerModel.php b/src/Assets/AssetContainerModel.php new file mode 100644 index 00000000..c7a55c90 --- /dev/null +++ b/src/Assets/AssetContainerModel.php @@ -0,0 +1,18 @@ + 'json', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; +} diff --git a/src/Assets/AssetContainerRepository.php b/src/Assets/AssetContainerRepository.php new file mode 100644 index 00000000..e2a0721d --- /dev/null +++ b/src/Assets/AssetContainerRepository.php @@ -0,0 +1,61 @@ + AssetContainer::class, + ]; + } + + public function all(): Collection + { + return Blink::once('asset-containers', function () { + $keys = AssetContainerModel::get()->map(function ($model) { + return AssetContainer::fromModel($model); + }); + + return Collection::make($keys); + }); + } + + public function find($handle): ?AssetContainer + { + return Blink::once('asset-containers::' . $handle, function () use ($handle) { + if (($model = AssetContainerModel::where('handle', $handle)->first()) == null) { + return null; + } + + $assetContainer = AssetContainer::fromModel($model); + + return $assetContainer; + }); + } + + public function findByHandle($handle): ?AssetContainer + { + return $this->find($handle); + } + + public function save($assetContainer) + { + $model = $assetContainer->toModel(); + + $model->save(); + + $assetContainer->model($model->fresh()); + } + + public function delete($assetContainer) + { + $assetContainer->toModel()->delete(); + } +} diff --git a/src/Assets/AssetModel.php b/src/Assets/AssetModel.php new file mode 100644 index 00000000..159d4c72 --- /dev/null +++ b/src/Assets/AssetModel.php @@ -0,0 +1,18 @@ + 'json', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; +} diff --git a/src/Assets/AssetRepository.php b/src/Assets/AssetRepository.php new file mode 100644 index 00000000..edc4db69 --- /dev/null +++ b/src/Assets/AssetRepository.php @@ -0,0 +1,28 @@ +container()->contents()->forget($asset->path())->save(); + + AssetModel::where('handle', $asset->containerHandle() . '::' . $asset->metaPath())->first()->delete(); + + Stache::store('assets::' . $asset->containerHandle())->delete($asset); + } + + public static function bindings(): array + { + return [ + AssetContract::class => Asset::class, + QueryBuilder::class => \Statamic\Assets\QueryBuilder::class, + ]; + } +} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 677de9cc..b2b24453 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -10,6 +10,8 @@ use Statamic\Contracts\Structures\NavTreeRepository as NavTreeRepositoryContract; use Statamic\Contracts\Taxonomies\TaxonomyRepository as TaxonomyRepositoryContract; use Statamic\Contracts\Taxonomies\TermRepository as TermRepositoryContract; +use Statamic\Contracts\Assets\AssetContainerRepository as AssetContainerRepositoryContract; +use Statamic\Contracts\Assets\AssetRepository as AssetRepositoryContract; use Statamic\Eloquent\Collections\CollectionRepository; use Statamic\Eloquent\Commands\ImportEntries; use Statamic\Eloquent\Entries\EntryQueryBuilder; @@ -21,6 +23,8 @@ use Statamic\Eloquent\Taxonomies\TaxonomyRepository; use Statamic\Eloquent\Taxonomies\TermQueryBuilder; use Statamic\Eloquent\Taxonomies\TermRepository; +use Statamic\Eloquent\Assets\AssetRepository; +use Statamic\Eloquent\Assets\AssetContainerRepository; use Statamic\Providers\AddonServiceProvider; use Statamic\Statamic; @@ -47,6 +51,7 @@ public function boot() public function register() { + $this->registerAssets(); $this->registerBlueprints(); $this->registerFieldsets(); $this->registerEntries(); @@ -155,4 +160,10 @@ private function registerStructures() return config('statamic-eloquent-driver.trees.model'); }); } + + private function registerAssets() + { + Statamic::repository(AssetRepositoryContract::class, AssetRepository::class); + Statamic::repository(AssetContainerRepositoryContract::class, AssetContainerRepository::class); + } } From a1c01a82e8ea1dc99ec6eb9b0d47581f237434b2 Mon Sep 17 00:00:00 2001 From: Julio Carlos Menendez Date: Wed, 6 Oct 2021 13:12:47 -0600 Subject: [PATCH 41/42] Adds roles to the database. --- config/eloquent-driver.php | 5 ++ .../2021_10_06_193801_create_roles_table.php | 35 ++++++++++ src/Auth/Role.php | 45 ++++++++++++ src/Auth/RoleModel.php | 19 ++++++ src/Auth/RoleRepository.php | 68 +++++++++++++++++++ src/ServiceProvider.php | 16 +++++ 6 files changed, 188 insertions(+) create mode 100644 database/migrations/2021_10_06_193801_create_roles_table.php create mode 100644 src/Auth/Role.php create mode 100644 src/Auth/RoleModel.php create mode 100644 src/Auth/RoleRepository.php diff --git a/config/eloquent-driver.php b/config/eloquent-driver.php index ebe9913b..ea2b6bc2 100644 --- a/config/eloquent-driver.php +++ b/config/eloquent-driver.php @@ -40,4 +40,9 @@ 'model' => \Statamic\Eloquent\Structures\NavTreeModel::class, ], + 'roles' => [ + 'model' => \Statamic\Eloquent\Auth\RoleModel::class, + 'entry' => \Statamic\Eloquent\Auth\Role::class, + ], + ]; diff --git a/database/migrations/2021_10_06_193801_create_roles_table.php b/database/migrations/2021_10_06_193801_create_roles_table.php new file mode 100644 index 00000000..c5f343c4 --- /dev/null +++ b/database/migrations/2021_10_06_193801_create_roles_table.php @@ -0,0 +1,35 @@ +id(); + $table->string('handle'); + $table->string('title'); + $table->json('permissions')->nullable(); + $table->json('preferences')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('roles'); + } +} diff --git a/src/Auth/Role.php b/src/Auth/Role.php new file mode 100644 index 00000000..5089271c --- /dev/null +++ b/src/Auth/Role.php @@ -0,0 +1,45 @@ +title($model->title) + ->handle($model->handle) + ->permissions($model->permissions) + ->preferences($model->preferences) + ->model($model); + } + + public function toModel() + { + $class = app('statamic.eloquent.roles.model'); + + return $class::findOrNew($this->model?->id)->fill([ + 'title' => $this->title, + 'handle' => $this->handle, + 'permissions' => $this->permissions, + 'preferences' => $this->preferences, + ]); + } + + public function model($model = null) + { + if (func_num_args() === 0) { + return $this->model; + } + + $this->model = $model; + + $this->id($model->id); + + return $this; + } +} \ No newline at end of file diff --git a/src/Auth/RoleModel.php b/src/Auth/RoleModel.php new file mode 100644 index 00000000..0091ae58 --- /dev/null +++ b/src/Auth/RoleModel.php @@ -0,0 +1,19 @@ + 'json', + 'preferences' => 'json', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; +} diff --git a/src/Auth/RoleRepository.php b/src/Auth/RoleRepository.php new file mode 100644 index 00000000..f9549bc0 --- /dev/null +++ b/src/Auth/RoleRepository.php @@ -0,0 +1,68 @@ +handle($handle); + } + + public function save($role) + { + $model = $role->toModel(); + + $model->save(); + + $role->model($model->fresh()); + } + + public function delete($role) + { + $role->model()->delete(); + } + + public static function bindings(): array + { + return [ + RoleContract::class => app('statamic.eloquent.roles.entry'), + ]; + } + + protected function transform($items, $columns = []) + { + return IlluminateCollection::make($items)->map(function ($model) { + return app(RoleContract::class)::fromModel($model); + }); + } + public function all(): IlluminateCollection + { + $class = app('statamic.eloquent.roles.model'); + return $this->transform($class::all()); + } + + public function find($handle): ?RoleContract + { + $class = app('statamic.eloquent.roles.model'); + $model = $class::whereHandle($handle)->first(); + + return $model + ? app(RoleContract::class)->fromModel($model) + : null; + } + + public function findByHandle($handle): ?RoleContract + { + $class = app('statamic.eloquent.roles.model'); + $model = $class::whereHandle($handle)->first(); + + return $model + ? app(RoleContract::class)->fromModel($model) + : null; + } +} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index b2b24453..6c5c4ff3 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -12,6 +12,7 @@ use Statamic\Contracts\Taxonomies\TermRepository as TermRepositoryContract; use Statamic\Contracts\Assets\AssetContainerRepository as AssetContainerRepositoryContract; use Statamic\Contracts\Assets\AssetRepository as AssetRepositoryContract; +use Statamic\Contracts\Auth\RoleRepository as RoleRepositoryContract; use Statamic\Eloquent\Collections\CollectionRepository; use Statamic\Eloquent\Commands\ImportEntries; use Statamic\Eloquent\Entries\EntryQueryBuilder; @@ -25,6 +26,7 @@ use Statamic\Eloquent\Taxonomies\TermRepository; use Statamic\Eloquent\Assets\AssetRepository; use Statamic\Eloquent\Assets\AssetContainerRepository; +use Statamic\Eloquent\Auth\RoleRepository; use Statamic\Providers\AddonServiceProvider; use Statamic\Statamic; @@ -59,6 +61,7 @@ public function register() $this->registerTaxonomies(); $this->registerGlobals(); $this->registerStructures(); + $this->registerRoles(); } protected function registerBlueprints() @@ -166,4 +169,17 @@ private function registerAssets() Statamic::repository(AssetRepositoryContract::class, AssetRepository::class); Statamic::repository(AssetContainerRepositoryContract::class, AssetContainerRepository::class); } + + private function registerRoles() + { + $this->app->bind('statamic.eloquent.roles.entry', function () { + return config('statamic-eloquent-driver.roles.entry'); + }); + + $this->app->bind('statamic.eloquent.roles.model', function () { + return config('statamic-eloquent-driver.roles.model'); + }); + + Statamic::repository(RoleRepositoryContract::class, RoleRepository::class); + } } From a81687546328de30e94b47ce69647af4810b1c31 Mon Sep 17 00:00:00 2001 From: Julio Carlos Menendez Date: Wed, 6 Oct 2021 15:54:50 -0600 Subject: [PATCH 42/42] Adds user groups to the database. --- config/eloquent-driver.php | 5 ++ .../2021_10_06_213822_create_groups_table.php | 34 +++++++++++ src/Auth/UserGroup.php | 43 ++++++++++++++ src/Auth/UserGroupModel.php | 18 ++++++ src/Auth/UserGroupRepository.php | 58 +++++++++++++++++++ src/ServiceProvider.php | 16 +++++ 6 files changed, 174 insertions(+) create mode 100644 database/migrations/2021_10_06_213822_create_groups_table.php create mode 100644 src/Auth/UserGroup.php create mode 100644 src/Auth/UserGroupModel.php create mode 100644 src/Auth/UserGroupRepository.php diff --git a/config/eloquent-driver.php b/config/eloquent-driver.php index ea2b6bc2..23d104ef 100644 --- a/config/eloquent-driver.php +++ b/config/eloquent-driver.php @@ -45,4 +45,9 @@ 'entry' => \Statamic\Eloquent\Auth\Role::class, ], + 'groups' => [ + 'model' => \Statamic\Eloquent\Auth\UserGroupModel::class, + 'entry' => \Statamic\Eloquent\Auth\UserGroup::class, + ], + ]; diff --git a/database/migrations/2021_10_06_213822_create_groups_table.php b/database/migrations/2021_10_06_213822_create_groups_table.php new file mode 100644 index 00000000..59cd2b32 --- /dev/null +++ b/database/migrations/2021_10_06_213822_create_groups_table.php @@ -0,0 +1,34 @@ +id(); + $table->string('handle'); + $table->string('title'); + $table->json('roles')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('groups'); + } +} diff --git a/src/Auth/UserGroup.php b/src/Auth/UserGroup.php new file mode 100644 index 00000000..b699b639 --- /dev/null +++ b/src/Auth/UserGroup.php @@ -0,0 +1,43 @@ +title($model->title) + ->handle($model->handle) + ->roles($model->roles) + ->model($model); + } + + public function toModel() + { + $class = app('statamic.eloquent.groups.model'); + + return $class::findOrNew($this->model?->id)->fill([ + 'title' => $this->title, + 'handle' => $this->handle, + 'roles' => $this->roles->keys(), + ]); + } + + public function model($model = null) + { + if (func_num_args() === 0) { + return $this->model; + } + + $this->model = $model; + + $this->id($model->id); + + return $this; + } +} diff --git a/src/Auth/UserGroupModel.php b/src/Auth/UserGroupModel.php new file mode 100644 index 00000000..b6eb0658 --- /dev/null +++ b/src/Auth/UserGroupModel.php @@ -0,0 +1,18 @@ + 'json', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; +} diff --git a/src/Auth/UserGroupRepository.php b/src/Auth/UserGroupRepository.php new file mode 100644 index 00000000..69874ffb --- /dev/null +++ b/src/Auth/UserGroupRepository.php @@ -0,0 +1,58 @@ +toModel(); + + $model->save(); + + $userGroup->model($model->fresh()); + } + + public function delete($userGroup) + { + $userGroup->model()->delete(); + } + + public static function bindings(): array + { + return [ + UserGroupContract::class => app('statamic.eloquent.groups.entry'), + ]; + } + + protected function transform($items, $columns = []) + { + return IlluminateCollection::make($items)->map(function ($model) { + return app(UserGroupContract::class)::fromModel($model); + }); + } + public function all(): IlluminateCollection + { + $class = app('statamic.eloquent.groups.model'); + return $this->transform($class::all()); + } + + public function find($id): ?UserGroupContract + { + $class = app('statamic.eloquent.groups.model'); + $model = $class::whereHandle($id)->first(); + + return $model + ? app(UserGroupContract::class)->fromModel($model) + : null; + } +} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 6c5c4ff3..30b9551f 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -13,6 +13,7 @@ use Statamic\Contracts\Assets\AssetContainerRepository as AssetContainerRepositoryContract; use Statamic\Contracts\Assets\AssetRepository as AssetRepositoryContract; use Statamic\Contracts\Auth\RoleRepository as RoleRepositoryContract; +use Statamic\Contracts\Auth\UserGroupRepository as UserGroupRepositoryContract; use Statamic\Eloquent\Collections\CollectionRepository; use Statamic\Eloquent\Commands\ImportEntries; use Statamic\Eloquent\Entries\EntryQueryBuilder; @@ -27,6 +28,7 @@ use Statamic\Eloquent\Assets\AssetRepository; use Statamic\Eloquent\Assets\AssetContainerRepository; use Statamic\Eloquent\Auth\RoleRepository; +use Statamic\Eloquent\Auth\UserGroupRepository; use Statamic\Providers\AddonServiceProvider; use Statamic\Statamic; @@ -62,6 +64,7 @@ public function register() $this->registerGlobals(); $this->registerStructures(); $this->registerRoles(); + $this->registerUserGroups(); } protected function registerBlueprints() @@ -182,4 +185,17 @@ private function registerRoles() Statamic::repository(RoleRepositoryContract::class, RoleRepository::class); } + + private function registerUserGroups() + { + $this->app->bind('statamic.eloquent.groups.entry', function () { + return config('statamic-eloquent-driver.groups.entry'); + }); + + $this->app->bind('statamic.eloquent.groups.model', function () { + return config('statamic-eloquent-driver.groups.model'); + }); + + Statamic::repository(UserGroupRepositoryContract::class, UserGroupRepository::class); + } }