l2t

Laravel8 Global Scope in Model

How to define global model scope in Laravel 8

In this tutorial we would learn about global scopes in Laravel model. Let's take one example to understand why we need global scope. Let say that you have a user model and it has active flag in your table.

Everytime you run any query on User model you want to make sure active where clause is added to our query so that we do not run this query for non-active users.

Global scope is basically a class that allows you to add query filter on top of your all queries that runs through your given model. In this tutorial we would cover following topics:

  • Create Global Scope
  • Register Scope in Model
  • Remove Scopes From Query

Writing Global Scopes

Let's create a new class under app/Scopes/HasActiveScope.php file with following contents:

<?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);
    }
}

Whenever laravel calls this scope class it will call apply method and add conditions defined in this method on top of your eloquent query. We would learn how that works later in this tutorial.

Applying Global Scopes

To assign a global scope to a model, you should override the model's booted method and invoke the model's addGlobalScope method. The addGlobalScope method accepts an instance of your scope as its only argument:

<?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);

        // you can do the same thing using anonymous function
        // let's add another scope using anonymous function
        static::addGlobalScope('delete', function (Builder $builder) {
            $builder->where('deleted', false);
        });
    }
}

How to use global scope?

Once your global scopes are added into booted function you do not need to worry about using them. These global scope are automatically applied to your model queries. Let's check out some examples:

# 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

Remove Scope From Query

In some cases, you might not want your global filter to apply. For example, if you want to fetch all users weather they are active or not. In that case you can remove your applied scope using following example:

# 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();

Local Scope in Laravel Model

Let say you do not like above approach and you do not prefer to apply global scope rather you want to apply local scope whenever necessary surely you can do that in Laravel.

Local scopes are prefixed using Scope keyword. In this case instead of defining global scope you can add local scope in your Laravel model like following:

<?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);
    }
}

How to apply local model scope in laravel?

Local scopes are easy to use in laravel you can use them as you need them. Let's take following example.

# 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();

Dynamic Scopes in Laravel Model

Sometime you may want to pass additional parameter to your local scope. In that case we can pass dynamic parameter to our local scope and it will act as dynamic scope.

Let's take following example:

<?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);
    }
}

How to use dynamic scopes in Laravel model?

In order to use dynamic model scope in Laravel you can check out following example:

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

Hope you like this tutorial do share and like my tutorials and motivate me to write some awesome tutorials like this, Thank you.