laraditz/saring
Saring is a simple Eloquent model filtering package for Laravel and Lumen. Add the Filterable trait to models, create per-model filter classes (e.g., UserFilter), optionally whitelist filterable fields, and call Model::filter($request->all()).
Installation:
composer require laraditz/saring
Apply Trait:
Add Filterable trait to your Eloquent model:
use Laraditz\Saring\Filterable;
class User extends Model
{
use Filterable;
}
Create Filter Class:
Generate a filter class in App/Filters (e.g., UserFilter for User model):
php artisan make:filter UserFilter
(Note: The package doesn’t include a built-in Artisan command, so manually create the file.)
Define Filters:
Implement filter methods in UserFilter:
namespace App\Filters;
use Laraditz\Saring\Filter;
class UserFilter extends Filter
{
public function name($value)
{
$this->where('name', 'LIKE', "%$value%");
}
}
First Use Case: Apply filters via query builder:
$users = User::filter(request()->all())->get();
Or chain filters explicitly:
$users = User::filter(new UserFilter)->name('John')->get();
Request-Based Filtering:
Use filter() with request input to dynamically apply filters:
$results = Model::filter(request()->query)->get();
(Assumes request keys match filter method names.)
Explicit Filter Chaining: Chain filters programmatically for reusable logic:
$activeUsers = User::filter(new UserFilter)
->active(true)
->name('Admin')
->get();
Nested/Complex Filters: Combine conditions with logical operators:
public function search($query)
{
$this->where(function ($q) use ($query) {
$q->where('name', 'LIKE', "%$query%")
->orWhere('email', 'LIKE', "%$query%");
});
}
API Resource Integration: Use in API controllers to return filtered data:
public function index(Request $request)
{
return UserResource::collection(
User::filter($request->query)->paginate()
);
}
Validation:
Validate filter inputs before applying them (e.g., using Laravel’s Validator):
$validated = Validator::make(request()->all(), [
'name' => 'sometimes|string|max:255',
])->validate();
User::filter($validated)->get();
Caching Filters: Cache frequent filter combinations (e.g., for dashboards):
$cached = Cache::remember('filtered_users', now()->addHours(1), function () {
return User::filter(request()->query)->get();
});
Filter Groups:
Organize filters by context (e.g., AdminUserFilter, PublicUserFilter) and switch dynamically:
$filter = auth()->user()->isAdmin() ? new AdminUserFilter : new PublicUserFilter;
User::filter($filter)->get();
Lumen Compatibility:
Use Input facade instead of request():
$users = User::filter(Input::all())->get();
Case Sensitivity:
Filter method names must match request keys exactly (e.g., name vs. Name).
Fix: Normalize keys in middleware or use snake_case consistently.
Missing Filter Classes:
Forgetting to create the filter class (e.g., UserFilter) will throw:
Class 'App\Filters\UserFilter' not found
Fix: Ensure the class exists in App/Filters and follows <Model>Filter naming.
SQL Injection Risks:
Directly interpolating user input (e.g., $this->where('name', $value)) is unsafe.
Fix: Use parameter binding:
$this->where('name', 'LIKE', "%$value%"); // Safe if $value is sanitized
Overwriting Query:
Chaining filter() multiple times overwrites previous filters.
Fix: Use explicit filter instances:
// Bad: Overwrites
User::filter(request()->query)->filter(request()->query);
// Good: Chains
User::filter(new UserFilter)->name('John')->email('test@example.com');
Performance with Large Datasets:
Complex filters (e.g., nested orWhere) can slow queries.
Fix: Add database indexes or use select() to limit columns:
User::select(['id', 'name'])->filter(...)->get();
Log Filtered Queries: Use Laravel’s query logging to inspect generated SQL:
DB::enableQueryLog();
User::filter(request()->query)->get();
dd(DB::getQueryLog());
Validate Filter Logic: Test filters in isolation:
$filter = new UserFilter;
$filter->name('Test');
dd($filter->getQuery()); // Inspect the query builder
Custom Filter Logic:
Extend the Filter class to add reusable methods:
namespace App\Filters;
use Laraditz\Saring\Filter;
class BaseFilter extends Filter
{
public function isActive($value)
{
$this->where('active', $value);
}
}
Dynamic Filter Loading:
Auto-load filters based on model events (e.g., booted):
class User extends Model
{
use Filterable;
protected static function booted()
{
static::addGlobalScope(new FilterScope);
}
}
Filter Events: Listen for filter application (e.g., log or modify queries):
event(new Filtering($model, $filter));
(Requires custom event handling.)
Filterable Attributes:
Restrict filterable columns via $filterable property:
class UserFilter extends Filter
{
protected $filterable = ['name', 'email']; // Only allow these
}
Localization: Support multi-language filters by translating values:
public function name($value)
{
$translated = __($value); // Example: Translate 'Admin' to 'Administrator'
$this->where('name', 'LIKE', "%$translated%");
}
How can I help you explore Laravel packages today?