A filter object for Laravel/Eloquent models based on laracasts approach.
coderscantina/laravel-filter is a Laravel package for a filter object for laravel/eloquent models based on laracasts approach..
It currently has 2 GitHub stars and 8.654 downloads on Packagist (latest version v2.0.0).
Install it with composer require coderscantina/laravel-filter.
Discover more Laravel packages by coderscantina
or browse all Laravel packages to compare alternatives.
Last updated
A secure and optimized filter object for Laravel/Eloquent models based on the laracasts approach.
Require this package with composer:
$ composer require coderscantina/filter
Define a filter:
<?php namespace App;
use CodersCantina\Filter\ExtendedFilter;
class TestFilter extends ExtendedFilter
{
public function name($name)
{
return $this->builder->where('name', $name);
}
public function latest()
{
return $this->builder->latest();
}
}
In your model:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
use CodersCantina\Filter\Filterable;
class TestModel extends Model
{
use Filterable;
}
In your controller:
<?php namespace App\Http\Controllers;
use App\TestModel;
use App\TestFilter;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Collection;
class LessonsController extends Controller
{
/**
* Show all lessons.
*
* @param Request $request
* @return Collection
*/
public function index(Request $request)
{
$filter = new TestFilter($request->all());
// For enhanced security, whitelist allowed filters
$filter->setWhitelistedFilters(['name', 'latest']);
return TestModel::filter($filter)->get();
}
}
The package supports advanced filtering with operator-based syntax for more expressive queries. This feature allows you to easily implement complex filtering logic with minimal code.
The following operators are supported:
| Operator | SQL Equivalent | Description |
|----------|---------------|-------------|
| null | IS NULL | Matches null values |
| !null | IS NOT NULL | Matches non-null values |
| eq | = | Equals (default if no operator specified) |
| neq | != | Not equals |
| empty | Custom | Matches empty strings or null values |
| !empty | Custom | Matches non-empty and non-null values |
| like | LIKE | Contains (adds wildcards around value) |
| !like | NOT LIKE | Does not contain (with wildcards) |
| ^like | LIKE | Starts with (adds wildcard after) |
| like$ | LIKE | Ends with (adds wildcard before) |
| lt | < | Less than |
| gt | > | Greater than |
| lte | <= | Less than or equal to |
| gte | >= | Greater than or equal to |
| in | IN | In a list of values (comma-separated) |
| !in | NOT IN | Not in a list of values (comma-separated) |
To use advanced operators, extend from the AdvancedFilter class instead of ExtendedFilter:
<?php namespace App;
use CodersCantina\Filter\AdvancedFilter;
class ProductFilter extends AdvancedFilter
{
public function name($value)
{
// Automatically handles operator syntax
$this->applyDynamicFilter('name', $value);
}
public function price($value)
{
// Supports both operators and range syntax
$this->applyAdvancedRangeFilter('price', $value);
}
public function created_at($value)
{
// Supports both operators and date range syntax
$this->applyAdvancedDateFilter('created_at', $value);
}
}
// Find products with names containing "phone"
$filter = new ProductFilter(['name' => 'like:phone']);
// Find products with price greater than or equal to 100
$filter = new ProductFilter(['price' => 'gte:100']);
// Find products created after January 1, 2023
$filter = new ProductFilter(['created_at' => 'gte:2023-01-01']);
// Find products in specific categories
$filter = new ProductFilter(['category' => 'in:electronics,phones,accessories']);
// Find products that are either active or featured
$filter = new ProductFilter(['status' => ['eq:active', 'eq:featured']]);
// Find non-empty descriptions
$filter = new ProductFilter(['description' => '!empty:']);
The advanced filtering still supports the range filter syntax (...) while adding operator capabilities:
// Traditional range syntax still works
$filter = new ProductFilter(['price' => '100...500']);
// Using operators for precise comparisons
$filter = new ProductFilter(['price' => 'gte:100']);
Similarly, date filters can use both traditional range and operator syntax:
// Traditional date range
$filter = new ProductFilter(['created_at' => '2023-01-01...2023-12-31']);
// Using operators
$filter = new ProductFilter(['created_at' => 'gte:2023-01-01']);
You can combine multiple operator conditions for the same field:
// Products that are either active or pending
$filter = new ProductFilter([
'status' => ['eq:active', 'eq:pending']
]);
You can extend the supported operators by adding your own:
$filter = new ProductFilter(['price' => 'between:10,50']);
$filter->setCustomOperators(['between' => 'BETWEEN']);
If you're integrating the advanced filter functionality into an existing filter:
AdvancedFilterable trait in your filter classAdvancedFilter or add the trait to your custom filter classapplyDynamicFilter(), applyAdvancedRangeFilter(), or applyAdvancedDateFilter()<?php namespace App;
use CodersCantina\Filter\ExtendedFilter;
use CodersCantina\Filter\AdvancedFilterable;
class CustomFilter extends ExtendedFilter
{
use AdvancedFilterable;
public function status($value)
{
$this->applyDynamicFilter('status', $value);
}
}
The AdvancedFilter class maintains all the security features of the base Filter class:
Always use filter whitelisting in production to control which filters can be applied from user input:
$filter->setWhitelistedFilters(['name', 'price', 'category', 'status']);
To enhance security, always specify which filters are allowed:
$filter->setWhitelistedFilters(['name', 'price', 'category']);
The package automatically sanitizes input to prevent SQL injection attacks. However, you should still validate your input in controllers using Laravel's validation system.
The Sortable trait which is included in the ExtendedFilter offers sorting abilities:
['sort' => '+foo,-bar']; // -> order by foo asc, bar desc
Sort using foreign key relations:
['sort' => '+foo.bar']; // -> left join x on x.id = foo.id order by foo.bar asc
Limit the number of sort columns for performance:
$filter->setMaxSortColumns(3);
Restrict sortable columns:
protected array $sortableColumns = ['name', 'price', 'created_at'];
Apply range filters in various formats:
['price' => '10...']; // -> price >= 10
['price' => '...50']; // -> price <= 50
['price' => '10...50']; // -> price >= 10 and price <= 50
Filter by date ranges with automatic formatting:
['created_at' => '2023-01-01...']; // -> created_at >= '2023-01-01 00:00:00'
['created_at' => '...2023-12-31']; // -> created_at <= '2023-12-31 23:59:59'
['created_at' => '2023-01-01...2023-12-31']; // -> Between Jan 1 and Dec 31, 2023
Apply limit and offset for pagination:
['limit' => 10, 'offset' => 20]; // -> LIMIT 10 OFFSET 20
The package includes several optimizations:
Create custom filter methods in your filter class:
public function active($value = true)
{
$this->builder->where('active', $value);
}
public function priceRange($value)
{
$this->applyRangeFilter('price', $value);
}
public function dateCreated($value)
{
$this->applyDateFilter('created_at', $value);
}
You can override core methods for custom behavior:
protected function isValidColumnName(string $column): bool
{
// Your custom validation logic
return parent::isValidColumnName($column) && in_array($column, $this->allowedColumns);
}
The package includes a comprehensive test suite:
$ composer test
setWhitelistedFilters()Please see CHANGELOG for more information on what has changed recently.