Applying common constraints with global scopes in Laravel
Laravel devs, here's a gem for you: π
Use global scopes to apply common constraints to your queries. Global scopes allow you to encapsulate query logic that applies to all queries for a given model, making your query logic reusable and maintainable. In this blog post, we'll explore how to use global scopes and provide a real-life example to demonstrate their benefits.
Why Use Global Scopes?
- Consistency: Apply consistent query constraints across all queries for a model.
- Reusability: Encapsulate commonly used query logic for reuse across multiple queries.
- Maintainability: Centralize query logic, making it easier to maintain and update.
Step-by-Step Implementation
Let's walk through the process of setting up and using global scopes in a Laravel application.
Step 1: Setting Up the Model
Ensure you have a model to work with. In this example, we'll use a Post
model and create a global scope to only show published posts.
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
// Boot method to add the global scope
protected static function boot()
{
parent::boot();
static::addGlobalScope('published', function (Builder $builder) {
$builder->where('is_published', true);
});
}
}
Step 2: Creating the Controller Method
Create a controller method that retrieves posts. The global scope will automatically filter the posts to only show published ones.
// app/Http/Controllers/PostController.php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function index()
{
$posts = Post::all();
return view('posts.index', ['posts' => $posts]);
}
}
Step 3: Setting Up the Route
Define a route that points to the controller method.
// routes/web.php
use App\Http\Controllers\PostController;
Route::get('/posts', [PostController::class, 'index']);
Step 4: Creating the View
Create a view to display the posts.
<!-- resources/views/posts/index.blade.php -->
<!DOCTYPE html>
<html>
<head>
<title>Posts</title>
</head>
<body>
<h1>Published Posts</h1>
<ul>
@foreach ($posts as $post)
<li>{{ $post->title }}</li>
@endforeach
</ul>
</body>
</html>
Example: Filtering Published Posts
In a real-life scenario, you might need to ensure that only published posts are shown to users. Using a global scope, you can encapsulate this logic and apply it consistently across all queries for the Post
model.
Creating Dummy Data
Let's generate some dummy data to work with.
php artisan tinker
// Inside Tinker
Post::factory()->create(['title' => 'Published Post 2', 'is_published' => true]);
Post::factory()->create(['title' => 'Published Post 3', 'is_published' => true]);
This command will generate some published and unpublished posts in your database.
Viewing the Published Posts
Access the /posts
route in your browser to see the list of published posts.
Advanced Example: Combining Multiple Scopes
You can also combine multiple global scopes for more complex filtering logic. For example, if you want to filter posts by both published status and a specific user, you can define another scope.
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected static function boot()
{
parent::boot();
// Scope to filter by published status
static::addGlobalScope('published', function (Builder $builder) {
$builder->where('is_published', true);
});
// Scope to filter by user
static::addGlobalScope('byUser', function (Builder $builder) {
$builder->where('user_id', auth()->id());
});
}
}
In this example, the Post
model will only return posts that are both published and belong to the authenticated user.
Conclusion
Using global scopes in Laravel allows you to apply common query constraints consistently across all queries for a given model. This approach improves the reusability, maintainability, and readability of your code by centralizing query logic. By following the steps outlined in this blog post, you can leverage the power of global scopes to ensure uniform data access rules and simplify your query logic.
Found this helpful?
If this guide was helpful to you, subscribe to my daily newsletter and give me a follow on X/Twitter. It helps a lot!