キーワード検索機能の追加
今回はこのように検索機能をつけて投稿の中から検索キーワードの文字列に合致する記事を表示してくれるようにした。
1. Controllerへの追加点
以下の関数を追加する
public function search(Request $request)
{
$query = $request->input('query');
$posts = Post::where('title', 'like', "%{$query}%")
->orWhere('body', 'like', "%{$query}%")
->latest()
->get();
return view('post.search', compact('posts'));
}
以下説明
public function search(Request $request)
public function search
→ search という名前の関数(メソッド)を作っています。これはコントローラー内で定義され、外部からアクセスできる関数です。
(Request $request)
→ ユーザーが送信したデータ(検索キーワードなど)を受け取るための Request オブジェクトを引数として受け取っています。
$query = $request->input('query');
$request->input('query')
→ ユーザーが検索フォームで入力した値を取得しています。
→ 例えば、ユーザーが「Laravel」と入力した場合、$query には "Laravel" という文字列が入ります。
$posts = Post::where('title', 'like', "%{$query}%")
->orWhere('body', 'like', "%{$query}%")
->latest()
->get();
ここでデータベースの posts テーブルから検索を行っています。
Post::where('title', 'like', "%{$query}%")
Post は、posts テーブルを操作するための Eloquent モデル です。
Eloquentモデルとは、LaravelのORM(Object-Relational Mapping)であるEloquentが提供する、データベースとPHPのオブジェクトを簡単に操作できる機能のことです。Eloquentモデルを使うことで、SQLを書かずにデータベースのレコードを操作できます。
where('title', 'like', "%{$query}%")
は、title カラム(列)に $query の文字列を含むデータを検索します。
LIKE は SQL の検索条件で、"%{$query}%" は、query という単語を含む(前後にどんな文字があってもOK)データを探すための書き方です。例えば、$query = "Laravel" の場合、以下のような title を持つ投稿がヒットします:
"Laravel 入門"
"Laravel の基本"
"初めての Laravel"
orWhere('body', 'like', "%{$query}%")
orWhere は "または(OR)" の条件を追加します。
body カラム(記事の本文)にも $query が含まれるデータも検索対象にします。
->latest()
latest() は、新しい投稿から順番に並べるためのものです。
->get()
get() を使うことで、検索結果をすべて取得します。
return view('post.search', compact('posts'));
view('post.search', compact('posts'))
→ post.search というビュー(画面)に posts のデータを渡して表示します。
compact('posts')
→ これは ['posts' => $posts] と同じ意味で、ビューに posts という変数名で検索結果を渡しています。
2. ビューの作成
index.blade.php に以下のコードを追加
<!-- 検索フォームをスタイリング -->
<div class="max-w-7xl mx-auto px-6 mt-4">
<form action="{{ route('post.search') }}" method="GET" class="flex gap-2 mb-6">
<input type="text" name="query" placeholder="検索キーワードを入力"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<button type="submit" class="px-4 py-2 bg-blue-500 text-white font-semibold rounded-lg hover:bg-blue-600">
検索
</button>
</form>
</div>
以下説明
<form action="{{ route('post.search') }}" method="GET" class="flex gap-2 mb-6">
action="{{ route('post.search') }}"
→ post.search ルートに検索キーワードを GET 送信
method="GET"
→ URLのクエリパラメータとして検索ワードを送る(例: /search?query=Laravel)
また新しくsearch.blade.php を作成し以下のようにビューを作成
<!-- resources/views/post/search.blade.php -->
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
🔍 検索結果
</h2>
</x-slot>
<div class="max-w-7xl mx-auto px-6">
<!-- 検索フォーム -->
<form action="{{ route('post.search') }}" method="GET" class="flex gap-2 my-6">
<input type="text" name="query" placeholder="検索キーワードを入力"
value="{{ request('query') }}"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<button type="submit" class="px-4 py-2 bg-blue-500 text-white font-semibold rounded-lg hover:bg-blue-600">
検索
</button>
</form>
<!-- 検索結果 -->
@if ($posts->isEmpty())
<p class="text-gray-500 text-center py-6">該当する投稿がありません。</p>
@else
@foreach($posts as $post)
<div class="mt-4 p-8 bg-white w-full rounded-2xl">
<h1 class="p-4 text-lg font-semibold">
件名:
<a href="{{route('post.show',$post)}}" class="text-blue-600">
{{$post->title}}
</a>
</h1>
<hr class="w-full">
<p class="mt-4 p-4">
{{$post->body}}
</p>
@if($post->image)
<img src="{{ asset('storage/' . $post->image) }}" alt="投稿画像" style="max-width:200px;">
@endif
<div class="p-4 text-sm font-semibold">
<p>
{{$post->created_at}} / {{ optional($post->user)->name ?? 'ゲスト' }}
</p>
</div>
</div>
@endforeach
@endif
</div>
</x-app-layout>
以下説明
<form action="{{ route('post.search') }}" method="GET" class="flex gap-2 my-6">
<input type="text" name="query" placeholder="検索キーワードを入力"
value="{{ request('query') }}"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<button type="submit" class="px-4 py-2 bg-blue-500 text-white font-semibold rounded-lg hover:bg-blue-600">
検索
</button>
</form>
この form のコードは、検索キーワードを入力し、ボタンを押すことで、特定のページに遷移し、検索結果を表示する という動作を実現しています。
action="{{ route('post.search') }}"
→ 検索の GET リクエストを送信
value="{{ request('query') }}"
これにより、検索ワードを保持(再検索時に入力欄に前回の検索ワードを残す)
@if ($posts->isEmpty())
<p class="text-gray-500 text-center py-6">該当する投稿がありません。</p>
@else
$posts->isEmpty() → 結果がない場合、メッセージを表示
@foreach($posts as $post)
<div class="mt-4 p-8 bg-white w-full rounded-2xl">
foreach($posts as $post) → posts のデータを1件ずつ表示
@if($post->image)
<img src="{{ asset('storage/' . $post->image) }}" alt="投稿画像" style="max-width:200px;">
@endif
if($post->image) → 画像がある場合のみ表示
asset('storage/' . $post->image)
→ storage フォルダ内の画像を表示
<div class="p-4 text-sm font-semibold">
<p>
{{$post->created_at}} / {{ optional($post->user)->name ?? 'ゲスト' }}
</p>
</div>
$post->created_at → 投稿日時を表示
optional($post->user)->name ?? 'ゲスト'
投稿者名を表示(ユーザー情報が null の場合 "ゲスト" にする)
このようなフォームを作成することができる。
form> の action とは?
form> タグの action 属性は、フォームの送信先(リクエストを送るURL) を指定します。
<form action="送信先のURL" method="GET">
例えば、以下のように書くと、https://example.com/search にリクエストが送られます。
<form action="/search" method="GET">
method="GET" は、HTML の
タグで使用される属性で、フォームデータを送信する際の HTTP メソッドを指定するものです。このフォームでは、「検索キーワードを入力」→「検索ボタンを押す」 と、GET リクエストが /search に送信されます。GET は主に 検索やページ遷移など、データを取得する目的 で使われます。GET リクエストでは、フォームの入力データが URL にクエリパラメータとして付加されます。
https://example.com/search?query=Laravel
route('post.search') の意味
Laravelでは、ルート(ページのURL)を route('ルート名') という形で取得できます。
これは、routes/web.php に定義されたルート名に対応するURLを動的に取得するためのものです。ルートに例えば
Route::get('/search', [PostController::class, 'search'])->name('post.search');
ここで name('post.search') を付けたことで、
route('post.search') は /search というURLを表す ようになります。