From 1c7e14a9c792152f63de27c0b73a98559d0138cb Mon Sep 17 00:00:00 2001 From: edalzell Date: Sat, 14 Nov 2026 18:21:16 -0700 Subject: [PATCH] Update mounted collection uris when the mount's uri changes --- src/Entries/Collection.php | 17 +++++ tests/Feature/Entries/MountingTest.php | 89 ++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/src/Entries/Collection.php b/src/Entries/Collection.php index 6c90a556c4a..90b3bcd1942 100644 --- a/src/Entries/Collection.php +++ b/src/Entries/Collection.php @@ -531,6 +531,8 @@ public function updateEntryUris($ids = null) { Facades\Entry::updateUris($this, $ids); + $this->collectionsMountedOnEntries($ids)->each->updateEntryUris(); + return $this; } @@ -979,6 +981,21 @@ public function getQueryableValue(string $field) return null; } + private function collectionsMountedOnEntries($ids) + { + $mounted = Facades\Collection::all() + ->filter(fn ($collection) => $collection->mount()?->collectionHandle() === $this->handle()); + + if ($mounted->isEmpty() || collect($ids)->isEmpty()) { + return $mounted; + } + + // Compare roots, since the ids may be localizations of the mounted entry. + $rootIds = collect($ids)->map(fn ($id) => Entry::find($id)?->root()->id())->filter()->all(); + + return $mounted->filter(fn ($collection) => in_array($collection->mount()->root()->id(), $rootIds)); + } + private function queryableMethods(): array { return [ diff --git a/tests/Feature/Entries/MountingTest.php b/tests/Feature/Entries/MountingTest.php index 544f74f4346..139ae1c51b4 100644 --- a/tests/Feature/Entries/MountingTest.php +++ b/tests/Feature/Entries/MountingTest.php @@ -72,4 +72,93 @@ public function updating_a_mounted_page_will_not_update_the_uris_when_slug_is_cl $mount->save(); } + + #[Test] + public function updating_the_parent_of_a_mounted_page_will_update_the_uris_for_each_entry_in_that_collection() + { + config(['cache.default' => 'file']); // Doesn't work when they're arrays since the object is stored in memory. + Cache::clear(); + + $this->makeStructuredPages(); + Collection::make('blog')->routes('{mount}/{slug}')->mount('blog')->save(); + $one = EntryFactory::collection('blog')->slug('one')->create(); + + $this->assertEquals($one->id(), Entry::findByUri('/about/blog/one')->id()); + + Entry::find('about')->slug('info')->save(); + + $this->assertNull(Entry::findByUri('/about/blog/one')); + $this->assertEquals($one->id(), Entry::findByUri('/info/blog/one')->id()); + } + + #[Test] + public function moving_a_mounted_page_in_the_tree_will_update_the_uris_for_each_entry_in_that_collection() + { + config(['cache.default' => 'file']); // Doesn't work when they're arrays since the object is stored in memory. + Cache::clear(); + + $pages = $this->makeStructuredPages(); + Collection::make('blog')->routes('{mount}/{slug}')->mount('blog')->save(); + $one = EntryFactory::collection('blog')->slug('one')->create(); + + $this->assertEquals($one->id(), Entry::findByUri('/about/blog/one')->id()); + + $pages->structure()->in('en')->tree([ + ['entry' => 'about'], + ['entry' => 'contact', 'children' => [['entry' => 'blog']]], + ])->save(); + + $this->assertNull(Entry::findByUri('/about/blog/one')); + $this->assertEquals($one->id(), Entry::findByUri('/contact/blog/one')->id()); + } + + #[Test] + public function moving_a_localized_mounted_page_in_the_tree_will_update_the_uris_for_each_entry_in_that_collection() + { + config(['cache.default' => 'file']); // Doesn't work when they're arrays since the object is stored in memory. + Cache::clear(); + + $this->setSites([ + 'en' => ['url' => '/', 'locale' => 'en'], + 'fr' => ['url' => '/fr/', 'locale' => 'fr'], + ]); + + $pages = $this->makeStructuredPages(['en', 'fr']); + collect(['about', 'contact', 'blog'])->each( + fn ($id) => Entry::find($id)->makeLocalization('fr')->id("{$id}-fr")->save() + ); + $pages->structure()->in('fr')->tree([ + ['entry' => 'about-fr', 'children' => [['entry' => 'blog-fr']]], + ['entry' => 'contact-fr'], + ])->save(); + + Collection::make('blog')->sites(['en', 'fr'])->routes('{mount}/{slug}')->mount('blog')->save(); + $one = EntryFactory::collection('blog')->locale('fr')->slug('one')->create(); + + $this->assertEquals($one->id(), Entry::findByUri('/about/blog/one', 'fr')->id()); + + $pages->structure()->in('fr')->tree([ + ['entry' => 'about-fr'], + ['entry' => 'contact-fr', 'children' => [['entry' => 'blog-fr']]], + ])->save(); + + $this->assertNull(Entry::findByUri('/about/blog/one', 'fr')); + $this->assertEquals($one->id(), Entry::findByUri('/contact/blog/one', 'fr')->id()); + } + + private function makeStructuredPages(array $sites = ['en']) + { + $pages = tap(Collection::make('pages')->sites($sites)->routes('{parent_uri}/{slug}')->structureContents(['root' => false]))->save(); + + EntryFactory::id('about')->collection('pages')->slug('about')->create(); + EntryFactory::id('contact')->collection('pages')->slug('contact')->create(); + EntryFactory::id('blog')->collection('pages')->slug('blog')->create(); + + $pages->structure()->in('en')->tree([ + ['entry' => 'about', 'children' => [['entry' => 'blog']]], + ['entry' => 'contact'], + ])->save(); + + return $pages; + } }