ローカルスコープはモデルのメソッドとして定義し、先頭に scope を付けます。Laravel は scopePopular のようなメソッドを見つけると、外からは popular() という名前で呼べるようにします 。
class User extends Model
{
public function scopeActive($query)
{
return $query->where('active', 1);
}
}
呼び出し側はこうです。
User::active()->get();
この active() 呼び出しは、内部的には Eloquent Builder に対してクエリ条件を追加しているだけです。スコープのメソッドは Builder を受け取り、Builder を返すのが基本です 。
Laravel 12 系では、#[Scope] 属性を使って scope プレフィックスなしで定義する方法も紹介されていますが、従来の scope* 方式は今でも使えます 。
モデルに書くメリット
条件をモデルに寄せると、同じ条件を何度も書かずに再利用できるのが大きな利点です 。また、where の塊がリポジトリやコントローラに散らばりにくくなり、User::active()->ofType('admin') のように読みやすいチェーンになります 。
さらに、モデルに「この集まりはどういう条件で取るか」という意味を閉じ込められるので、ドメインの意図が見えやすいです。active users や published articles のような概念が、そのままメソッド名になります 。
デメリット
一方で、モデルに条件を集めすぎると、モデルが肥大化しやすいです。検索条件、集計条件、管理画面用条件などを全部入れると、関連の薄いロジックまでモデルに混ざります 。
また、複雑な検索や複数テーブルをまたぐ条件は、スコープだけで表現すると読みにくくなることがあります。そういう場合は、モデルスコープよりもクエリオブジェクトやサービス層の方が適切なことがあります 。
リポジトリに直書きする場合との比較
| 観点 | モデルのスコープ | リポジトリに where 直書き |
|---|---|---|
| 再利用性 | 高い。同じ条件をどこでも呼べる | 低い。各メソッドで重複しやすい |
| 可読性 | ドメイン名で読める | SQL 寄りで意図が見えやすいこともある |
| 変更容易性 | 条件変更を一箇所に集約しやすい | 変更箇所が散らばりやすい |
| 複雑条件への向き不向き | 単純な条件に強い | 複雑な検索でも書き分けやすい |
| 責務分離 | ドメイン的な条件をモデルに寄せやすい | データ取得の詳細をリポジトリに閉じやすい |
書くときの注意点
スコープは「どこでも使える便利な共通条件」だけに絞るのが基本です。画面固有の条件や、一回しか使わない条件まで入れると、かえって見通しが悪くなります 。
スコープは 必ず Builder を返す ようにしてください。途中で get() や first() を呼ぶと、チェーンできなくなります 。