Laravel8のMODELのグローバルスコープ・ローカルスコープを使用する

シェアする

この記事では、Laravelのモデルにおけるグローバルスコープについて紹介します。なぜグローバルスコープが必要なのかを理解するために、1つの例を挙げて紹介ます。例えば、ユーザーモデルがあり、テーブルにactiveフラグがあるとします。
Userモデルに対してクエリを実行するたびに、active Where句がクエリに追加し、activeでないユーザーに対してクエリを実行しないようにしたいという機会があった際に、グローバルスコープとは、基本的には、与えられたモデルを介して実行されるすべてのクエリの上にクエリフィルタを追加することができる流クラスのことをいいます。

この記事では、以下のトピックを扱います。この記事を最後まで読んでいただけると内容を理解しやすいと思います。

・グローバルスコープの作成
・グローバルスコープをモデルに登録する
・クエリからグローバルスコープを削除する

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

app/Scopes/HasActiveScope.phpファイルの下に、以下の内容で新しいクラスを作成しましょう。

<?php

namespace App\Scopes;

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

class HasActiveScope implements Scope
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('active', true);
    }
}

laravelがこのスコープクラスを呼び出すたびにapplyメソッドが呼び出され、このメソッドで定義された条件がeloquentクエリの上に追加されます。

グローバルスコープを適用する

モデルにグローバルスコープを割り当てるには、モデルのbootedメソッドをオーバーライドして、モデルのaddGlobalScopeメソッドを呼び出す必要があります。addGlobalScope メソッドは、唯一の引数としてあなたのスコープのインスタンスを受け取ります。

<?php

namespace App\Models;

use App\Scopes\HasActiveScope;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The "booted" method of the model.
     *
     * @return void
     */
    protected static function booted()
    {
        // using seperate scope class
        static::addGlobalScope(new HasActiveScope);

        // 無名関数を使っても同じことができます。
        // 無名関数を使って別のスコープを追加しています。
        static::addGlobalScope('delete', function (Builder $builder) {
            $builder->where('deleted', false);
        });
    }
}

グローバルスコープの使い方は?

グローバルスコープがbootedメソッドに追加されると、その使用について他に何かする必要はありません。これらのグローバルスコープは、自動的にモデルクエリに適用されます。例を紹介します。

# fetching all active and non-deleted users
$users = User::all();

# above query will result in following sql
select * from `users` where `active` = 1 and `deleted` = 0

クエリからグローバルスコープを削除する

場合によっては、グローバル・フィルタを適用させたくないこともあります。たとえば、アクティブかどうかにかかわらず、すべてのユーザーを取得したい場合です。このような場合、以下の例で適用されたスコープを削除することができます。

# fetch all users weather they are active or not
$users = User::withoutGlobalScope(new HasActiveScope)->all();

# fetch active users weather they are deleted or not
User::withoutGlobalScope('delete')->all();

Laravelのモデルにおけるローカルスコープ

例えば、上記のような方法が好きではなく、グローバルスコープを適用するのではなく、必要なときにローカルスコープを適用したい場合、Laravelはそれが可能です。

ローカルスコープは、Scopeキーワードをプレフィックスとして使用します。この場合、グローバルスコープを定義する代わりに、以下のようにローカルスコープをLaravelのモデルに追加することができます。

<?php

namespace App\Models;

use App\Scopes\HasActiveScope;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function scopeActive($query)
    {
        return $query->where('active', 1);
    }

    public function scopeDelete($query)
    {
        return $query->where('delete', 0);
    }
}

laravelでローカルモデルのスコープを使用する方法?

ローカルスコープは、laravelでは使いやすく、必要に応じて使用することができます。以下の例を見てみましょう。

# apply active local scope to following query
$users = User::active()->orderBy('created_at')->get();

# apply delete local scope to following query
$users = User::delete()->orderBy('created_at')->get();

Laravelのモデルにおける動的スコープ

時には、ローカルスコープに追加のパラメータを渡したい場合があります。そんなときは、ローカルスコープに動的なパラメータを渡せば、それが動的なスコープとして機能するようになります。

下記に例を示します。

<?php

namespace App\Models;

use App\Scopes\HasActiveScope;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function scopeActive($query)
    {
        return $query->where('active', 1);
    }

    public function scopeDelete($query)
    {
        return $query->where('delete', 0);
    }

    public function scopeWithRole($query, $role)
    {
        return $query->where('role', $role);
    }
}​

Laravelモデルで動的スコープを使用する方法?

Laravelでダイナミックモデルスコープを使用するには、以下の例を参考にしてください。

# find active users with role admin
$users = User::active()->withRole('admin')->all();

今回の記事ではLaravelでのモデルのグローバルスコープ・ローカルスコープについて紹介ました。
参考になると幸いです。

シェアする

フォローする