From 7232df9ad1a42fc172b2dd2b9a2cf13f79bdcb99 Mon Sep 17 00:00:00 2001 From: edalzell Date: Thu, 16 Jul 2026 17:32:15 -0700 Subject: [PATCH] Fix search:update silently ignoring the index argument When index names are customized via `Index::resolveNameUsing()`, passing a configured handle to `statamic:search:update` matched nothing and fell through to the "which index?" prompt instead of updating that index. `getRequestedIndex()` resolved the handle by prefix-matching against the resolved name, which no longer holds once a resolver renames the index. Match on the configured handle instead, which the index already tracks. --- src/Search/Commands/Update.php | 9 ++-- src/Search/Index.php | 5 ++ tests/Search/Commands/UpdateTest.php | 73 ++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 tests/Search/Commands/UpdateTest.php diff --git a/src/Search/Commands/Update.php b/src/Search/Commands/Update.php index 3e6ba18611a..349d0066040 100644 --- a/src/Search/Commands/Update.php +++ b/src/Search/Commands/Update.php @@ -6,7 +6,6 @@ use Statamic\Console\RunsInPlease; use Statamic\Events\SearchIndexUpdated; use Statamic\Facades\Search; -use Statamic\Support\Str; use function Laravel\Prompts\select; @@ -35,7 +34,7 @@ public function handle() private function getIndexes() { - if ($requestedIndex = $this->getRequestedIndex()) { + if (! is_null($requestedIndex = $this->getRequestedIndex())) { return $requestedIndex; } @@ -71,10 +70,10 @@ private function getRequestedIndex() return [$this->indexes()->get($arg)]; } - // They might have entered a name as it appears in the config, but if it + // They might have entered a handle as it appears in the config, but if it // should be localized we'll get all of the localized versions. - if (collect(config('statamic.search.indexes'))->put('cp', [])->has($arg)) { - return $this->indexes()->filter(fn ($index) => Str::startsWith($index->name(), $arg))->all(); + if ($indexes = $this->indexes()->filter(fn ($index) => $index->handle() === $arg)->all()) { + return $indexes; } throw new \InvalidArgumentException("Index [$arg] does not exist."); diff --git a/src/Search/Index.php b/src/Search/Index.php index 43e2437bbaf..c4422dbb7f5 100644 --- a/src/Search/Index.php +++ b/src/Search/Index.php @@ -41,6 +41,11 @@ public function name() return $this->name; } + public function handle() + { + return $this->handle; + } + public static function resolveNameUsing(?Closure $callback) { static::$nameCallback = $callback; diff --git a/tests/Search/Commands/UpdateTest.php b/tests/Search/Commands/UpdateTest.php new file mode 100644 index 00000000000..b165ae00651 --- /dev/null +++ b/tests/Search/Commands/UpdateTest.php @@ -0,0 +1,73 @@ +setSites([ + 'en' => ['url' => '/'], + 'fr' => ['url' => '/fr/'], + ]); + + config(['statamic.search.indexes' => [ + 'test' => ['driver' => 'null', 'sites' => ['en', 'fr']], + 'cp' => ['driver' => 'null'], + ]]); + } + + #[Test] + public function it_updates_the_localized_indexes_matching_the_configured_handle() + { + $this->setUpIndexes(); + + $this->artisan(Update::class, ['index' => 'test']) + ->expectsOutputToContain('Index test_en updated.') + ->expectsOutputToContain('Index test_fr updated.') + ->doesntExpectOutputToContain('Index cp updated.') + ->assertExitCode(0); + } + + #[Test] + public function it_updates_the_localized_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) => 'local_'.$name.'_'.$locale); + + $this->setUpIndexes(); + + // The argument is the handle as it appears in the config, so it should still + // match both localized versions, and it should leave the cp index alone. + $this->artisan(Update::class, ['index' => 'test']) + ->expectsOutputToContain('Index local_test_en updated.') + ->expectsOutputToContain('Index local_test_fr updated.') + ->doesntExpectOutputToContain('Index local_cp_ updated.') + ->assertExitCode(0); + } + + #[Test] + public function it_errors_when_the_index_doesnt_exist() + { + $this->setUpIndexes(); + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Index [unknown] does not exist.'); + + $this->artisan(Update::class, ['index' => 'unknown'])->run(); + } +}