【Laravel】ローカルスコープとグローバルスコープの使い方|active(), popular(), ofType()などの関数が見つからない時の確認方法

laravel-prograshi(プロぐらし) Laravel
記事内に広告が含まれていることがあります。

Larevelでデバッグしている時にDBからのデータ取得でactive()やpopular()という関数が記述してあるのに、調べてもLaravel公式のメソッドやヘルパーとしては定義されていない。

アプリケーションのファイル全てで active() や function active() を検索しても、そのような名前の関数はどこにも定義されていない、、そんな時の対処法です。


対処法

最初に結論から言うと、その関数は scopeActivescopePopularというように、前置詞にscopeをつけた状態で定義されています。

基本的には同じファイルに定義されています。

例えば、active()という関数が使われている場合は、以下のような関数が定義されています。

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

この関数の中身は、Eloquentモデルのwhere句を使って、activeカラムで値が1のデータのみを絞り込む処理です。

あれこの関数どこにも定義されてないけど??と思ったら、scopeをつけて検索してみると見つかるかもしれません。

ローカルスコープ

関数名の前にscopeをつけて定義した関数をローカルスコープと言います。

Laravelに用意されている便利な機能の一つで、何度も使う関数を定義することができます。

ローカルスコープの使い方

ローカルスコープの使い方はとても簡単です。以下の2つの手順を踏むだけです。

  1. モデルファイルの中に「scope + 関数名」 の関数を定義する。(関数名は冒頭大文字)
  2. 呼び出す。(scopeなし、小文字)

▼(1)関数の定義

public function scope関数名($querry) {
        return $query->処理;
    }
point

引数には関数の前に指定したテーブルのデータが入ります。

例えば、App\User::関数名() であれば、Userの全てのデータが引数(上記の場合は$querry)に渡されます。


▼(2)呼び出し

モデル::関数名()


実例:popular

モデルファイルの中に「scope + 関数名」 の関数を定義する

例えば、voteというカラムで値が100以上の行のみを抜き出すpopularという関数を定義すると次のようになります。

    public function scopePopular($query)
    {
        return $query->where('votes', '>=', 100);
    }
point

where句が使われている例が多いですが、orderByなどwhere句以外も使うことができます。


呼び出す

呼び出す時はscopeをつけずに、popular()のみで呼び出します。

App\User::popular()->get();

これは次の処理と同じです。

App\User::where('votes', '>=', 100)->get();
point

モデルからデータを取得する時は、絞り込んだ後にget()をつける必要があります。

get()メソッドを使うことでLaravelで扱えるデータ(stdClassオブジェクトのインスタンス)になります。

複数数の関数をつなげる

ローカルスコープで定義した関数は他のメソッドと同様にメソッドチェーンでつなぐことができます。

$users = App\User::popular()->active()->orderBy('created_at')->get();


動的なローカルスコープ

任意の引数を渡して動的にレコードの絞り込みをすることもできます。

第1引数には前の処理で取得したデータが入るので、第2引数以降で渡したい引数を定義するだけです。

    public function scopeOfType($query, $type)
    {
        return $query->where('type', $type);
    }

上記の処理は、typeという名前のカラムから、変数$typeで渡した値と一致するデータを持つ行のみを抽出する処理になります。


(参考)Laravel公式 ローカルスコープ


グローバルスコープ

ローカルスコープの他にグローバルスコープという機能も用意されています。

ローカルスコープは使いたい時に関数として呼び出すのに対し、グローバルスコープは対象のモデルからデータを取得する時に必ず実行する処理になります。

ユーザーログインを必要とする場合など、必ず対象のユーザーidでデータを絞り込む場合などに使えます。


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

グローバルスコープの使い方は簡単でmodelファイルにに決まった書き方で記述するのみです。

指定してする必要があるのは2点のみです。

  1. グローバルスコープ名(addGlobalScopeの第1引数)
  2. 実行したい処理
namespace App\Models;

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

class モデル名 extends Model
{

    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('グローバルスコープ名', function (Builder $builder) {
            $builder->実行したい処理;
        });
    }
}
point

グローバルスコープ名は、特定の処理で作成したグローバルスコープを外す時に使います(後述)。

小文字とし、複数単語をつなげる場合はスネークケースで記述します(例:’user_id’)


グローバルスコープの実例

例えば、Userモデルでageカラムの値が20以上のユーザーのみを必ず抜き出す場合は以下のようになります。

namespace App\Models;

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

class User extends Model
{

    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('age', function (Builder $builder) {
            $builder->where('age', '>', 200);
        });
    }
}

これで、Uesrモデル経由でデータを取得する際にwhere('age', '>', 200)が必ず実行されるようになります。


グローバルスコープを部分的に外す

特定の処理でグローバルスコープを外すことも簡単にできます。

モデル名::withoutGlobalScope('グローバルスコープ名')->get();

グローバルスコープの実例で示したageというグローバルスコープを外したい場合は次のようにします。

モデル名::withoutGlobalScope('age')->get();

これでグローバルスコープで指定したwhere('age', '>', 200)が実行されなくなります。

タイトルとURLをコピーしました