Laravel Scopes

Bayram EKER
3 min readSep 7, 2022

--

Global Scopes

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

<?phpnamespace 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:

<?phpnamespace 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 scopes

Local scopes make it able to define common sets of constraints that are easily reusable. This comes in handy if we only want to get the published messages, for example.

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.

$messages = Message::published()->orderBy('created_at')->get();

You do not need to add the scope prefix when calling the scope method

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.

You can pass the parameter when calling the scope:

$messages = Message::isHighlighted(true)->orderBy('created_at')->get();

Application:

Step 1

Start with the model. This means that you need to have a search form in which you want to make search requests in your database.

So am going to use my application to explain how to implement the scope filters in laravel. Update the model with this code. For example, mine is a blog website made purely in laravel.

model:

public function scopeFilter($query, array $filters) {
if($filters['search'] ?? false) {
$query->where('title', 'like', '%' . request('search') . '%')
->orWhere('slug', 'like', '%' . request('search') . '%')
->orWhere('details', 'like', '%' . request('search') . '%');
}
}

Step 2

Once this is done you will need to update the controller that’s associated with the model. In my case, this is the one.

PagesController.php

class PagesController extends Controller
{
public function index()
{
$posts = Post::inRandomOrder()->where('post_type', 'post')->where('is_published', '1')->filter(request(['search']))->paginate(3);
return view('pages.index', compact('posts'));
}

Take note of where I have placed the

filter(request(['search']))

that’s where you will update your function with.

Step 3

The next thing is to have a search form like this… this code is from my nav.blade.php

Nav.blade.php

<form action = "/" method="get" class="form-inline">
{{csrf_field()}}
<div class="input-group search-box">
<input type="text" name="search" class="form-control" placeholder="Type a Query..." aria-label="Search for..." id="q">
<span class="input-group-btn">
<button class="btn btn-secondary" type="button"><i class="ion-search"></i></button>
</span>
</div>
</form>

From the above search form, action is set to"/"which means when someone types a query he/she will be redirected back to the home page with the relevant result. We are done!

--

--

No responses yet