Query Filters was fully inspired by this lesson on Laracasts, it provides a simple way to filter Eloquent models based on query parameters of an HTTP request.
Via Composer:
composer require cerbero/query-filters
If your version of Laravel is prior to 5.5, you can register this package service provider by adding the following line to the list of providers in config/app.php
:
'providers' => [
...
Cerbero\QueryFilters\Providers\QueryFiltersServiceProvider::class,
]
This package includes a generator for query filter classes that by default are generated in app/QueryFilters
. If you prefer a different path, you can set it in the config/query_filters.php
file after running:
php artisan vendor:publish --tag=query_filters_config
Imagine to have a route for indexing all actors stored in the database. This route accepts query parameters to filter records, for example:
/actors?won_oscar&acting=0&acted-in=2000
In this case the route will need to display only actors who won at least one Oscar, are no longer acting but acted in 2000.
This can be achieved by generating a query filters class and optionally defining the allowed query parameters and related variable names via the following Artisan command:
php artisan make:query-filters ActorFilters 'won_oscar&acting=bool&acted-in=year'
That command will generate and populate with filters the ActorFilters
class:
use Cerbero\QueryFilters\QueryFilters;
/**
* Filter records based on query parameters.
*
*/
class ActorFilters extends QueryFilters
{
/**
* Filter records based on the query parameter "won_oscar"
*
* @return void
*/
public function wonOscar()
{
// $this->query
}
/**
* Filter records based on the query parameter "acting"
*
* @param mixed $bool
* @return void
*/
public function acting($bool)
{
// $this->query
}
/**
* Filter records based on the query parameter "acted-in"
*
* @param mixed $year
* @return void
*/
public function actedIn($year)
{
// $this->query
}
}
Please note how filter names are the equivalent camel case form of their related query parameters.
Filters are only applied if their query parameter is present in the HTTP request with a non-empty value, unless they need no value to function (e.g. won_oscar
).
The $query
property lets filters determine how queries change when they are applied:
public function wonOscar()
{
$this->query->where('oscars', '>', 0);
}
public function acting($bool)
{
$this->query->where('acting', $bool);
}
public function actedIn($year)
{
$this->query->whereHas('movies', function ($movies) use ($year) {
$movies->whereYear('release_date', '=', $year);
});
}
After filters are defined, Eloquent models can apply them by using the FiltersRecords
trait:
use Cerbero\QueryFilters\FiltersRecords;
use Illuminate\Database\Eloquent\Model;
class Actor extends Model
{
use FiltersRecords;
}
Finally in your route you can filter actors by calling the method filterBy()
of your model and passing the query filters:
use App\Actor;
use App\QueryFilters\ActorFilters;
...
public function index(ActorFilters $filters)
{
return Actor::filterBy($filters)->get();
}
Alternatively you can hydrate query filters from a plain array:
use App\Actor;
use App\QueryFilters\ActorFilters;
use Illuminate\Http\Request;
...
public function index(Request $request)
{
$filters = ActorFilters::hydrate($request->query());
return Actor::filterBy($filters)->get();
}
Sometimes you may want to silently skip filters if their value is not valid. Instead of setting validation rules in HTTP requests, you may define them in the query filters class.
This avoids a failed validation to stop the filtering process and applies only valid filters while ignoring filters with values that do not pass the validation:
class ActorFilters extends QueryFilters
{
protected function getRules()
{
return [
'acting' => 'bool',
'acted-in' => 'int|digits:4',
];
}
}
Please see CHANGELOG for more information what has changed recently.
composer test
Please see CONTRIBUTING and CONDUCT for details.
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.