Laravelでの開発において、検索機能を実装する場面は多くあります。特に複数のテーブルにまたがって検索する場合、リレーションとクエリの書き方に工夫が必要です。本記事では、EloquentのリレーションとwhereHasを使って、複数テーブルにまたがる柔軟な検索処理を実装する方法を解説します。
基本のテーブル構成を確認する
例として以下のような構成を想定します。
- usersテーブル:ユーザー情報
- postsテーブル:投稿情報(user_idでusersに紐付く)
- commentsテーブル:コメント情報(post_idでpostsに紐付く)
ユーザー名やコメント内容など、複数のテーブルを横断して検索したいケースを扱います。
リレーションを定義する
まずは各モデルでリレーションを定義しておきましょう。
// User.php
public function posts()
{
return $this->hasMany(Post::class);
}
// Post.php
public function user()
{
return $this->belongsTo(User::class);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
// Comment.php
public function post()
{
return $this->belongsTo(Post::class);
}
whereHasを使った検索の基本
たとえば「コメント本文に特定のキーワードが含まれる投稿を検索する」場合、次のように記述できます。
$keyword = 'Laravel';
$posts = Post::whereHas('comments', function ($query) use ($keyword) {
$query->where('body', 'like', '%' . $keyword . '%');
})->get();
このようにwhereHasを使うことで、関連テーブルの条件で親テーブルを絞り込めます。
ネストしたリレーションでも検索可能
さらに深い階層のリレーションでも同様に検索できます。たとえば「コメントにLaravelと含まれているユーザー一覧を取得する」といったケースです。
$users = User::whereHas('posts.comments', function ($query) use ($keyword) {
$query->where('body', 'like', '%' . $keyword . '%');
})->get();
posts.commentsのように.でつなぐことで、ネストしたリレーションにも対応できます。
withと組み合わせて検索結果を効率的に取得する
検索後に関連情報をすべて表示したい場合、with()でリレーションを同時に読み込むと効率的です。
$users = User::with('posts.comments')
->whereHas('posts.comments', function ($query) use ($keyword) {
$query->where('body', 'like', '%' . $keyword . '%');
})
->get();
これによりN+1問題も回避しつつ、一覧や詳細画面にそのまま利用できます。
まとめ:リレーションとwhereHasで柔軟な検索を実現
Laravelでは、EloquentのリレーションとwhereHasを使うことで、複数のテーブルにまたがる検索処理をシンプルかつ強力に構築できます。検索対象が深い階層にあっても対応可能で、実務で非常に役立つテクニックです。
複雑な検索機能を求められるプロジェクトでは、ぜひ活用してみてください。