Installation:
composer require aldemeery/sieve
No service provider or facade registration needed—just use the Sieve class directly.
First Use Case:
Define a filter class for your model (e.g., ProductFilter):
use Aldemeery\Sieve\Filter;
class ProductFilter extends Filter
{
public function apply($query)
{
$query->where('color', $this->value('color'))
->where('condition', $this->value('condition'));
}
}
Use it in a controller:
use Aldemeery\Sieve\Sieve;
public function index(Request $request)
{
$filter = new ProductFilter($request->all());
$query = Product::query();
Sieve::apply($filter, $query);
return $query->get();
}
Filter class: Core abstraction for defining filters.Sieve::apply(): Static method to apply filters to queries.value() helper: Retrieve sanitized request values (e.g., $this->value('color')).Basic Filtering:
class UserFilter extends Filter
{
public function apply($query)
{
$query->where('active', $this->value('active', false))
->where('role', $this->value('role'));
}
}
Dynamic Conditions:
Use when() for conditional logic:
public function apply($query)
{
$this->whenHas('search', fn($query) => $query->where('name', 'like', "%{$this->value('search')}%"));
}
Ordering:
public function apply($query)
{
$query->orderBy('created_at', $this->value('sort', 'desc'));
}
Nested Filters: Chain filters for complex queries:
$filter = new ProductFilter($request->all());
$query = Product::query();
Sieve::apply($filter, $query);
Sieve::apply(new CategoryFilter($request->all()), $query);
Filter classes to test query logic in isolation:
$filter = Mockery::mock(ProductFilter::class, [$request->all()]);
$filter->shouldReceive('apply')->once();
SQL Injection:
Always use $this->value() to escape inputs. Avoid raw $request->input() in apply().
Over-Filtering: Avoid applying filters blindly to all queries. Use guard clauses:
if ($this->has('color')) { ... }
Performance:
Complex filters (e.g., nested orWhere) can bloat queries. Profile with DB::enableQueryLog().
Default Values:
$this->value('field', default) returns null if the field is missing. Use null explicitly for IS NULL checks:
$query->whereNull('deleted_at')->orWhere('deleted_at', $this->value('deleted_at'));
Query Logs: Enable Laravel’s query logging to inspect generated SQL:
DB::enableQueryLog();
$query->get();
dd(DB::getQueryLog());
Filter Dumping: Temporarily dump filter values:
dd($this->all()); // All raw request values
Custom Value Sanitization:
Override sanitize() in your Filter:
protected function sanitize($value)
{
return strtolower(parent::sanitize($value));
}
Reusable Filter Logic: Extract common logic into traits:
trait Searchable
{
public function applySearch($query)
{
$query->where('name', 'like', "%{$this->value('search')}%");
}
}
Filter Composition: Combine filters dynamically:
$filters = [
new ProductFilter($request->all()),
new PriceFilter($request->all()),
];
Sieve::applyMany($filters, $query);
Filter classes.$_GET/$_POST. For custom sources (e.g., API payloads), pass an array to the Filter constructor.How can I help you explore Laravel packages today?