Make QuickSwitcher search across all locales

Delegates to DocumentService::search which queries DocumentTranslation
and collapses to distinct documents. Display titles use the Document
title accessor (current locale + fallback).
This commit is contained in:
Yutaka Kurosaki
2026-05-10 12:43:01 +09:00
parent 0100a0afb4
commit c9586612f5
2 changed files with 38 additions and 48 deletions
+13 -48
View File
@@ -4,65 +4,32 @@
use App\Models\Document;
use App\Services\DocumentService;
use Livewire\Component;
use Livewire\Attributes\Computed;
use Livewire\Component;
class QuickSwitcher extends Component
{
public $search = '';
public $selectedIndex = 0;
public string $search = '';
public int $selectedIndex = 0;
#[Computed]
public function results()
{
if (empty($this->search)) {
return Document::select('id', 'title', 'slug', 'path', 'updated_at')
$documents = Document::with('translations')
->orderBy('updated_at', 'desc')
->limit(10)
->get()
->map(fn($doc) => [
'id' => $doc->id,
'title' => $doc->title,
'slug' => $doc->slug,
'directory' => dirname($doc->path),
])
->toArray();
->get();
} else {
$documents = app(DocumentService::class)->search($this->search, 10);
}
// FULLTEXT検索を使用(日本語対応)
$results = Document::select('id', 'title', 'slug', 'path', 'updated_at')
->whereRaw('MATCH(title, content) AGAINST(? IN BOOLEAN MODE)', [$this->search])
->orderBy('updated_at', 'desc')
->limit(10)
->get()
->map(fn($doc) => [
'id' => $doc->id,
'title' => $doc->title,
'slug' => $doc->slug,
'directory' => dirname($doc->path),
])
->toArray();
// FULLTEXT検索で結果がない場合は LIKE 検索にフォールバック
if (empty($results)) {
$results = Document::select('id', 'title', 'slug', 'path', 'updated_at')
->where(function($query) {
$query->where('title', 'like', '%' . $this->search . '%')
->orWhere('content', 'like', '%' . $this->search . '%');
})
->orderBy('updated_at', 'desc')
->limit(10)
->get()
->map(fn($doc) => [
'id' => $doc->id,
'title' => $doc->title,
'slug' => $doc->slug,
'directory' => dirname($doc->path),
])
->toArray();
}
return $results;
return $documents->map(fn ($doc) => [
'id' => $doc->id,
'title' => $doc->title,
'slug' => $doc->slug,
'directory' => dirname($doc->path),
])->values()->toArray();
}
public function updated($propertyName)
@@ -92,8 +59,6 @@ public function selectDocument()
$results = $this->results;
if (isset($results[$this->selectedIndex])) {
$document = $results[$this->selectedIndex];
// slug が存在することを確認
if (!empty($document['slug'])) {
return $this->redirect(route('documents.show', $document['slug']));
}
+25
View File
@@ -102,4 +102,29 @@ public function test_editor_for_missing_locale_shows_empty_form_with_new_locale_
// The blade should render a tab marked active for ja with empty inputs
$response->assertSeeText(__('messages.locale_names.ja', [], 'en'));
}
public function test_quick_switcher_finds_documents_by_any_locale_title(): void
{
$doc = Document::factory()->create(['default_locale' => 'en', 'slug' => 'qs']);
$doc->translations()->where('locale', 'en')->update(['title' => 'Getting Started', 'content' => 'EN body']);
DocumentTranslation::factory()->create([
'document_id' => $doc->id,
'locale' => 'ja',
'title' => 'はじめに',
'content' => '本文',
]);
$component = \Livewire\Livewire::test(\App\Livewire\QuickSwitcher::class)
->set('search', 'はじめに');
$results = $component->get('results');
$this->assertCount(1, $results);
$this->assertSame($doc->id, $results[0]['id']);
$component2 = \Livewire\Livewire::test(\App\Livewire\QuickSwitcher::class)
->set('search', 'Getting');
$results2 = $component2->get('results');
$this->assertCount(1, $results2);
$this->assertSame($doc->id, $results2[0]['id']);
}
}