【Laravel】複数テーブルを跨いだ検索機能の実装方法|リレーションとwhereHasの応用

【Laravel】複数テーブルを跨いだ検索機能の実装方法|リレーションとwhereHasの応用 Laravel

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を使うことで、複数のテーブルにまたがる検索処理をシンプルかつ強力に構築できます。検索対象が深い階層にあっても対応可能で、実務で非常に役立つテクニックです。

複雑な検索機能を求められるプロジェクトでは、ぜひ活用してみてください。