Installation:
composer require ysm/filterable
Publish the config (optional):
php artisan vendor:publish --provider="Ysm\Filterable\FilterableServiceProvider"
Basic Usage: Apply the trait to your Eloquent model:
use Ysm\Filterable\Filterable;
class User extends Model
{
use Filterable;
}
First Filter Request: Define a filterable field in your model:
protected $filterable = ['name', 'email'];
Use in a controller:
$users = User::filter(request()->all())->get();
Key Files:
config/filterable.php (for global settings)app/Models/YourModel.php (trait application)routes/web.php (API/route integration)Basic Filtering:
// Controller
$results = Model::filter(request()->query)->get();
API Integration:
// Route
Route::get('/api/users', [UserController::class, 'index']);
// Controller
public function index()
{
return response()->json(
User::filter(request()->all())->paginate()
);
}
Dynamic Filtering:
// Model
protected $filterable = [
'name' => ['type' => 'like'],
'status' => ['type' => 'in', 'values' => ['active', 'inactive']],
];
// Request
User::filter(['name' => 'John', 'status' => 'active']);
Combining with Scopes:
// Model
public function scopeActive($query)
{
return $query->where('active', true);
}
// Usage
User::active()->filter(request()->all())->get();
Custom Filter Logic:
// Model
protected $customFilters = [
'age_range' => function ($query, $value) {
[$min, $max] = explode('-', $value);
return $query->whereBetween('age', [$min, $max]);
}
];
// Request
User::filter(['age_range' => '25-40']);
Validation Integration:
// Form Request
public function rules()
{
return [
'name' => 'sometimes|string',
'email' => 'sometimes|email',
];
}
// Controller
$validated = $this->validate(request()->all());
User::filter($validated)->get();
Case Sensitivity:
type: 'like' for case-insensitive searches.protected $filterable = ['name' => ['type' => 'like']];
Date Handling:
Y-m-d). Use Carbon instances or ISO strings.User::filter(['created_at' => '2023-01-01']);
Relationship Filters:
user.posts.title) require explicit handling. Use with() and custom filters:
protected $customFilters = [
'post_title' => function ($query, $value) {
return $query->whereHas('posts', fn($q) => $q->where('title', 'like', "%{$value}%"));
}
];
Performance:
Schema::table('users', function (Blueprint $table) {
$table->index('email');
$table->index('name');
});
Mass Assignment:
$fillable if needed:
protected $fillable = ['name', 'email'];
Log Filter Queries:
Enable query logging in config/filterable.php:
'debug' => env('FILTERABLE_DEBUG', false),
Check Laravel logs for generated SQL.
Validate Input:
Use dd(request()->all()) to inspect incoming filter parameters before applying them.
Test Edge Cases:
''), null, and invalid values can break queries. Handle them in custom filters:
protected $customFilters = [
'status' => function ($query, $value) {
if ($value === '') return $query;
return $query->where('status', $value);
}
];
Custom Filter Types:
Extend the package by adding new filter types in app/Providers/FilterableServiceProvider.php:
use Ysm\Filterable\Filters\Filter;
class CustomFilter extends Filter
{
public function apply($query, $value)
{
// Custom logic
}
}
Register it in the service provider:
$this->app->bind('filter.custom', function () {
return new CustomFilter();
});
Override Default Behavior: Publish and modify the config to change global defaults (e.g., default operator, allowed types).
Integration with Search: Combine with Laravel Scout or Algolia for full-text search:
User::filter(request()->all())
->when(request('search'), fn($q) => $q->scoutSearch(request('search')))
->get();
Localization: For multilingual apps, add locale-aware filters:
protected $customFilters = [
'name' => function ($query, $value) {
return $query->where('name', 'like', "%{$value}%")
->orWhere('name_translations', 'like', "%{$value}%");
}
];
How can I help you explore Laravel packages today?