LaravelのEloquentでクエリスコープを定義する方法を徹底解説!local・globalの違いと使い方
生徒
「Laravelでデータを検索するときに、毎回同じ条件を書くのが面倒なんですが、もっと簡単に書く方法ってありますか?」
先生
「それはとても良い気づきですね!LaravelのEloquentにはクエリスコープという仕組みがあって、検索条件をあらかじめまとめておくことができます。」
生徒
「クエリスコープってなんですか?」
先生
「簡単に言うと、よく使う検索条件を“ショートカット”のように登録しておく仕組みです。では、localスコープとglobalスコープの違いを例を交えて解説していきましょう!」
1. クエリスコープとは?
LaravelのEloquent ORMには、データベース操作を簡単にするための仕組みがたくさん用意されています。その中のひとつがクエリスコープです。クエリスコープを使うと、毎回同じように書いていた検索条件を、ひとつの「共通ルール」としてモデルの中にまとめておくことができます。
例えば、「有効なユーザーだけを取得したい」という条件を毎回書くのは面倒ですよね。何度も同じwhereを並べていると、コードが長くなり読みづらくなってしまいます。
use App\Models\User;
// クエリスコープを使う前のイメージ
$activeUsers = User::where('status', 'active')
->whereNull('deleted_at')
->get();
「ステータスがactive」かつ「削除されていない」ユーザーを毎回このように書くと大変
クエリスコープを使うと、このような「よく使う検索条件」に名前を付けておき、短いメソッド呼び出しだけで同じ条件を再利用できるようになります。
// クエリスコープを使った書き方のイメージ(後の章で定義方法を解説)
$activeUsers = User::active()->get();
active() と書くだけで、先ほどの条件一式が適用された状態でユーザーを取得できるイメージ
このようにクエリスコープを使うと、Eloquentのコードがスッキリして読みやすくなり、同じ条件を何度もコピペする必要もなくなります。Laravelのクエリスコープには大きく分けてlocalスコープとglobalスコープの2種類があり、「必要なときだけ呼び出すスコープ」と「常に自動で付くスコープ」というイメージで使い分けます。具体的な書き方や定義方法は、このあと順番に見ていきましょう。
2. localスコープの定義と使い方
localスコープは、そのモデルの中だけで使えるスコープです。名前の通り「ローカル」なので、そのモデルに対するクエリでだけ有効になります。よく使う検索条件に名前を付けておき、必要なときだけ呼び出せるようにするイメージです。
たとえば、会員一覧画面で「アクティブなユーザーだけを表示したい」というケースを考えてみましょう。毎回where('status', 'active')と書くのは面倒ですし、書き忘れも起きやすくなります。localスコープを使うと、この条件に「active」という名前を付けて、Eloquentのメソッドとして呼び出せるようになります。
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
// localスコープの定義
public function scopeActive($query)
{
return $query->where('status', 'active');
}
}
プログラミング未経験の方に向けて、少し丁寧に見ていきます。
class User extends Model:Userテーブルを扱うための「Userモデル」のクラスです。scopeActive:localスコープは「scope + 名前」というルールでメソッド名を付けます。この例では「active」という名前のスコープになります。$query->where('status', 'active'):statusカラムがactiveのデータだけを絞り込む、という意味です。
ポイントは、メソッド名に必ず「scope」を付けることと、第一引数にクエリビルダ($query)が渡ってくることです。中身では、普段書いているEloquentのクエリと同じように、whereやorderByなどを自由に書けます。
定義したスコープは、コントローラなどで次のように呼び出すことができます。
use App\Models\User;
// localスコープを使ったデータ取得
$activeUsers = User::active()->get();
statusがactiveのユーザー一覧を、active() という1つのメソッド呼び出しで取得できる
呼び出すときはscopeの部分を省略して、定義した名前(この場合はactive)だけを書きます。毎回where('status', 'active')を書く代わりに、User::active()と書けるようになるので、クエリがとても読みやすくなります。
また、localスコープは通常のクエリメソッドと同じように、他の条件とチェーンして使えるのも特徴です。
// localスコープと他の条件を組み合わせる例
$activeAdmins = User::active()
->where('role', 'admin')
->orderBy('created_at', 'desc')
->get();
「アクティブなユーザー」かつ「管理者(admin)」を、新しい順に取得するイメージ
このようにlocalスコープを定義しておくと、「アクティブなユーザー」という意味をひとつのメソッドに閉じ込められるので、LaravelのEloquentクエリがぐっと読みやすくなります。同じような条件を何度も書いていると感じたら、「これはlocalスコープにできないかな?」と考えてみると、コードの整理にもつながります。
3. globalスコープの定義と使い方
globalスコープは、そのモデルを使ったクエリすべてに自動的に条件を適用する仕組みです。例えば「削除されていないデータだけを常に取得したい」といったケースで使います。
具体的な例を見てみましょう。
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class Post extends Model
{
protected static function booted()
{
static::addGlobalScope('published', function (Builder $builder) {
$builder->where('is_published', true);
});
}
}
このように定義すると、Post::all()やPost::where(...)を実行したときに、自動的にis_published = trueの条件が追加されます。
// 自動的に is_published = true がつく
$posts = Post::all();
公開済みの投稿だけが取得される
もし特定の場面でグローバルスコープを外したい場合は、次のように書きます。
$allPosts = Post::withoutGlobalScope('published')->get();
公開・非公開を含めた全ての投稿が取得される
4. localスコープとglobalスコープの使い分け
localスコープとglobalスコープは、使う目的によって選びます。
- localスコープ:そのときだけ特定の条件を適用したいとき(例:アクティブなユーザー、在庫ありの商品)
- globalスコープ:常に適用したい条件があるとき(例:公開済みの記事、削除されていないデータ)
つまり、「毎回書くのは面倒だけど必ず必要な条件」ならglobalスコープを使い、「必要なときだけ呼び出す条件」ならlocalスコープを使うのが基本的な考え方です。
5. 実際の開発での活用例
例えば、ブログアプリを作るときには次のような場面で活用できます。
- localスコープ:「人気記事」「最新の記事」「特定のカテゴリーの記事」などを簡単に取得するために使う
- globalスコープ:「公開済みの記事だけを取得する」「削除されていない記事だけを扱う」など、常に必要な条件を自動で付与するために使う
これにより、アプリ全体のコードがシンプルになり、保守性も向上します。特に初心者の方は、同じ条件を何度も書いていたら「これはスコープにできるかも?」と意識すると良いでしょう。
まとめ
ここまでで、LaravelのEloquentで使えるクエリスコープの基本的な考え方と、localスコープ・globalスコープの違いを一通り確認しました。クエリスコープは、毎回同じように書いていた検索条件をモデル側にまとめておくことで、コードを短く読みやすくし、Laravelアプリ全体の挙動をそろえるための大切な仕組みです。特に初心者のうちは、whereを何度も書いている画面を見つけたら「これはスコープにできないかな」と意識してみると、自然とEloquentの設計力も身についていきます。
まずlocalスコープについて振り返ると、UserモデルにscopeActiveというメソッドを用意して、activeという短い呼び出しに置きかえることで、「有効なユーザーだけを取得する」というよくある条件を一行で表現できるようになりました。これは、料理でよく使う味付けをあらかじめタレとして作っておくのに似ていて、同じ調味料を何度も計量せずに済むイメージです。スコープを使うと、開発途中で条件を変えたいときも、モデル側の一か所を書き換えるだけで、アプリのあちこちにあるクエリに反映できるので、とても効率的です。
globalスコープはもう一歩踏み込んだ仕組みで、「このモデルを使うときは、常にこの条件を自動で付けたい」というときに役立ちます。公開済みの記事だけを基本として扱いたい場合や、論理削除されたデータを普段は見せたくない場合など、アプリのルールとして全体に共通する条件を、モデルのbootedメソッドの中で一度だけ定義できます。これによって、開発者がうっかり条件を書き忘れても、globalスコープが見えないガードレールのように守ってくれるので、安全で安定したクエリを書きやすくなります。
一方で、globalスコープはとても強力な分、意図せず効いていると原因が分かりにくくなることもあります。データが思ったより少ない、あるレコードが取得されない、といったときには、そのモデルにaddGlobalScopeが定義されていないか確認してみるとよいでしょう。また、特別な画面だけは全件を見たい場合にwithoutGlobalScopeでスコープを外せることも、合わせて覚えておくと安心です。localスコープとglobalスコープは、「自分から呼び出す条件」と「自動で付く条件」という違いをイメージすると整理しやすくなります。
Laravelのクエリスコープを使いこなすと、同じビジネスロジックを繰り返し使う場面がとても楽になります。たとえば、アクティブユーザー、公開フラグ付きの記事、在庫ありの商品など、複数画面で同じ条件を使う部分は、積極的にスコープ化しておくと、後から条件が増えたときの修正漏れを防げます。「モデルに書けるルールはなるべくモデルに寄せる」という意識でコードを書くと、ControllerやView側がすっきりして、Laravelらしい構成に近づいていきます。
また、クエリスコープはチーム開発でも力を発揮します。スコープ名を分かりやすく付けておけば、他の人がコードを読んだときにも意図が伝わりやすくなります。たとえばscopePublishedやscopePopularのような名前であれば、「公開済み」「人気順」といった意味がすぐに想像できます。条件式を直接眺めなくても、メソッド名から役割が読み取れるのは大きな利点です。Laravelのモデルを設計するときは、テーブルのカラムだけでなく、「どんなスコープがあると便利か」という視点でも考えてみるとよいでしょう。
さらに、テストコードを書くときにもクエリスコープは役に立ちます。たとえば、「アクティブユーザーだけが対象になっていること」を確認したいとき、activeスコープを通した結果と、あえてスコープを使わない結果を比べることで、期待通りの条件が付いているかを落ち着いて検証できます。こうした小さな確認を積み重ねることで、Laravelアプリの品質も少しずつ安定していきます。
日々の学習の中では、最初から完璧なスコープ設計を目指す必要はありません。「同じようなクエリが続いて書かれていないか」「この条件には名前を付けられないか」といった視点で既存コードを見直していくだけでも、少しずつEloquentのクエリスコープを使う感覚が身についていきます。小さな工夫の積み重ねが、読みやすく変更に強いLaravelアプリへとつながっていきます。
ここで、localスコープとglobalスコープの使い方をシンプルな例でまとめておきます。
// Userモデルにアクティブユーザー用のlocalスコープを定義
class User extends Model
{
public function scopeActive($query)
{
return $query->where('status', 'active');
}
}
// Postモデルに公開済みだけを対象にするglobalスコープを定義
class Post extends Model
{
protected static function booted()
{
static::addGlobalScope('published', function ($builder) {
$builder->where('is_published', true);
});
}
}
実際にクエリを書くときは、次のようにとても自然な形で呼び出せます。
// localスコープでアクティブユーザーだけ取得
$users = User::active()->get();
// globalスコープで公開済み投稿だけ取得(whereを書かなくても自動で条件がつく)
$posts = Post::all();
このように、LaravelのEloquentとクエリスコープを組み合わせるだけで、「何度も書いていた条件」を「意味のある名前を持った部品」に変えられます。結果として、クエリの読みやすさも、アプリ全体の仕様の分かりやすさも高まります。まずは一つ二つ、よく使う条件からスコープを作ってみて、どのくらいコードが整理されるかを体験してみるのがおすすめです。
今後、ページネーションや並び順、期間指定など、少し複雑な検索条件を扱うときも、クエリスコープという考え方を知っていれば、落ち着いてモデル側にルールを集約していくことができます。Eloquentのクエリビルダとスコープを少しずつ組み合わせながら、自分のLaravelアプリに合った読みやすいクエリスタイルを育てていきましょう。焦らず、一つ一つのスコープがどんな意味を持っているのかを確認しながら進めていけば、自然とデータベース設計やビジネスロジックの整理も上手になっていきます。
生徒
「クエリスコープが“検索条件のショートカット”というイメージがようやく分かってきました。同じwhereを何度も書かなくてよいのは、とても助かりそうです。」
先生
「そうですね。まずはUserモデルにactiveのlocalスコープを作ってみたり、Postモデルに公開済みだけを対象にするglobalスコープを試してみると、違いが実感しやすいと思います。」
生徒
「localスコープは必要なときだけ呼び出して、globalスコープは最初から自動で条件が付く、という整理で覚えておけば良さそうですね。大事なルールはglobal、それ以外はlocalという使い分けでしょうか。」
先生
「その考え方で十分です。最初は全部localスコープで書いてみて、“これはアプリ全体の前提条件だな”と思ったものをglobalスコープに昇格させていくやり方もおすすめですよ。だんだんと、自分のプロジェクトに合ったバランスが見えてきます。」
生徒
「プロジェクトの途中からでも、よく使う条件を少しずつスコープに移していけば、既存のコードもきれいになっていきそうですね。怖がらずに、まずは小さなモデルから試してみようと思います。」
先生
「実際にモデルに手を加えてみると、クエリスコープの便利さがさらに体感できます。小さなスコープからで構わないので、少しずつ取り入れていきましょう。」