Skip to main content

スコープとは

Eloquentのスコープは、クエリに対する制約をまとめて再利用できる仕組みです。スコープには2種類あります。

ローカルスコープ

定義

ローカルスコープは、モデルのメソッドに #[Scope] アトリビュートを付与して定義します。
#[Scope] アトリビュートは Illuminate\Database\Eloquent\Attributes 名前空間にあります。PHP 8.0以降のネイティブ構文です。

使い方

定義したスコープは、メソッドとして呼び出せます。チェーンもできます。

パラメータの受け渡し

スコープメソッドの第2引数以降に追加のパラメータを定義できます。
呼び出しのときにそのまま引数を渡します。

orWhere との組み合わせ

スコープを orWhere でつなぐとき、論理グループが必要になる場合があります。

グローバルスコープ

仕組み

グローバルスコープは Illuminate\Database\Eloquent\Scope インターフェースを実装したクラスです。このインターフェースは apply メソッド1つだけを要求します。
apply メソッドの中でクエリビルダーに制約を追加します。

グローバルスコープクラスの作成

make:scope コマンドで雛形を生成します。
app/Models/Scopes/ActiveScope.php が生成されます。

モデルへの適用

1

#[ScopedBy] アトリビュートで登録(推奨)

Laravel 13では #[ScopedBy] アトリビュートを使うのが最もシンプルです。
複数のスコープを配列で指定できます。
2

booted() メソッドで手動登録

booted メソッドをオーバーライドして addGlobalScope を呼び出す方法もあります。
グローバルスコープを追加すると、User::all() など全クエリに自動で WHERE is_active = 1 が付きます。

無名クロージャによるグローバルスコープ

クラスを別ファイルに作るほどでもない単純なスコープは、クロージャで定義できます。
クロージャで定義したスコープを後から除外するには、クラス名ではなくスコープ名(文字列)を使う必要があります。

グローバルスコープの除外

特定のクエリではスコープを無効にしたい場面があります。

フレームワーク内部: SoftDeletingScope

Laravel標準の SoftDeletes トレイトがグローバルスコープをどう活用しているかを見ると、実装パターンが分かります。 SoftDeletingScopeScope インターフェースを実装しています。
withTrashed() は実際には withoutGlobalScope($this) を呼び出しています。つまり SoftDeletingScope 自身を除外することで、削除済みレコードも取得できるようにしています。
onlyTrashed() も同様に、スコープ自身を除外した上で whereNotNull('deleted_at') を追加しています。
Scope インターフェースに extend メソッドは定義されていませんが、Eloquentのビルダーはスコープが extend メソッドを持っていれば自動的に呼び出します。カスタムマクロを追加したい場合に活用できます。

実践的なユースケース

マルチテナント: テナントIDによる自動絞り込み

SaaSアプリケーションでは、全クエリにテナントIDのフィルタを自動適用することが重要です。
これで Post::all() を呼ぶだけで、認証中のユーザーのテナントデータだけが返ります。

公開/非公開フィルタ

管理画面では非公開の投稿も表示したいが、フロントエンドでは公開済みのみ表示したい場合です。
管理画面では withoutGlobalScope でスコープを除外します。

select ではなく addSelect を使う

グローバルスコープ内でカラムを追加するときは select ではなく addSelect を使ってください。select を使うと、呼び出し元のクエリが select しているカラムを上書きしてしまいます。

次のステップ

Eloquent カスタムキャスト

属性の変換ロジックをカスタムキャストとして実装し、Value Objectパターンを活用する方法を学びます。
最終更新日 2026年3月28日