From 93e1a154d80815b15b12a1b02ef7cb46e37c104d Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Tue, 2 Jul 2024 12:15:14 +0100 Subject: [PATCH 01/16] Clear entry-uris cache on save --- src/Entries/EntryRepository.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Entries/EntryRepository.php b/src/Entries/EntryRepository.php index 15e8ebeb..df85b6a0 100644 --- a/src/Entries/EntryRepository.php +++ b/src/Entries/EntryRepository.php @@ -56,6 +56,8 @@ public function save($entry) $entry->model($model->fresh()); + Blink::store('entry-uris')->forget($entry->id()); + Blink::put("eloquent-entry-{$entry->id()}", $entry); Blink::put("eloquent-entry-{$entry->uri()}", $entry); } From 4b15703616fba3c2256a4c915fbabcb222b88f47 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Tue, 2 Jul 2024 12:16:01 +0100 Subject: [PATCH 02/16] Only when necessary --- src/Entries/EntryRepository.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Entries/EntryRepository.php b/src/Entries/EntryRepository.php index df85b6a0..b9bfc871 100644 --- a/src/Entries/EntryRepository.php +++ b/src/Entries/EntryRepository.php @@ -56,7 +56,9 @@ public function save($entry) $entry->model($model->fresh()); - Blink::store('entry-uris')->forget($entry->id()); + if ($entry->isDirty('slug')) { + Blink::store('entry-uris')->forget($entry->id()); + } Blink::put("eloquent-entry-{$entry->id()}", $entry); Blink::put("eloquent-entry-{$entry->uri()}", $entry); From b0452b573470ef88cec34fd3df0350dade92a514 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Tue, 2 Jul 2024 15:08:50 +0100 Subject: [PATCH 03/16] We shouldnt do this, issue is in core --- src/Entries/EntryRepository.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Entries/EntryRepository.php b/src/Entries/EntryRepository.php index b9bfc871..15e8ebeb 100644 --- a/src/Entries/EntryRepository.php +++ b/src/Entries/EntryRepository.php @@ -56,10 +56,6 @@ public function save($entry) $entry->model($model->fresh()); - if ($entry->isDirty('slug')) { - Blink::store('entry-uris')->forget($entry->id()); - } - Blink::put("eloquent-entry-{$entry->id()}", $entry); Blink::put("eloquent-entry-{$entry->uri()}", $entry); } From b09c3bd925fbae47763a1ba12ebb2b846617d78f Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Tue, 2 Jul 2024 15:08:55 +0100 Subject: [PATCH 04/16] Add test showing issue - should fail --- tests/Entries/EntryTest.php | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/Entries/EntryTest.php b/tests/Entries/EntryTest.php index be603b10..3415babb 100644 --- a/tests/Entries/EntryTest.php +++ b/tests/Entries/EntryTest.php @@ -5,12 +5,15 @@ use Facades\Statamic\Fields\BlueprintRepository; use Illuminate\Foundation\Testing\RefreshDatabase; use PHPUnit\Framework\Attributes\Test; +use Statamic\Contracts\Entries\CollectionRepository as CollectionRepositoryContract; use Statamic\Eloquent\Collections\Collection; use Statamic\Eloquent\Entries\Entry; use Statamic\Eloquent\Entries\EntryModel; use Statamic\Facades; use Statamic\Facades\Collection as CollectionFacade; use Statamic\Facades\Entry as EntryFacade; +use Statamic\Stache\Repositories\CollectionRepository; +use Statamic\Statamic; use Tests\TestCase; class EntryTest extends TestCase @@ -301,4 +304,37 @@ public function it_doesnt_store_mapped_data_when_config_is_disabled() $this->assertSame($entry->foo, $fresh->foo); } + + #[Test] + public function saving_an_entry_with_a_different_slug_clears_the_uri_cache_when_collections_are_file_driven() + { + Statamic::repository(CollectionRepositoryContract::class, CollectionRepository::class); + + $collection = Collection::make('blog')->title('blog') + ->structureContents(['max_depth' => 2, 'orderable' => true]) + ->routes([ + 'en' => '{parent_uri}/{slug}', + ])->save(); + + $entry = (new Entry()) + ->id('1.0') + ->collection('blog') + ->slug('the-slug') + ->data([ + 'foo' => 'bar', + ]); + + $entry->save(); + + $collection->structure()->in('en')->tree([['entry' => '1.0', 'children' => []]])->save(); + + $this->assertSame('/the-slug', $entry->uri()); + $this->assertSame('/the-slug', $entry->model()->uri); + + $entry->slug('the-new-slug')->save(); + + dd($entry->model()); + + $this->assertSame('/blog/the-new-slug', $entry->model()->uri); + } } From ac5a7e5ceb2e22f4e421f2484bbf8c825f8c32d8 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 2 Jul 2024 17:01:27 -0400 Subject: [PATCH 05/16] adjust test --- tests/Entries/EntryTest.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/Entries/EntryTest.php b/tests/Entries/EntryTest.php index 3415babb..25a445a2 100644 --- a/tests/Entries/EntryTest.php +++ b/tests/Entries/EntryTest.php @@ -329,12 +329,11 @@ public function saving_an_entry_with_a_different_slug_clears_the_uri_cache_when_ $collection->structure()->in('en')->tree([['entry' => '1.0', 'children' => []]])->save(); $this->assertSame('/the-slug', $entry->uri()); - $this->assertSame('/the-slug', $entry->model()->uri); + $this->assertSame('/the-slug', $entry->model()->fresh()->uri); $entry->slug('the-new-slug')->save(); - dd($entry->model()); - - $this->assertSame('/blog/the-new-slug', $entry->model()->uri); + $this->assertSame('/the-new-slug', $entry->uri()); + $this->assertSame('/the-new-slug', $entry->model()->fresh()->uri); } } From 962639e3ce91fff0c7f2362207019264911c7228 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 2 Jul 2024 17:04:07 -0400 Subject: [PATCH 06/16] use core branch temporarily --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5b134ff9..c907323e 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ }, "require": { "php": "^8.1", - "statamic/cms": "^5.12" + "statamic/cms": "dev-collections-doing-stuff-entries-should-probably-be-doing as 5.12.0" }, "require-dev": { "doctrine/dbal": "^3.8", From 33d206c01951556234d3e6fd069b56e1b733897d Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 2 Jul 2024 17:05:57 -0400 Subject: [PATCH 07/16] override --- src/Entries/EntryRepository.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Entries/EntryRepository.php b/src/Entries/EntryRepository.php index 15e8ebeb..f42fc564 100644 --- a/src/Entries/EntryRepository.php +++ b/src/Entries/EntryRepository.php @@ -67,4 +67,16 @@ public function delete($entry) $entry->model()->delete(); } + + public function updateUris($collection, $ids = null) + { + $ids = collect($ids); + + $this + ->query() + ->where('collection', $collection->handle()) + ->when($ids->isNotEmpty(), fn ($query) => $query->whereIn('id', $ids)) + ->get() + ->each(fn ($entry) => $entry->model()->update(['uri' => $entry->uri()])); + } } From 1c5f87dd2e130f80403fa6e8d5929ba892894410 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 5 Jul 2024 16:01:54 -0400 Subject: [PATCH 08/16] remove method from collection repository --- src/Collections/CollectionRepository.php | 10 ---------- src/Entries/EntryRepository.php | 4 +--- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/Collections/CollectionRepository.php b/src/Collections/CollectionRepository.php index ccb1f7a0..794110e9 100644 --- a/src/Collections/CollectionRepository.php +++ b/src/Collections/CollectionRepository.php @@ -10,16 +10,6 @@ class CollectionRepository extends StacheRepository { - public function updateEntryUris($collection, $ids = null) - { - $query = $collection->queryEntries() - ->when($ids, fn ($query) => $query->whereIn('id', $ids)) - ->get() - ->each(function ($entry) { - app('statamic.eloquent.entries.model')::find($entry->id())->update(['uri' => $entry->uri()]); - }); - } - public function all(): IlluminateCollection { return Blink::once('eloquent-collections', function () { diff --git a/src/Entries/EntryRepository.php b/src/Entries/EntryRepository.php index f42fc564..7c0b7e28 100644 --- a/src/Entries/EntryRepository.php +++ b/src/Entries/EntryRepository.php @@ -72,9 +72,7 @@ public function updateUris($collection, $ids = null) { $ids = collect($ids); - $this - ->query() - ->where('collection', $collection->handle()) + $collection->queryEntries() ->when($ids->isNotEmpty(), fn ($query) => $query->whereIn('id', $ids)) ->get() ->each(fn ($entry) => $entry->model()->update(['uri' => $entry->uri()])); From 7457b5a88fe1edc58b9ac7ae4f17dc3c3c0932ab Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 9 Jul 2024 12:19:52 -0400 Subject: [PATCH 09/16] ensure that the unblinked uri is stored when saving the entry ... i moved the id conditional to the start because i only want to clear the blink when the source has an id, and the blink clear needs to happen before calling uri. --- src/Entries/Entry.php | 14 ++++++++++---- tests/Entries/EntryTest.php | 26 +++++++++----------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/Entries/Entry.php b/src/Entries/Entry.php index 0a1e6100..65f5ce3d 100644 --- a/src/Entries/Entry.php +++ b/src/Entries/Entry.php @@ -100,7 +100,17 @@ public static function makeModelFromContract(EntryContract $source) $dataMappings = (new self)->getDataColumnMappings(new $class); + $attributes = []; + + if ($id = $source->id()) { + $attributes['id'] = $id; + + // Ensure that when calling $source->uri() that it doesn't use the cached value. + Blink::store('entry-uris')->forget($source->id()); + } + $attributes = [ + ...$attributes, 'origin_id' => $origin?->id(), 'site' => $source->locale(), 'slug' => $source->slug(), @@ -118,10 +128,6 @@ public static function makeModelFromContract(EntryContract $source) $attributes[$key] = $data->get($key); } - if ($id = $source->id()) { - $attributes['id'] = $id; - } - return $class::findOrNew($id)->fill($attributes); } diff --git a/tests/Entries/EntryTest.php b/tests/Entries/EntryTest.php index 25a445a2..84edfbaf 100644 --- a/tests/Entries/EntryTest.php +++ b/tests/Entries/EntryTest.php @@ -5,15 +5,12 @@ use Facades\Statamic\Fields\BlueprintRepository; use Illuminate\Foundation\Testing\RefreshDatabase; use PHPUnit\Framework\Attributes\Test; -use Statamic\Contracts\Entries\CollectionRepository as CollectionRepositoryContract; use Statamic\Eloquent\Collections\Collection; use Statamic\Eloquent\Entries\Entry; use Statamic\Eloquent\Entries\EntryModel; use Statamic\Facades; use Statamic\Facades\Collection as CollectionFacade; use Statamic\Facades\Entry as EntryFacade; -use Statamic\Stache\Repositories\CollectionRepository; -use Statamic\Statamic; use Tests\TestCase; class EntryTest extends TestCase @@ -306,34 +303,29 @@ public function it_doesnt_store_mapped_data_when_config_is_disabled() } #[Test] - public function saving_an_entry_with_a_different_slug_clears_the_uri_cache_when_collections_are_file_driven() + public function saving_an_entry_updates_the_uri() { - Statamic::repository(CollectionRepositoryContract::class, CollectionRepository::class); + // The URI is stored in the Blink cache. This test ensures + // that the new URI is stored and not the blinked one. - $collection = Collection::make('blog')->title('blog') - ->structureContents(['max_depth' => 2, 'orderable' => true]) - ->routes([ - 'en' => '{parent_uri}/{slug}', - ])->save(); + Collection::make('blog')->title('blog') + ->routes('{parent_uri}/{slug}') + ->save(); $entry = (new Entry()) ->id('1.0') ->collection('blog') ->slug('the-slug') - ->data([ - 'foo' => 'bar', - ]); + ->data(['foo' => 'bar']); $entry->save(); - $collection->structure()->in('en')->tree([['entry' => '1.0', 'children' => []]])->save(); - $this->assertSame('/the-slug', $entry->uri()); - $this->assertSame('/the-slug', $entry->model()->fresh()->uri); + $this->assertSame('/the-slug', $entry->model()->uri); $entry->slug('the-new-slug')->save(); $this->assertSame('/the-new-slug', $entry->uri()); - $this->assertSame('/the-new-slug', $entry->model()->fresh()->uri); + $this->assertSame('/the-new-slug', $entry->model()->uri); } } From 25e7b63b99cc6ab0f3ad00cecd1ed475f29b6bec Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 9 Jul 2024 13:00:12 -0400 Subject: [PATCH 10/16] test --- tests/Entries/EntryRepositoryTest.php | 73 +++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 tests/Entries/EntryRepositoryTest.php diff --git a/tests/Entries/EntryRepositoryTest.php b/tests/Entries/EntryRepositoryTest.php new file mode 100644 index 00000000..31f8bd52 --- /dev/null +++ b/tests/Entries/EntryRepositoryTest.php @@ -0,0 +1,73 @@ +routes('blog/{slug}')->save(); + + (new Entry)->id(1)->collection($collection)->slug('alfa')->save(); + (new Entry)->id(2)->collection($collection)->slug('bravo')->save(); + (new Entry)->id(3)->collection($collection)->slug('charlie')->save(); + + $collection->routes('posts/{slug}')->save(); + + // Assert that the URIs are unchanged, to make sure that saving + // the collection isn't what caused the URIs to be updated. + $this->assertEquals([ + '/blog/alfa', + '/blog/bravo', + '/blog/charlie', + ], EntryModel::all()->map->uri->all()); + + (new EntryRepository(new Stache))->updateUris($collection); + + $this->assertEquals([ + '/posts/alfa', + '/posts/bravo', + '/posts/charlie', + ], EntryModel::all()->map->uri->all()); + } + + #[Test] + public function it_updates_the_uris_of_specific_entries_in_a_collection() + { + $collection = Collection::make('blog')->routes('blog/{slug}')->save(); + + (new Entry)->id(1)->collection($collection)->slug('alfa')->save(); + (new Entry)->id(2)->collection($collection)->slug('bravo')->save(); + (new Entry)->id(3)->collection($collection)->slug('charlie')->save(); + + $collection->routes('posts/{slug}')->save(); + + // Assert that the URIs are unchanged, to make sure that saving + // the collection isn't what caused the URIs to be updated. + $this->assertEquals([ + '/blog/alfa', + '/blog/bravo', + '/blog/charlie', + ], EntryModel::all()->map->uri->all()); + + (new EntryRepository(new Stache))->updateUris($collection, [2, 3]); + + $this->assertEquals([ + '/blog/alfa', + '/posts/bravo', + '/posts/charlie', + ], EntryModel::all()->map->uri->all()); + } +} From cdb16853c6f60be0d0facdb2d3125b68c6b75020 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 9 Jul 2024 13:10:37 -0400 Subject: [PATCH 11/16] orders --- src/Collections/CollectionRepository.php | 19 ----- src/Entries/EntryRepository.php | 19 +++++ src/Listeners/UpdateStructuredEntryOrder.php | 35 --------- src/ServiceProvider.php | 8 -- tests/Entries/EntryRepositoryTest.php | 82 ++++++++++++++++++++ 5 files changed, 101 insertions(+), 62 deletions(-) delete mode 100644 src/Listeners/UpdateStructuredEntryOrder.php diff --git a/src/Collections/CollectionRepository.php b/src/Collections/CollectionRepository.php index 794110e9..136ca2e0 100644 --- a/src/Collections/CollectionRepository.php +++ b/src/Collections/CollectionRepository.php @@ -4,7 +4,6 @@ use Illuminate\Support\Collection as IlluminateCollection; use Statamic\Contracts\Entries\Collection as CollectionContract; -use Statamic\Eloquent\Jobs\UpdateCollectionEntryOrder; use Statamic\Facades\Blink; use Statamic\Stache\Repositories\CollectionRepository as StacheRepository; @@ -66,22 +65,4 @@ public static function bindings(): array CollectionContract::class => Collection::class, ]; } - - public function updateEntryOrder(CollectionContract $collection, $ids = null) - { - $query = $collection->queryEntries() - ->when($ids, fn ($query) => $query->whereIn('id', $ids)) - ->get(['id']) - ->each(function ($entry) { - $dispatch = UpdateCollectionEntryOrder::dispatch($entry->id()); - - $connection = config('statamic.eloquent-driver.collections.update_entry_order_connection', 'default'); - - if ($connection != 'default') { - $dispatch->onConnection($connection); - } - - $dispatch->onQueue(config('statamic.eloquent-driver.collections.update_entry_order_queue', 'default')); - }); - } } diff --git a/src/Entries/EntryRepository.php b/src/Entries/EntryRepository.php index 7c0b7e28..22f06b09 100644 --- a/src/Entries/EntryRepository.php +++ b/src/Entries/EntryRepository.php @@ -4,6 +4,7 @@ use Statamic\Contracts\Entries\Entry as EntryContract; use Statamic\Contracts\Entries\QueryBuilder; +use Statamic\Eloquent\Jobs\UpdateCollectionEntryOrder; use Statamic\Facades\Blink; use Statamic\Stache\Repositories\EntryRepository as StacheRepository; @@ -77,4 +78,22 @@ public function updateUris($collection, $ids = null) ->get() ->each(fn ($entry) => $entry->model()->update(['uri' => $entry->uri()])); } + + public function updateOrders($collection, $ids = null) + { + $collection->queryEntries() + ->when($ids, fn ($query) => $query->whereIn('id', $ids)) + ->get(['id']) + ->each(function ($entry) { + $dispatch = UpdateCollectionEntryOrder::dispatch($entry->id()); + + $connection = config('statamic.eloquent-driver.collections.update_entry_order_connection', 'default'); + + if ($connection != 'default') { + $dispatch->onConnection($connection); + } + + $dispatch->onQueue(config('statamic.eloquent-driver.collections.update_entry_order_queue', 'default')); + }); + } } diff --git a/src/Listeners/UpdateStructuredEntryOrder.php b/src/Listeners/UpdateStructuredEntryOrder.php deleted file mode 100644 index 65c2d557..00000000 --- a/src/Listeners/UpdateStructuredEntryOrder.php +++ /dev/null @@ -1,35 +0,0 @@ -tree; - $collection = $tree->collection(); - - if (config('statamic.eloquent-driver.entries.driver', 'file') !== 'eloquent') { - return; - } - - if (config('statamic.eloquent-driver.collections.driver') === 'eloquent') { - // If the collections are configured to use Eloquent, then the entry - // order will be updated through the regular event/listener flow. - return; - } - - $diff = $tree->diff(); - - $ids = array_merge($diff->moved(), $diff->added()); - - if (empty($ids)) { - return; - } - - app(CollectionRepository::class)->updateEntryOrder($collection, $ids); - } -} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index c2e8a806..dbc4a73c 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -31,7 +31,6 @@ use Statamic\Eloquent\Forms\SubmissionRepository; use Statamic\Eloquent\Globals\GlobalRepository; use Statamic\Eloquent\Globals\GlobalVariablesRepository; -use Statamic\Eloquent\Listeners\UpdateStructuredEntryOrder; use Statamic\Eloquent\Revisions\RevisionRepository; use Statamic\Eloquent\Structures\CollectionTreeRepository; use Statamic\Eloquent\Structures\NavigationRepository; @@ -40,7 +39,6 @@ use Statamic\Eloquent\Taxonomies\TermQueryBuilder; use Statamic\Eloquent\Taxonomies\TermRepository; use Statamic\Eloquent\Tokens\TokenRepository; -use Statamic\Events\CollectionTreeSaved; use Statamic\Providers\AddonServiceProvider; use Statamic\Statamic; @@ -61,12 +59,6 @@ class ServiceProvider extends AddonServiceProvider \Statamic\Eloquent\Updates\ChangeFormSubmissionsIdType::class, ]; - protected $listen = [ - CollectionTreeSaved::class => [ - UpdateStructuredEntryOrder::class, - ], - ]; - public function boot() { parent::boot(); diff --git a/tests/Entries/EntryRepositoryTest.php b/tests/Entries/EntryRepositoryTest.php index 31f8bd52..4ef8ecec 100644 --- a/tests/Entries/EntryRepositoryTest.php +++ b/tests/Entries/EntryRepositoryTest.php @@ -3,10 +3,12 @@ namespace Tests\Entries; use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Facades\Event; use PHPUnit\Framework\Attributes\Test; use Statamic\Eloquent\Entries\Entry; use Statamic\Eloquent\Entries\EntryModel; use Statamic\Eloquent\Entries\EntryRepository; +use Statamic\Events\CollectionTreeSaved; use Statamic\Facades\Collection; use Statamic\Stache\Stache; use Tests\TestCase; @@ -70,4 +72,84 @@ public function it_updates_the_uris_of_specific_entries_in_a_collection() '/posts/charlie', ], EntryModel::all()->map->uri->all()); } + + #[Test] + public function it_updates_the_order_of_all_entries_in_a_collection() + { + Event::fake(CollectionTreeSaved::class); + + $collection = Collection::make('blog') + ->structureContents(['max_depth' => 1]) + ->save(); + + (new Entry)->id(1)->collection($collection)->slug('alfa')->save(); + (new Entry)->id(2)->collection($collection)->slug('bravo')->save(); + (new Entry)->id(3)->collection($collection)->slug('charlie')->save(); + (new Entry)->id(4)->collection($collection)->slug('delta')->save(); + + $collection->structure()->in('en')->tree([ + ['entry' => 4], + ['entry' => 2], + ['entry' => 1], + ['entry' => 3], + ])->save(); + + // Assert that the order is unchanged, to make sure that saving + // the structure isn't what caused the order to be updated. + $this->assertEquals([ + 1 => 1, + 2 => 1, + 3 => 1, + 4 => 1, + ], EntryModel::all()->mapWithKeys(fn ($e) => [$e->id => $e->order])->all()); + + (new EntryRepository(new Stache))->updateOrders($collection); + + $this->assertEquals([ + 1 => 3, + 2 => 2, + 3 => 4, + 4 => 1, + ], EntryModel::all()->mapWithKeys(fn ($e) => [$e->id => $e->order])->all()); + } + + #[Test] + public function it_updates_the_order_of_specific_entries_in_a_collection() + { + Event::fake(CollectionTreeSaved::class); + + $collection = Collection::make('blog') + ->structureContents(['max_depth' => 1]) + ->save(); + + (new Entry)->id(1)->collection($collection)->slug('alfa')->save(); + (new Entry)->id(2)->collection($collection)->slug('bravo')->save(); + (new Entry)->id(3)->collection($collection)->slug('charlie')->save(); + (new Entry)->id(4)->collection($collection)->slug('delta')->save(); + + $collection->structure()->in('en')->tree([ + ['entry' => 4], + ['entry' => 2], + ['entry' => 1], + ['entry' => 3], + ])->save(); + + // Assert that the order is unchanged, to make sure that saving + // the structure isn't what caused the order to be updated. + $this->assertEquals([ + 1 => 1, + 2 => 1, + 3 => 1, + 4 => 1, + ], EntryModel::all()->mapWithKeys(fn ($e) => [$e->id => $e->order])->all()); + + (new EntryRepository(new Stache))->updateOrders($collection, [2, 3]); + + $this->assertEquals([ + 1 => 1, + 2 => 2, + 3 => 4, + 4 => 1, + ], EntryModel::all()->mapWithKeys(fn ($e) => [$e->id => $e->order])->all()); + } } From bf0762bec7c49d77169ea7f7527714614a512b13 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 9 Jul 2024 13:20:59 -0400 Subject: [PATCH 12/16] same for parents --- src/Entries/EntryRepository.php | 19 ++++++ src/Jobs/UpdateCollectionEntryParent.php | 28 ++++++++ tests/Entries/EntryRepositoryTest.php | 82 ++++++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 src/Jobs/UpdateCollectionEntryParent.php diff --git a/src/Entries/EntryRepository.php b/src/Entries/EntryRepository.php index 22f06b09..4a3e00c6 100644 --- a/src/Entries/EntryRepository.php +++ b/src/Entries/EntryRepository.php @@ -5,6 +5,7 @@ use Statamic\Contracts\Entries\Entry as EntryContract; use Statamic\Contracts\Entries\QueryBuilder; use Statamic\Eloquent\Jobs\UpdateCollectionEntryOrder; +use Statamic\Eloquent\Jobs\UpdateCollectionEntryParent; use Statamic\Facades\Blink; use Statamic\Stache\Repositories\EntryRepository as StacheRepository; @@ -96,4 +97,22 @@ public function updateOrders($collection, $ids = null) $dispatch->onQueue(config('statamic.eloquent-driver.collections.update_entry_order_queue', 'default')); }); } + + public function updateParents($collection, $ids = null) + { + $collection->queryEntries() + ->when($ids, fn ($query) => $query->whereIn('id', $ids)) + ->get(['id']) + ->each(function ($entry) { + $dispatch = UpdateCollectionEntryParent::dispatch($entry->id()); + + $connection = config('statamic.eloquent-driver.collections.update_entry_parent_connection', 'default'); + + if ($connection != 'default') { + $dispatch->onConnection($connection); + } + + $dispatch->onQueue(config('statamic.eloquent-driver.collections.update_entry_parent_queue', 'default')); + }); + } } diff --git a/src/Jobs/UpdateCollectionEntryParent.php b/src/Jobs/UpdateCollectionEntryParent.php new file mode 100644 index 00000000..fcd3472c --- /dev/null +++ b/src/Jobs/UpdateCollectionEntryParent.php @@ -0,0 +1,28 @@ +entryId = $entryId; + } + + public function handle() + { + if ($entry = Entry::find($this->entryId)) { + $entry->save(); + } + } +} diff --git a/tests/Entries/EntryRepositoryTest.php b/tests/Entries/EntryRepositoryTest.php index 4ef8ecec..c874376b 100644 --- a/tests/Entries/EntryRepositoryTest.php +++ b/tests/Entries/EntryRepositoryTest.php @@ -152,4 +152,86 @@ public function it_updates_the_order_of_specific_entries_in_a_collection() 4 => 1, ], EntryModel::all()->mapWithKeys(fn ($e) => [$e->id => $e->order])->all()); } + + #[Test] + public function it_updates_the_parents_of_all_entries_in_a_collection() + { + Event::fake(CollectionTreeSaved::class); + + $collection = Collection::make('blog') + ->structureContents(['root' => true]) + ->save(); + + (new Entry)->id(1)->collection($collection)->slug('alfa')->save(); + (new Entry)->id(2)->collection($collection)->slug('bravo')->save(); + (new Entry)->id(3)->collection($collection)->slug('charlie')->save(); + (new Entry)->id(4)->collection($collection)->slug('delta')->save(); + + $collection->structure()->in('en')->tree([ + ['entry' => 4], + ['entry' => 2, 'children' => [ + ['entry' => 1], + ]], + ['entry' => 3], + ])->save(); + + // Assert that the parents are unchanged, to make sure that saving + // the structure isn't what caused the parents to be updated. + $this->assertEquals([ + 1 => null, + 2 => null, + 3 => null, + 4 => null, + ], EntryModel::all()->mapWithKeys(fn ($e) => [$e->id => $e->data['parent'] ?? null])->all()); + + (new EntryRepository(new Stache))->updateParents($collection); + + $this->assertEquals([ + 1 => 2, + 2 => 4, + 3 => 4, + 4 => null, + ], EntryModel::all()->mapWithKeys(fn ($e) => [$e->id => $e->data['parent'] ?? null])->all()); + } + + #[Test] + public function it_updates_the_parents_of_specific_entries_in_a_collection() + { + Event::fake(CollectionTreeSaved::class); + + $collection = Collection::make('blog') + ->structureContents(['root' => true]) + ->save(); + + (new Entry)->id(1)->collection($collection)->slug('alfa')->save(); + (new Entry)->id(2)->collection($collection)->slug('bravo')->save(); + (new Entry)->id(3)->collection($collection)->slug('charlie')->save(); + (new Entry)->id(4)->collection($collection)->slug('delta')->save(); + + $collection->structure()->in('en')->tree([ + ['entry' => 4], + ['entry' => 2, 'children' => [ + ['entry' => 1], + ]], + ['entry' => 3], + ])->save(); + + // Assert that the parents are unchanged, to make sure that saving + // the structure isn't what caused the parents to be updated. + $this->assertEquals([ + 1 => null, + 2 => null, + 3 => null, + 4 => null, + ], EntryModel::all()->mapWithKeys(fn ($e) => [$e->id => $e->data['parent'] ?? null])->all()); + + (new EntryRepository(new Stache))->updateParents($collection, [2, 3]); + + $this->assertEquals([ + 1 => null, + 2 => 4, + 3 => 4, + 4 => null, + ], EntryModel::all()->mapWithKeys(fn ($e) => [$e->id => $e->data['parent'] ?? null])->all()); + } } From 389945accf02ee9a3e5458b76bbb674e58124499 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 10 Jul 2024 15:12:01 -0400 Subject: [PATCH 13/16] use real constraint --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c907323e..44c205d2 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ }, "require": { "php": "^8.1", - "statamic/cms": "dev-collections-doing-stuff-entries-should-probably-be-doing as 5.12.0" + "statamic/cms": "^5.14.0" }, "require-dev": { "doctrine/dbal": "^3.8", From 8988017326cd43c83bfbe31723f6e498ca17405f Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 10 Jul 2024 15:12:25 -0400 Subject: [PATCH 14/16] implied --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 44c205d2..26304565 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ }, "require": { "php": "^8.1", - "statamic/cms": "^5.14.0" + "statamic/cms": "^5.14" }, "require-dev": { "doctrine/dbal": "^3.8", From 185908f0afb0508e7e815247ffc09a5bf86e2bb6 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 10 Jul 2024 15:14:37 -0400 Subject: [PATCH 15/16] bump From 27e2ae0dbe51437c35c6efac4d5f7ee73307d851 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 10 Jul 2024 15:16:37 -0400 Subject: [PATCH 16/16] bump