Understanding Scopes in Eloquent (with examples)

Updated: January 16, 2024 By: Guest Contributor Post a comment

Introduction

Laravel’s Eloquent ORM provides a beautiful, simple ActiveRecord implementation for working with your database. One of its less discussed, yet powerful features, are the scopes. Scopes allow you to encapsulate part of query logic into a method, which can then be re-used throughout your application. In this tutorial, we will dive deep into the concept of scopes in Eloquent, providing clear examples to solidify your understanding. You’ll learn about local scopes, global scopes, and how to apply them in your Laravel projects.

What Are Scopes?

In Eloquent, scopes are methods that you can define on your Eloquent model classes which are used to add constraints to queries for that model.

Local Scopes

Local scopes allow you to define common sets of query constraints which you may easily re-use throughout your application. For example:

class Post extends Model {
    /**
     * Scope a query to only include active posts.
     */
    public function scopeActive($query) {
        return $query->where('active', 1);
    }
}

Now, you can utilize the scope via a method on an instance of the Eloquent model:

$activePosts = Post::active()->get();

Global Scopes

Global scopes allow you to add constraints to all queries for a given model. Laravel’s built-in soft delete functionality is an example of a global scope. A custom global scope looks like this:

use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class ActiveScope implements Scope {
    public function apply(Builder $builder, Model $model) 
    {
        $builder->where('active', '=', 1);
    }
}

Now, let’s apply our custom global scope to a model:

class Post extends Model {
    protected static function booted() {
        static::addGlobalScope(new ActiveScope);
    }
}

With the scope applied, any query on the Post model will automatically apply the active constraint.

Using Scopes in the Real World

Let’s illustrate with an example where we want to filter blog posts that are active and from a particular category.

class Post extends Model {
    /**
     * Scope to filter active posts.
     */
    public function scopeActive($query) {
        return $query->where('active', true);
    }

    /**
     * Scope to filter posts by a given category.
     */
    public function scopeOfCategory($query, $category) {
        return $query->where('category_id', $category->id);
    }
}

To retrieve all active posts from a specific category you can chain your scopes together:

$category = Category::find(1);
$activePostsInCategory = Post::active()->ofCategory($category)->get();

Dynamic Scopes

In some cases, you may want your scope to accept parameters. Let’s create a dynamic scope that retrieves posts from the past ‘n’ days:

class Post extends Model {
    /**
     * Scope to retrieve posts from the last 'n' days.
     */
    public function scopeFromLastDays($query, $days) {
        return $query->where('created_at', '>=', now()->subDays($days));
    }
}

To retrieve posts from the last 10 days, call the scope and pass in the number of days:

$recentPosts = Post::fromLastDays(10)->get();

Advanced Example: Composing Multiple Scopes

Let’s take a complex example where we compose multiple scopes to implement a feature that filters and sorts blog posts based on user input:

class Post extends Model {
    ...
    public function scopeSearch($query, $searchTerm) {
        return $query->where('title', 'like', "%{$searchTerm}%");
    }

    public function scopeSort($query, $direction = 'asc') {
        return $query->orderBy('created_at', $direction);
    }
}

$posts = Post::active()->search('laravel')->sort('desc')->get();

This chain of scopes will return active posts with ‘laravel’ in their title, sorted in descending order by their creation date.

Conclusion

The scope features in Eloquent are a powerful paradigm for querying the database in a clean and re-usable way. They shine in complex applications, adding a level of abstraction that makes managing database queries a breeze.