Installation:
composer require ndnam90/laravel-filterable
Publish the config (if needed):
php artisan vendor:publish --provider="Ndnam90\Filterable\FilterableServiceProvider"
First Use Case: Apply filtering to a model query. Start by defining a filterable trait in your model:
use Ndnam90\Filterable\Filterable;
class Post extends Model
{
use Filterable;
protected $filterable = [
'title' => 'like',
'published_at' => 'date',
'category_id' => '='
];
}
Then filter in your controller:
$posts = Post::filter(request()->all())->get();
Where to Look First:
config/filterable.php (if published) for customization.app/Models/YourModel.php to define filterable fields.Basic Filtering:
// Controller
$results = Model::filter(request()->query)->get();
$filterable array.Dynamic Filtering:
// Override default behavior in model
public function scopeFilter($query, array $filters)
{
return $this->applyFilters($query, $filters);
}
API Integration:
// API Resource
public function toArray($request)
{
return [
'data' => $this->filter(request()->query)->get(),
];
}
Complex Rules:
// Custom filter logic
protected $filterable = [
'price_range' => function ($query, $value) {
[$min, $max] = explode(',', $value);
return $query->whereBetween('price', [$min, $max]);
}
];
Form Integration:
// Blade form
<form method="GET">
<input type="text" name="title" placeholder="Search title...">
<input type="date" name="published_at">
<button type="submit">Filter</button>
</form>
$validated = request()->validate([
'title' => 'sometimes|string',
'published_at' => 'sometimes|date',
]);
$results = Model::filter($validated)->get();
paginate() after filtering:
$results = Model::filter(request()->query)->paginate(10);
$filterable:
protected $filterable = [
'author.name' => 'like' // Filters author.name column
];
Outdated Package:
spatie/laravel-query-builder.SQL Injection Risk:
request()->all() without validation can expose your app.Performance:
like on large text fields) can slow queries.php artisan schema:dump
Then manually add indexes in migrations.Undefined Filters:
$filterable keys silently fails.config/filterable.php for strict mode or add error handling:
try {
$results = Model::filter($filters)->get();
} catch (\Exception $e) {
Log::error("Filter error: " . $e->getMessage());
}
Log Queries:
Enable Laravel’s query logging in config/database.php:
'logging' => true,
Then check logs for generated SQL.
Test Filters: Manually test filter logic in Tinker:
php artisan tinker
$filters = ['title' => 'test'];
$query = (new Post)->newQuery()->filter($filters);
dd($query->toSql(), $query->getBindings());
Custom Filter Types: Extend the package by adding new filter operators in the service provider:
// app/Providers/FilterableServiceProvider.php
public function register()
{
Filterable::extend('custom', function ($query, $value) {
return $query->whereRaw("custom_column LIKE ?", ["%{$value}%"]);
});
}
Override Default Behavior: Publish and modify the config:
php artisan vendor:publish --tag=filterable-config
Then customize config/filterable.php (e.g., change default operator).
Macros: Add query builder macros for reusable filter logic:
use Illuminate\Database\Eloquent\Builder;
Builder::macro('filterByStatus', function ($status) {
return $this->where('status', $status);
});
Then use in $filterable:
protected $filterable = [
'status' => 'filterByStatus'
];
config/filterable.php to throw exceptions for invalid filters:
'strict' => env('FILTERABLE_STRICT', false),
= to like):
'default_operator' => 'like',
How can I help you explore Laravel packages today?