Laravel query scopes
In Laravel, query scopes allow you to define common query logic in a reusable way, enabling you to apply these conditions easily to your Eloquent queries. This feature helps keep your code clean and reduces redundancy, especially when you find yourself writing the same query conditions multiple times throughout your application.
Types of Query Scopes
There are two main types of query scopes in Laravel: local scopes and global scopes.
1. Local Scopes
Local scopes are methods defined in your Eloquent model that can be called when querying that model. They allow you to encapsulate a set of conditions into a single method.
Defining a Local Scope:
To define a local scope, you prefix a method with scope
in your Eloquent model. Here’s an example using a Post
model:
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
// Define a local scope to filter published posts
public function scopePublished(Builder $query)
{
return $query->where('is_published', true);
}
}
Using a Local Scope:
You can use the defined local scope in your queries like this:
// Get all published posts
$publishedPosts = Post::published()->get();
You can also chain local scopes:
// Get published posts with a specific category
$categoryPosts = Post::published()->where('category_id', 1)->get();
2. Global Scopes
Global scopes are applied automatically to all queries for a given model. This is useful when you want to apply certain conditions universally (e.g., soft deleting, user-specific data).
Defining a Global Scope:
To create a global scope, you need to implement the Scope
interface or extend the Builder
class. Here’s an example that restricts users to only see their own posts:
namespace App\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class UserScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('user_id', auth()->id());
}
}
Then, you can apply this global scope in your model:
namespace App\Models;
use App\Scopes\UserScope;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
// Apply the global scope
protected static function booted()
{
static::addGlobalScope(new UserScope);
}
}
With this global scope in place, all queries for the Post
model will automatically include the condition to filter by the authenticated user's ID.
Removing Global Scopes
If you need to bypass a global scope for a specific query, you can use the withoutGlobalScope
method:
// Get all posts, ignoring the global scope
$allPosts = Post::withoutGlobalScope(UserScope::class)->get();
Summary
In summary, query scopes in Laravel are a powerful feature that helps you:
- Encapsulate common query logic: Define reusable query conditions in your models, improving code readability and maintainability.
- Control visibility: Use global scopes to apply conditions to all queries for a model automatically.
- Chain queries easily: Combine local scopes with other query methods to build complex queries without repeating code.
Using query scopes is an effective way to write clean and expressive code in your Laravel applications, making your Eloquent queries more manageable and flexible.