Laravel 10: Query Scopes

Sandro Jhuliano Cagara
3 min readMar 5, 2023

What are scopes?

A scope is a method in your model that makes it able to add database logic into your model.

Global scopes

Global scopes allow you to add constraints to all queries on a model. This way you make sure that every query on a given model has certain constraints. You can create a global scope by running the following command:

php artisan make:scope UserScope

This will create the UserScope class in the app/Scopes folder. (if no existing folder, laravel will make that for you). Coming back to the example that I described earlier in this post, this is what the UserScope looked like.

<?php

namespace App\Scopes;

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

class UserScope implements Scope
{
public function apply(Builder $builder, Model $model): void
{
$builder->where('active', '1');
}
}

After creating the scope we should add it to our model. This can be done by overwriting the boot method. This results in every query on this model getting WHERE active=’1’ as a constraint.

<?php

namespace App\Models;

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

class User extends Model
{
protected static function boot()
{
parent::boot();
static::addGlobalScope(new UserScope());
}
}

Anonymous Global Scopes

If you have simple scopes that do not need their own class you could define an anonymous global scope using a Closure. This is also done in the boot method of the model. The UserScope class from the previous example could be rewritten to an anonymous global scope:

<?php

namespace App;

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

class User extends Model
{
protected static function boot()
{
parent::boot();
static::addGlobalScope('active', function (Builder $builder) {
$builder->where('active', '1');
});
}
}

Removing a global scope

It is possible to remove a global scope if you have a certain query that you want to execute without the global scope.

There are two ways to remove a global scope, depending on if it is an anonymous global scope or not.

To remove a global scope you can call the withoutGlobalScope method with the class name of the scope as a parameter.

User::withoutGlobalScope('App\Scopes\UserScope')->get();

For an anonymous global scope, you can call the same method, but with the name of the anonymous global scope as the first parameter.

User::withoutGlobalScope('active')->get();

Removing multiple global scopes is possible as well using the withoutGlobalScopes method.

Local scopes

Local scopes make it able to define standard sets of constraints that are easily reusable. This comes in handy if we only want to get male users, for example.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
public function scopeIsMale($query)
{
return $query->where('is_male', 'm');
}
}

After defining one or more local scopes they could be used by calling the scope method on the model. Chaining of scope methods is possible.

$user = User::isMale()->orderBy('created_at')->get();

Dynamic local scopes

Dynamic local scopes work in exactly the same way as a normal local scope. The only difference is that a dynamic local scope accepts parameters.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
public function scopeIsMale($query, $isMale)
{
return $query->where('is_male', $isMale);
}
}

You can pass the parameter when calling the scope:

$user = User::IsMale('m')->orderBy('created_at')->get();

Please feel free to leave a comment if you have any feedback, or questions or want me to write about another Laravel-related topic.

--

--

Sandro Jhuliano Cagara
Sandro Jhuliano Cagara

Written by Sandro Jhuliano Cagara

Senior Full Stack Developer, Graphic Designer, Programmer and Gamer

No responses yet