更新:2024/12/04

【Laravel】グローバルスコープの使い方と意味について

はるか
はるか
グローバルスコープ。便利。
ふゅか
ふゅか
毎回同じ条件を書かなくても済むもんね!

1. グローバルスコープとは

Laravelグローバルスコープは、クエリに自動的に条件を適用する仕組みです。たとえば、is_deleted フラグがfalseのデータだけを取得したい場合や、特定のユーザーに関連するデータのみを常にフィルタリングしたい場合に便利です。

1.1. グローバルスコープの基本

通常、Eloquentを使用してクエリを作成するとき、必要に応じて条件を追加します。以下の例を見てください。

// 条件を指定してデータを取得
$users = User::where('is_active', true)->get();

しかし、どのクエリでも同じ条件(ここではis_activeがtrue)を適用したい場合、毎回whereを記述するのは手間ですし、書き忘れる可能性もあります。これを防ぐのがグローバルスコープの役割です。

グローバルスコープを設定することで、モデルに対するすべてのクエリに指定した条件が自動で適用されます。

1.2. Laravelの動作環境

Laravelを利用する環境は基本的に、次の通りです。

  • Laravel Framework 10.48.25
  • php 8.1

2. グローバルスコープの実装方法

ここでは、記事の公開状態を管理する例を使って、グローバルスコープの設定手順を説明します。

2.1. Articleモデルとデータ

まず、articlesテーブルが以下のような構造を持っていると仮定します。

id title content status created_at updated_at
1 初めての記事 サンプル本文 draft 2024-12-01 10:00:00 2024-12-01 10:00:00
2 非公開の記事 非公開本文 draft 2024-12-02 12:00:00 2024-12-02 12:00:00
3 公開済みの記事 記事本文 published 2024-12-03 15:00:00 2024-12-03 15:00:00

グローバルスコープを利用して、is_publisheddraftのデータのみをデフォルトで取得するようにします。例えば、次のようにデータを表示したとします。

2.2. スコープの設定

2.2.1. スコープクラスを作成

グローバルスコープを適用するには、専用のスコープクラスを作成します。以下のコマンドを実行してスコープクラスを作成しましょう。

php artisan make:scope PublishedScope

これにより、App\Models\Scopesディレクトリ内にPublishedScopeという名前のスコープクラスが作成されます。作成されたスコープクラスに条件を追加します。

namespace App\Models\Scopes;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

class PublishedScope implements Scope
{
    public function apply(Builder $builder, Model $model)
    {
        // 非公開済みの記事のみを取得する条件
        $builder->where('status', "draft");
    }
}
はるか
はるか
スコープクラス作成。php artisan make:scope。

2.2.2. Articleモデルに適用

次に、Articleモデルにこのスコープを適用します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\Scopes\PublishedScope;

class Article extends Model
{
    protected static function booted()
    {
        // スコープを適用
        static::addGlobalScope(new PublishedScope);
    }
}

これで、Article::all()Article::where()を使用すると、status = "draft"の条件が自動的に適用されます。ここで使用したbooted メソッドは、Eloquentモデルで初期設定を行うための静的メソッドです。このメソッドは、モデルが初めて「ブート」されるときに呼び出されます。ここで、モデルにグローバルスコープを追加したり、特定のイベントリスナーを登録するなど、モデル全体に適用される処理を定義できます。

ふゅか
ふゅか
あとはモデルのbootedメソッドにスコープを適用すればOKだよ!これで、モデルに対するすべてのクエリに自動的に条件がつく!

2.3. コントローラーでデータ取得

次に、コントローラーを作成してデータを取得します。

php artisan make:controller ArticleController

以下のようにデータを取得してビューに渡します。

namespace App\Http\Controllers;

use App\Models\Article;

class ArticleController extends Controller
{
    public function index()
    {
        // グローバルスコープにより公開済みの記事だけを取得
        $articles = Article::orderBy('created_at', 'desc')->get();

        return view('articles.index', compact('articles'));
    }
}

2.4. 実行結果

ブラウザでこのページを表示すると、以下のようなテーブルが表示されます。

非公開の記事のみ表示することができました。

2.5. スコープの一時無効化

必要に応じてスコープを無効化して全データを取得する場合、以下を使用します。

use App\Models\Scopes\PublishedScope;

$articles = Article::withoutGlobalScope(PublishedScope::class)->get();

PR