Laravel: Simplifying Query Scopes for Cleaner Models

By Maulik Paghdal

15 Dec, 2024

Laravel: Simplifying Query Scopes for Cleaner Models

Introduction

In Laravel, managing Eloquent queries in a clean and reusable way is critical for maintaining readable and efficient code. Query scopes offer a simple yet powerful solution for encapsulating commonly used query logic into reusable methods within your models.

This blog will explore the concept of query scopes, including local and global scopes, with practical examples to simplify your Laravel models.

What Are Query Scopes?

Query scopes in Laravel allow you to encapsulate query logic within your Eloquent models, promoting reusability and reducing duplication.

  1. Local Scopes: Define reusable query logic that can be called on a model instance.
  2. Global Scopes: Automatically apply query logic to all queries for a given model.

Local Scopes in Laravel

A local scope is a custom method defined within an Eloquent model to filter queries.

Defining a Local Scope

Prefix the method name with scope and define it in your model:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    public function scopePublished($query)
    {
        return $query->where('status', 'published');
    }

    public function scopeRecent($query, $days = 7)
    {
        return $query->where('created_at', '>=', now()->subDays($days));
    }
}

Using Local Scopes

Call the scope methods like this:

use App\Models\Post;

// Get all published posts
$publishedPosts = Post::published()->get();

// Get recent posts from the last 30 days
$recentPosts = Post::recent(30)->get();

Global Scopes in Laravel

A global scope automatically applies conditions to all queries for a specific model.

Defining a Global Scope

Create a custom class that implements Illuminate\Database\Eloquent\Scope:

namespace App\Scopes;

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

class PublishedScope implements Scope
{
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('status', 'published');
    }
}

Applying a Global Scope

In the model, apply the scope using the booted method:

namespace App\Models;

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

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

Now, all queries for Post will include the where('status', 'published') condition:

use App\Models\Post;

// Get all posts (only published ones will be retrieved)
$posts = Post::all();

Combining Scopes

You can combine multiple scopes to create complex queries:

use App\Models\Post;

// Get recent published posts
$recentPublishedPosts = Post::published()->recent(30)->get();

Benefits of Using Query Scopes

  1. Code Reusability: Write once, reuse across your application.
  2. Cleaner Models: Encapsulate query logic within the model, keeping controllers and services clean.
  3. Consistency: Apply consistent query logic across your application.

Best Practices for Query Scopes

  1. Use Local Scopes for Flexibility: Local scopes are ideal for reusable logic that is not always required.
  2. Be Cautious with Global Scopes: Use global scopes only when the logic applies universally to a model.
  3. Name Scopes Meaningfully: Use clear, descriptive names for your scope methods to improve code readability.
  4. Avoid Overloading Scopes: Keep your scopes focused on a single responsibility to avoid complexity.

Conclusion

Query scopes are an essential tool in Laravel for writing clean, reusable, and maintainable Eloquent queries. Local scopes simplify reusable query logic, while global scopes enforce model-wide constraints. By leveraging both types of scopes wisely, you can enhance the readability and efficiency of your Laravel application.

Start incorporating query scopes into your Laravel projects today to keep your codebase clean and efficient!