Laravelで複雑な検索やフィルター処理を繰り返し実装していると、「同じ条件を何度も書いてしまっている」「クエリが読みにくい」と感じたことはないでしょうか?
そんなときに活用すべきが、Eloquentの「クエリスコープ(Query Scope)」機能です。この記事では、クエリスコープの基本的な使い方から、実務で役立つ設計パターン、応用例までをわかりやすく解説します。
クエリスコープとは?
クエリスコープとは、モデルに共通化されたクエリロジックを定義し、チェーンメソッドとして呼び出せる仕組みです。検索条件を関数化することで、コードの再利用性と可読性が向上します。
ローカルスコープの基本的な書き方
まずは、もっとも一般的な「ローカルスコープ」の定義方法です。User
モデルに「有効ユーザーのみ取得する」スコープを定義してみましょう。
// app/Models/User.php
public function scopeActive($query)
{
return $query->where('status', 'active');
}
呼び出し側は、以下のようにチェーンメソッドとして使用できます。
User::active()->get();
関数名の先頭は「scope」+呼び出し時はその部分を省略するのがルールです(例:scopeActive()
→ active()
)。
パラメータ付きのスコープ
スコープに引数を渡すことも可能です。たとえば、指定日以降に作成されたユーザーを取得するスコープは以下のように書けます。
public function scopeCreatedAfter($query, $date)
{
return $query->whereDate('created_at', '>=', $date);
}
呼び出し側:
User::createdAfter('2024-01-01')->get();
引数を複数指定することで、さらに柔軟な条件を組み込むことも可能です。
スコープの組み合わせで柔軟な検索処理
スコープはチェーン可能なので、複数の条件を読みやすく並べられます。
User::active()
->createdAfter('2024-01-01')
->where('role', 'admin')
->get();
このように記述すれば、検索ロジックの再利用性が向上し、保守もしやすくなります。
動的スコープの設計パターン:検索フォームの値に応じて条件分岐
実務では、「検索条件があるときだけ絞り込みたい」ことが多くあります。そうした場合は、条件付きでクエリを追加するスコープを使うと便利です。
public function scopeKeyword($query, $keyword)
{
if (!empty($keyword)) {
$query->where('name', 'like', '%' . $keyword . '%');
}
}
呼び出し:
User::keyword(request('keyword'))->paginate(10);
バリデーション済のリクエスト値と連動させれば、柔軟な検索機能をシンプルに実装できます。
よく使うクエリスコープの設計例
以下は実務でよく使われるスコープの例です。
// ステータス指定
public function scopeStatus($query, $status)
{
return $query->when($status, fn($q) => $q->where('status', $status));
}
// 並び順(指定がない場合はデフォルト)
public function scopeSortBy($query, $column = 'created_at', $direction = 'desc')
{
return $query->orderBy($column, $direction);
}
スコープの注意点とベストプラクティス
- スコープは常に
return $query
することで、チェーンが可能になります。 - 過剰なネストは避ける。条件が複雑化する場合はサービスクラスへの分離を検討。
- 命名は「意図が伝わる名前」にする(例:
active()
・recent()
・keyword()
など)。
まとめ
Eloquentのクエリスコープを活用すれば、重複コードを排除し、検索処理を可読性高く構築することが可能になります。
- スコープで検索条件を共通化・再利用
- 検索フォームとの連携で柔軟な絞り込み
- 命名・設計ルールを統一して保守性向上
複雑な一覧画面や検索画面を構築する際には、ぜひスコープの活用を検討してみてください。