PHP
Dynamic Filtering with Eloquent Local Scopes
Implement flexible and reusable query filters in Laravel Eloquent using local scopes, allowing dynamic search criteria for models based on various inputs.
// app/Models/Product.php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
// Define a local scope for category filtering
public function scopeCategory(Builder $query, string $categorySlug): void
{
$query->whereHas('category', function ($q) use ($categorySlug) {
$q->where('slug', $categorySlug);
});
}
// Define a local scope for price range filtering
public function scopePriceRange(Builder $query, float $minPrice, float $maxPrice): void
{
$query->whereBetween('price', [$minPrice, $maxPrice]);
}
// Define a local scope for search term
public function scopeSearch(Builder $query, string $searchTerm): void
{
$query->where('name', 'like', '%' . $searchTerm . '%')
->orWhere('description', 'like', '%' . $searchTerm . '%');
}
}
// app/Http/Controllers/ProductController.php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
public function index(Request $request)
{
$products = Product::query();
if ($request->has('category')) {
$products->category($request->input('category'));
}
if ($request->has(['min_price', 'max_price'])) {
$products->priceRange($request->input('min_price'), $request->input('max_price'));
}
if ($request->has('search')) {
$products->search($request->input('search'));
}
// Add ordering, pagination, etc.
$products = $products->orderBy('created_at', 'desc')->paginate(10);
return view('products.index', compact('products'));
}
}
How it works: This snippet demonstrates how to use Eloquent local scopes to implement dynamic, reusable filtering logic. Local scopes are methods prefixed with `scope` in your model, accepting the `Builder` instance as their first argument. You can then chain these scopes in your controller based on request parameters. This approach keeps your controller clean and makes query logic reusable across your application, improving maintainability and readability for complex filtering scenarios.