Problem: You need to build queries with optional conditions based on user input, but using multiple if statements makes your code messy and hard to read.
Solution:
// Basic when() usage
$users = User::query()
->when($request->status, function ($query, $status) {
return $query->where('status', $status);
})
->when($request->role, function ($query, $role) {
return $query->where('role', $role);
})
->get();
// With default value (else condition)
$posts = Post::query()
->when($request->category_id,
function ($query, $categoryId) {
return $query->where('category_id', $categoryId);
},
function ($query) {
return $query->whereNull('category_id');
}
)
->get();
// Complex conditions
$products = Product::query()
->when($request->search, function ($query, $search) {
$query->where(function ($query) use ($search) {
$query->where('name', 'like', "%{$search}%")
->orWhere('description', 'like', "%{$search}%");
});
})
->when($request->min_price && $request->max_price, function ($query) use ($request) {
return $query->whereBetween('price', [$request->min_price, $request->max_price]);
})
->when($request->sort === 'price', function ($query) use ($request) {
return $query->orderBy('price', $request->direction ?? 'asc');
})
->paginate(20);
// Works with relationships
$users = User::with(['posts' => function ($query) use ($request) {
$query->when($request->published_only, function ($query) {
return $query->where('published', true);
});
}])->get();
Why it works: when()
only executes the callback if the first parameter is truthy. This eliminates the need for if statements around query building. The optional second callback runs when the condition is falsy, perfect for default behaviors.
Pro tip: Chain multiple when()
calls for clean, readable query building. Great for search filters and API endpoints with optional parameters.
Share this article
Add Comment
No comments yet. Be the first to comment!