{ Laravel Scopes }

Scopes in Laravel aren’t always easy to pick up on when you’re starting out – they use “magic” methods that you can’t map directly to a specific function. This is also what makes them so powerful. They help with code reusability, so you can setup a query in one spot and reference it wherever it’s needed for a particular model. The examples shown here are local scopes. They act on a specific model and not all of them, which is where global scopes come in handy.

Supposing I have a User and a Role model, I can add something like this to User model file (By default, \App\User.php):

public function scopeForRoles( $query ) {
   return $query->with( 'roles' )->whereHas( 'roles', function( $role ) {
      return $role->where( 'name', 'administrator' );
   });
}

This gives me a helper method to grab a user and eager load their roles. In this case I’m making sure to only return users who have a role and additionally filtering it to only give me users with the “administrator” role. You can add more parameters to filter on, but the primary one is $query, which is equivalent to User::query().


->whereHas( 'roles', function( $role ) {

whereHas takes two parameters – a key and value pair or a callback function. The ability to use a callable sets it apart from the simple where.

return $role->where( 'name', 'administrator' );

The callback acts on $role like the built-in array_filter function. It only returns when the given expression is true.


Here’s the “magic” part, you can call it like this:

$users = User::forRoles()->get( ['id', 'name' ] );

It becomes a pseudo-static method on the model by reducing scopeForRoles to forRoles. Remove “scope” and change the case to the traditional getter style. I’m completing the call here by invoking get with an array of attributes. These are optional, but supposing I’m setting up a select element for a form I just want the id and name attributes.

NOTE: I’m using the plural “roles” because it’s common for a user to have one or more possible roles. It’s a one-to-many type relationship, hence with( ‘roles’ ) and not with( ‘role’ ) .