From 98494f3c12ea91ea3516704399f6d95709f6d778 Mon Sep 17 00:00:00 2001 From: Jason Baciulis Date: Tue, 27 Oct 2026 16:09:51 +0700 Subject: [PATCH] Fix Search utility when index names are customized --- .../CP/Utilities/UpdateSearchController.php | 11 +-- tests/Feature/Utilities/UpdateSearchTest.php | 93 +++++++++++++++++++ 2 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 tests/Feature/Utilities/UpdateSearchTest.php diff --git a/src/Http/Controllers/CP/Utilities/UpdateSearchController.php b/src/Http/Controllers/CP/Utilities/UpdateSearchController.php index 46f1d423acd..9736c59e9fe 100644 --- a/src/Http/Controllers/CP/Utilities/UpdateSearchController.php +++ b/src/Http/Controllers/CP/Utilities/UpdateSearchController.php @@ -18,14 +18,13 @@ public function update(Request $request) 'indexes' => 'required', ])['indexes']); - $indexes->each(function ($index) { - [$name, $locale] = explode('::', $index); + $availableIndexes = Search::indexes(); - if ($locale) { - $name = Str::before($name, '_'.$locale); - } + $indexes->each(function ($index) use ($availableIndexes) { + $name = Str::before($index, '::'); + + $index = $availableIndexes->get($name) ?? throw new \InvalidArgumentException("Search index [{$name}] is not defined."); - $index = Search::index($name, $locale ?: null); $index->update(); SearchIndexUpdated::dispatch($index); diff --git a/tests/Feature/Utilities/UpdateSearchTest.php b/tests/Feature/Utilities/UpdateSearchTest.php new file mode 100644 index 00000000000..c39e0c0b40f --- /dev/null +++ b/tests/Feature/Utilities/UpdateSearchTest.php @@ -0,0 +1,93 @@ +setSites([ + 'en' => ['url' => '/', 'locale' => 'en'], + 'fr' => ['url' => '/fr/', 'locale' => 'fr'], + ]); + + config(['statamic.search.indexes' => [ + 'test' => ['driver' => 'null'], + 'localized' => ['driver' => 'null', 'sites' => ['en', 'fr']], + ]]); + } + + private function update(array $indexes) + { + return $this + ->actingAs(tap(User::make()->makeSuper())->save()) + ->post(cp_route('utilities.search.update'), ['indexes' => $indexes]); + } + + private function assertIndexesUpdated(array $names) + { + $updated = Event::dispatched(SearchIndexUpdated::class)->map(fn ($event) => $event[0]->index->name()); + + $this->assertEquals($names, $updated->all()); + } + + #[Test] + public function it_updates_the_selected_indexes() + { + $this->setUpIndexes(); + + $this->update(['test::null', 'localized_fr::fr'])->assertSessionHas('success'); + + $this->assertIndexesUpdated(['test', 'localized_fr']); + } + + #[Test] + public function it_updates_the_selected_indexes_when_the_names_have_been_customized() + { + // When a custom resolver prefixes the name, the resolved name can no longer be + // reversed back into the configured handle by string manipulation. + Index::resolveNameUsing(fn ($name, $locale) => 'prefix_'.($locale ? $name.'_'.$locale : $name)); + + $this->setUpIndexes(); + + $this->update(['prefix_test::null', 'prefix_localized_fr::fr'])->assertSessionHas('success'); + + $this->assertIndexesUpdated(['prefix_test', 'prefix_localized_fr']); + } + + #[Test] + public function it_errors_when_the_index_doesnt_exist() + { + $this->setUpIndexes(); + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Search index [unknown] is not defined.'); + + $this->withoutExceptionHandling()->update(['unknown::null']); + } +}