【Laravel】複数テーブルをまたぐ検索フォームの作り方|EloquentのwhereHas・joinの使い分け

【Laravel】複数テーブルをまたぐ検索フォームの作り方|EloquentのwhereHas・joinの使い分け Laravel

Laravelで複数のテーブルにまたがる検索機能を実装する際、Eloquentのリレーションを活用すれば、クエリを簡潔に書くことができます。この記事では、Eloquentでの検索における whereHasjoin の使い分けを中心に、検索フォームの作成から検索処理の実装方法まで解説します。

検索機能の概要と想定ケース

ここでは、以下のようなデータ構造を例に解説します。

  • usersテーブル:ユーザー情報
  • postsテーブル:ユーザーが投稿した記事(user_id外部キーあり)

「投稿タイトル」と「ユーザー名」の両方にキーワード検索をかけるようなフォームを想定します。

検索フォームの作成

Bladeファイルに以下のようなフォームを用意します。

<form action="{{ route('search') }}" method="GET">
  <input type="text" name="keyword" placeholder="検索キーワード" value="{{ request('keyword') }}">
  <button type="submit">検索</button>
</form>

whereHasを使った検索の実装方法

whereHasは、リレーション先の条件に一致する親レコードを検索する際に便利です。

use App\Models\Post;

public function search(Request $request)
{
    $keyword = $request->input('keyword');

    $query = Post::query();

    if (!empty($keyword)) {
        $query->where('title', 'like', "%{$keyword}%")
              ->orWhereHas('user', function ($q) use ($keyword) {
                  $q->where('name', 'like', "%{$keyword}%");
              });
    }

    $results = $query->with('user')->get();

    return view('search.result', compact('results'));
}

このようにすれば、「投稿タイトル」も「ユーザー名」も対象とした柔軟な検索が可能です。

joinを使った検索の実装方法

パフォーマンスを重視したい場合や、ソートをリレーション先のカラムで行いたい場合はjoinを使うと便利です。

use Illuminate\Support\Facades\DB;

$keyword = $request->input('keyword');

$results = DB::table('posts')
    ->join('users', 'posts.user_id', '=', 'users.id')
    ->select('posts.*', 'users.name as user_name')
    ->where(function ($query) use ($keyword) {
        $query->where('posts.title', 'like', "%{$keyword}%")
              ->orWhere('users.name', 'like', "%{$keyword}%");
    })
    ->get();

joinを使えば、SQLレベルでの高速な結合検索が可能です。ただし、Eloquentのリレーションは使えないため、モデルインスタンスではなく生のデータとなります。

whereHasとjoinの使い分けのポイント

項目 whereHas join
リレーションの活用 ○(Eloquentリレーション) ×(手動で結合)
パフォーマンス △(やや遅い場合あり) ◎(SQLレベルで高速)
結果の取得形式 Eloquentモデル 配列またはオブジェクト
スコープ・リレーション 使える 使えない

まとめ

複数テーブルをまたぐ検索フォームの実装では、Eloquentの whereHas を使えばモデル間の関係を活かした柔軟な検索が可能です。一方、join は処理速度やSQLレベルの最適化に優れており、大量データを扱う場合に有効です。用途に応じて使い分けることで、実用的で高速な検索機能を構築できます。

関連記事