Eloquent Query Scopes & Custom Builders – Optimizing Database Queries

Eloquent Query Scopes & Custom Builders – Optimizing Database Queries

Efficient database querying is crucial for performance in Laravel applications, especially as your project scales. Laravel's Eloquent Query Scopes and Custom Builders provide a way to reuse query logic, making your code more modular and maintainable. In this blog, we’ll explore how to optimize database queries using these techniques.


1. Understanding Query Scopes in Laravel

Eloquent Query Scopes allow you to define common query constraints once and reuse them throughout your application.

1.1 Defining a Local Scope

A local scope is defined within an Eloquent model and used for reusable query conditions.

Example: Filtering Active Users

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }
}        

1.2 Using a Local Scope in Queries

Now, we can filter active users easily:

$activeUsers = User::active()->get();        

You can also chain scopes for more refined queries:

$verifiedUsers = User::active()->whereNotNull('email_verified_at')->get();        

1.3 Defining a Scope with Parameters

Scopes can also accept parameters:

public function scopeRole($query, $role)
{
    return $query->where('role', $role);
}        

Usage:

$admins = User::role('admin')->get();        

2. Using Global Scopes

Unlike local scopes, Global Scopes are automatically applied to all queries for a model.

2.1 Creating a Global Scope

Define a class implementing Scope:

namespace App\Scopes;

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

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

2.2 Applying a Global Scope to a Model

Register the scope in your model’s booted() method:

namespace App\Models;

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

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

Now, all User queries automatically include where('status', 'active').

To disable a global scope:

$users = User::withoutGlobalScope(ActiveScope::class)->get();        

3. Creating a Custom Builder Class

For complex queries, a Custom Builder Class helps maintain cleaner code.

3.1 Creating the Custom Builder

Create a builder class in app/Builders/UserBuilder.php:

namespace App\Builders;

use Illuminate\Database\Eloquent\Builder;

class UserBuilder extends Builder
{
    public function active()
    {
        return $this->where('status', 'active');
    }

    public function role($role)
    {
        return $this->where('role', $role);
    }
}        

3.2 Using the Custom Builder in a Model

Modify the User model to return our custom builder:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Builders\UserBuilder;

class User extends Model
{
    public function newEloquentBuilder($query): UserBuilder
    {
        return new UserBuilder($query);
    }
}        

3.3 Using the Custom Builder in Queries

$users = User::query()->active()->role('admin')->get();        

By encapsulating complex logic within a dedicated builder class, queries remain clean, reusable, and more maintainable.


4. When to Use Scopes vs. Custom Builders?


Article content

Use query scopes for reusable filtering conditions and custom builders when dealing with complex queries that require advanced chaining logic.


5. Conclusion

Optimizing database queries is essential for scalable Laravel applications. Query Scopes allow for concise and reusable query logic, while Custom Builders provide a structured way to handle complex queries. By mastering these techniques, you can write cleaner, more efficient code that enhances performance and maintainability.

Try implementing query scopes and custom builders in your next Laravel project and experience the difference! 🚀

To view or add a comment, sign in

More articles by Vignesh Jothi

Insights from the community

Others also viewed

Explore topics