hamza-wakrim / laro-filters
Laro Filters adds custom filters automatically to your Eloquent Models in Laravel.It's easy to use and fully dynamic, just with sending the Query Strings to it.
Installs: 3
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
Type:lib
pkg:composer/hamza-wakrim/laro-filters
Requires
- php: ^8.0|^8.1|^8.2|^8.3|^8.4
Requires (Dev)
- mockery/mockery: 1.4.x-dev|1.4.2|1.5.1|^1.6
- orchestra/testbench: 5.*|^6.0|^6.6.0|^7.0.0|^8.0.0|v9.0.0|v10.0.0
- phpstan/phpstan: ^1.8
- phpunit/phpunit: 8.3|8.5|9.3|^9.5|10.5.5|^11.5.3
This package is auto-updated.
Last update: 2025-11-28 13:00:17 UTC
README
Laro Filters is a robust Laravel package providing an intuitive way to filter your Eloquent models using query strings. Perfect for crafting responsive APIs and complex data sets, this package seamlessly integrates with Laravel's existing Eloquent models, adding powerful and dynamic filtering capabilities with minimal setup.
Features:
- Support for complex query structures
- Easy to override conditions for custom behavior
- Harmonious integration with Laravel and Eloquent, including query builders
- Full control over filter execution and customization
- Support rate limit feature
We've tailored Laro Filters to be as flexible as you needβwhether your queries are straightforward or complex. With an extensive feature set, you can implement specific functionalities unique to your application with ease.
Note We considered what predictable features you wanted to implement no matter simple or complex, although we have a lot of features to make able you to implement your specific something's else.
Table of content
Requirements
- PHP 8.0 - 8.1 - 8.2 - 8.3 - 8.4
- Laravel 8.x - 9.x - 10.x - 11.x - 12.x (New)
Versions Information
| Major Version | Version | Status | PHP Version | Laravel Version |
|---|---|---|---|---|
| ^4.0 | 4.5.0 - 4.x.x | Active support | >= 8.2 | >= 12.x |
| ^4.0 | 4.2.0 - 4.4.9 | Active support | >= 8.2 | > 11.0 <= 11.x |
| ^4.0 | 4.0.x - 4.1.5 | Active support | >= 8.0 | >= 9.x <= 10.x |
| ^3.0 | 3.2.x - 3.4.x | End of life | >= 8.0 | >= 9.x |
| ^3.0 | 3.0.0 - 3.0.5 | End of life | >= 7.4.0 | >= 5.6.x <= 8.x |
| ^2.0 | 2.0.0 - 2.6.7 | End of life | <= 7.4.0 | >= 5.x <= 5.4 |
π€ Introduction
Conceivably, you would face challenges if you've done a task as an end-point in which there are some queries with many advanced options.
Let's say we want to make an advanced search page with multiple filter options.
A simple implementation without Laro Filters
The Resource URI would be look like:
/users/index?age_more_than=25&gender=male&created_at=25-09-2019
And a simple implementation in the Controller would look like :
<?php namespace App\Http\Controllers; use App\User; use Illuminate\Http\Request; class UserController extends Controller { public function index(Request $request) { $users = User::where('is_active', true); if ($request->has('age_more_than')) { $users->where('age', '>', $request->age_more_than); } if ($request->has('gender')) { $users->where('gender', $request->gender); } if ($request->has('created_at')) { $users->where('created_at','>=', $request->created_at); } return json_encode($users->get()); } }
This solution is simple and that works well but not for an enterprise project. But you'd have to add a condition for each filter you need. Especially if you would make more complex filtering, your code can become a monster quickly! π₯
Hence, Laro Filters is ready for to you get rid of complexity in addition to saving time.
A simple implementation with Laro Filters
Laro Filters can help you to manage these features. Just you will set query string to work with that. It would make your own query automatically and systematically while you can control them.
Right after installing Laro Filters, the request URI would be like this:
/users/list?age_more_than[operator]=>&age[value]=35&gender=male&created_at[operator]==>&created_at[value]=25-09-2019
And in the Controller, You just need that one line:
/** * Class UsersController. */ namespace App\Http\Controllers; use App\User; class UsersController { public function list() { return User::filter()->get(); } }
By Laro filters implementation, you can use all the documented filters!
π Installation
1- Run the following command in your project directory to add the Laro Filters as a dependency
$ composer require hamza-wakrim/laro-filters
- Note We support auto-discovery but you can check them.
2- Add laroFilters\ServiceProvider::class to provider app.php
'providers' => [ /* * Package Service Providers... */ laroFilters\ServiceProvider::class ]
-
In latest Laravel version add it to
providers.php:return [ App\Providers\AppServiceProvider::class, laroFilters\ServiceProvider::class ];
3- Add Facade 'laroFilters' => laroFilters\Facade\LaroFilters::class to aliases app.php
'alias' => [ /* * Facade alias... */ 'laroFilters' => laroFilters\Facade\LaroFilters::class, ],
- There is no need any change for Laravel 12.
That's it enjoy! π₯
π Basic Usage
Config Model and set whitelist
Add the Filterable trait to yourself models and set fields in the whitelist array in which you will want to use of
filter .
You can override this method in your models as well.
use laroFilters\QueryFilter\ModelFilters\Filterable; class User extends Model { use Filterable; private static $whiteListFilter =[ 'id', 'username', 'email', 'created_at', 'updated_at', ]; }
- You can set
*char for that filter in all fields alike below example:
private static $whiteListFilter = ['*'];
You able add or set $whiteListFilter on the fly in your method. For example:
Set array to WhiteListFilter
- Note This method override
$whiteListFilterarray
User::setWhiteListFilter(['name']);
Add new field to WhiteListFilter
User::addWhiteListFilter('name');
-Note Just in case, you must set $whiteListFilter in Models. Aim of the method avert to manipulation query string
by a bad user.
Conditions Guidance Table
- To better understand this, I provided a table of all conditions and samples. It represents how eloquent filter detect params and each param what query would make.
| Condition Name | Eloquent Method | Param | Example | Eloquent | DB |
|---|---|---|---|---|---|
| WhereCustomCondition | Declared custom method of Model |
β | β | ||
| SpecialCondition | f_params[limit]=10 f_params[orderBy][field]=id f_params[orderBy][field]=profile.name |
support f_params, e.g: limit and orderBy (including relation sorting) |
β | β | |
| WhereBetweenCondition | whereBetween | created_at[start]=2016/05/01 &created_at[end]=2017/10/01 |
whereBetween( 'created_at', [{start},{end}]) |
β | β |
| WhereByOptCondition | where | count_posts[operator]=>& count_posts[value]=35 |
where('count_posts', ">", $value) |
β | β |
| WhereLikeCondition | where | first_name[like]=Hamza | where('first_name', 'like', $value) |
β | β |
| WhereInCondition | whereIn | username[]=Hamza& username[]=Hamza12 |
whereIn('username', $value) | β | β |
| WhereOrCondition | orWhere | username=Hamza& or[username]=Hamza |
orWhere('username', $value) | β | β |
| WhereHas | WhereHas | posts[title]=sport one | whereHas('posts', function ($q) {$q->where('title', $value)}); |
β | β |
| WhereDoesntHaveCondition | whereDoesntHave | doesnt_have=category | doesntHave($value) | β | β |
| WhereDateCondition | whereDate | created_at=2024-09-01 | whereDate('created_at', $value) | β | β |
| WhereYearCondition | whereYear | created_at[year]=2024 | whereYear('created_at', $value) | β | β |
| WhereMonthCondition | whereMonth | created_at[month]=3 | whereMonth('created_at', $value) | β | β |
| WhereDayCondition | whereDay | created_at[day]=15 | whereDay('created_at', $value) | β | β |
| WhereNullCondition | whereNull | username[null]=true | whereNull('username') | β | β |
| WhereNotNullCondition | whereNotNull | username[not_null]=true | whereNotNull('username') | β | β |
| WhereCondition | where | username=Hamza | where('username', $value) | β | β |
Simple Examples
You just pass data form as query string. For example:
Simple Where
/users/list?email=hama.wakrim@gmail.com
SELECT ... WHERE ... email = 'hamza.wakrim@gmail.com'
/users/list?first_name=hamza&last_name=wakrim
SELECT ... WHERE ... first_name = 'hamza' AND last_name = 'wakrim'
- If you send date format
Y-m-dwe will work likeWhereDate()method Laravel.
/users/list?created_at=2024-09-01
SELECT ... WHERE ... strftime('%Y-%m-%d', "created_at") = cast(2024-09-01 as text)
Where In
This example make method whereIn.
/users/list?username[]=hamza&username[]=hamza22&family=wakrimm
SELECT ... WHERE ... username in ('hamzza','hamza90') AND family = 'wakrimm'
OrWhere
This example make method orWhere().
/users/list?name=hamza&username=wakrimm&or[username]=hamza
SELECT ... WHERE ... name = 'hamza' AND username = 'wakrimm' or username = 'hamza'
Where like
If you are going to make a query by like conditions. You can do that by this example.
/users/list?first_name[like]=%Hamza%
SELECT ... WHERE ... first_name LIKE '%Hamza%'
Where by operator
You can set any operator mysql in the queries string.
/users/list?count_posts[operator]=>&count_posts[value]=35
SELECT ... WHERE ... count_posts > 35
/users/list?username[operator]=!=&username[value]=hamza
SELECT ... WHERE ... username != 'hamza'
/users/list?count_posts[operator]=<&count_posts[value]=25
SELECT ... WHERE ... count_posts < 25
Where the nested relations Model
You can set all nested relations in the query string just via the array of query string. Imagine, the user model has a relation with posts. And posts table has a relation with orders table.
You can make query conditions by set posts[count_post] and posts[orders][name] in the query string.
- Just be careful you must set
posts.count_postandposts.orders.namein the User model.
use laroFilters\QueryFilter\ModelFilters\Filterable; class User extends Model { use Filterable; private static $whiteListFilter =[ 'username', 'posts.count_post', 'posts.category', 'posts.orders.name', ]; /** * @return \Illuminate\Database\Eloquent\Relations\belongsTo */ public function posts() { return $this->belongsTo('Models\Post'); } }
/users/list?posts[count_post]=876&username=hamza
select * from "users" where exists
(select * from "posts" where "posts"."user_id" = "users"."id"
and "posts"."count_post" = 876)
and "username" = "hamza"
- The above example is the same code that you used without the eloquent filter. Check it under code. It's not amazing?
$builder = (new User())->with('posts'); $builder->whereHas('posts', function ($q) { $q->where('count_post', 876); })->where('username','hamza');
Where array the nested relation Model
You can pass array to make whereIn condition.
/users/list?posts[category][]=php&posts[category][]=laravel&posts[category][]=jquery&username=hamza
select * from "users" where exists
(select * from "posts" where
"posts"."category" in ('php','laravel','jquery') )
and "username" = "hamza"
Doesnthave Where (new feature)
/tags/list?doesnt_have=category
select * from "tags" where not exists (select * from "categories" where "tags"."foo_id" = "categories"."id")'
- To fetching those data that doesn't have any relationship with the model as the same
Doesnthavemethod worked.
Special Params
You can set special params limit and orderBy in the query string to make a query by that.
Limit
/users/list?f_params[limit]=1
SELECT ... WHERE ... order by `id` desc limit 1 offset 0
OrderBy - Direct Columns
/users/list?f_params[orderBy][field]=id&f_params[orderBy][type]=ASC
SELECT ... WHERE ... order by `id` asc
/users/list?f_params[orderBy][field]=id,count_posts&f_params[orderBy][type]=ASC
SELECT ... WHERE ... order by `id` asc, `count_posts` asc
OrderBy - Relation Sorting
You can sort by related model columns using dot notation (e.g., relation.column). The system automatically handles different relation types:
- BelongsTo Relations: Joins the related table and orders by the relation's column
- HasOne Relations: Joins the related table and orders by the relation's column
- HasMany Relations: Uses a subquery with aggregate function (MIN for ASC, MAX for DESC) to avoid duplicate rows
- Other Relations: Uses a subquery to get the first related record for ordering
Example - Sort by BelongsTo relation:
/users/list?f_params[orderBy][field]=profile.name&f_params[orderBy][type]=ASC
SELECT * FROM users
LEFT JOIN profiles as profiles_order_profile ON users.profile_id = profiles_order_profile.id
ORDER BY profiles_order_profile.name ASC
Example - Sort by HasOne relation:
/posts/list?f_params[orderBy][field]=author.email&f_params[orderBy][type]=DESC
SELECT * FROM posts
LEFT JOIN users as users_order_author ON users_order_author.id = posts.author_id
ORDER BY users_order_author.email DESC
Example - Sort by HasMany relation:
/users/list?f_params[orderBy][field]=posts.created_at&f_params[orderBy][type]=DESC
SELECT * FROM users
ORDER BY (SELECT MAX(posts.created_at) FROM posts WHERE posts.user_id = users.id) DESC
Example - Mix direct columns and relations:
/posts/list?f_params[orderBy][field]=created_at,author.name&f_params[orderBy][type]=DESC
SELECT * FROM posts
LEFT JOIN users as users_order_author ON users_order_author.id = posts.author_id
ORDER BY created_at DESC, users_order_author.name DESC
Note:
- The relation name must match a method on your model
- Only single-level relations are supported (e.g.,
profile.name, notuser.profile.name) - Relation sorting only works with Eloquent models, not DB queries
- If relation doesn't exist, throws
EloquentFilterExceptionwith code3
Where between
If you are going to make a query based on date, You must fill keys, start, and end in the query string.
Hence You can set it as a query string. These params are used for the filter by date.
/users/list?created_at[start]=2016/05/01&created_at[end]=2017/10/01
SELECT ... WHERE ... created_at BETWEEN '2016/05/01' AND '2017/10/01'
Advanced Where
/users/list?count_posts[operator]=>&count_posts[value]=10&username[]=hamza&username[]=hamza&family=wakrimm&created_at[start]=2016/05/01&created_at[end]=2020/10/01
&f_params[orderBy][field]=id&f_params[orderBy][type]=ASC
select * from `users` where `count_posts` > 10 and `username` in ('hamza', 'hamza') and
`family` = wakrimm and `created_at` between '2016/05/01' and '2020/10/01' order by 'id' asc limit 10 offset 0
Therefore, fields of query string are same rows table database in $whiteListFilter in your model or declare the method in your model as override method.
The overridden method can be considered a custom query filter.
Custom Query Filter
Laro Filters doesn't support all the conditions by default. For this situation, you can make an overridden method.
If you are going to make yourself a query filter, you can do it easily.
You should take care of using filterCustom before method name in new version.
You should run the command to make a trait and use it on the model:
php artisan laroFilters:filter users
namespace App\ModelFilters; use Illuminate\Database\Eloquent\Builder; /** * Trait UsersFilter. */ trait UsersFilter { /** * This is a sample custom query * @param \Illuminate\Database\Eloquent\Builder $builder * @param $value * * @return \Illuminate\Database\Eloquent\Builder */ public function filterCustomSample_like(Builder $builder, $value) { return $builder->where('username', 'like', '%'.$value.'%'); } }
-Note These fields of query string are the same methods of the trait. Use trait in your model:
/users/list?sample_like=a
select * from `users` where `username` like %a% order by `id` desc limit 10 offset 0
use App\ModelFilters\UsersFilter; class User extends Model { use UsersFilter,Filterable; protected $table = 'users'; protected $guarded = []; private static $whiteListFilter =[ 'id', 'username', 'email', 'created_at', 'updated_at', ]; }
Some Filter methods
User::filter()->paginate();
-
LaroFilters::filterRequests(): get all params that used by the Laro Filters. You can set key to get specific index. For exampleLaroFilters::filterRequests('username')it's getting username index. -
LaroFilters::getAcceptedRequest(): get all params that set by the AcceptRequest method. -
LaroFilters::getIgnoredRequest(): get all ignored params that set by the getIgnoreRequest method.
Request encoded
In particular projects, We don't want to share our request filters with all users. It means every single user should have a unique valid url for duplicated search then It works just for the same user.
LaroFilters::getRequestEncoded(): get passed request as encoded request based on default.LaroFilters::setRequestEncoded(): set request encoded with a selective salt.
You just need to pass hashed_filters as key to detect hashed_filter and encode them in the core. Every single user has a unique url per user. In addition, nobody can manipulate parameters in order to get specific data.
/users/list?hashed_filters=MXsidGl0bGUiOiJzcG9ydCJ9
SELECT ... WHERE ... name = 'hamza'
- You make sure adjust
request_saltin config.php. You'd better set a unique value like user_id or ip.
For this purpose, You had better have an end-point to set and get request encoded then pass it to your main end-point for result.
Custom Detection Conditions
Sometimes you want to make your custom condition to make a new query that Laro Filters doesn't support by default. The good news is you would make a custom condition in the eloquent filter from now on.
You can make conditions to generate a new query after checking by that. For example:
We must have two classes. The First detects conditions second class generates the query.
- Step 1: Create a class to detect some conditions
use laroFilters\QueryFilter\Detection\Contract\ConditionsContract; /**`` * Class WhereRelationLikeCondition. */ class WhereRelationLikeCondition implements ConditionsContract { /** * @param $field * @param $params * @param $is_override_method * * @return string|null */ public static function detect($field, $params, $is_override_method = false): ?string { if (!empty($params['value']) && !empty($params['limit']) && !empty($params['email'])) { $method = WhereRelationLikeConditionQuery::class; } return $method ?? null; } }
- Step 2:Right after, create a class to generate a query. In this example we make
WhereRelationLikeConditionQueryclass:
use laroFilters\QueryFilter\Queries\BaseClause; use Illuminate\Database\Eloquent\Builder; /** * Class WhereRelationLikeConditionQuery. */ class WhereRelationLikeConditionQuery extends BaseClause { /** * @param $query * * @return Builder */ public function apply($query): Builder { return $query ->whereHas('posts', function ($q) { $q->where('comment', 'like', "%" . $this->values['like_relation_value'] . "%"); }) ->where("$this->filter", '<>', $this->values['value']) ->where('email', 'like', "%" . $this->values['email'] . "%") ->limit($this->values['limit']); } }
- Step 3: You make the method
EloquentFilterCustomDetectionfor return array detections of the condition in the model.
use laroFilters\QueryFilter\ModelFilters\Filterable; class User extends Model { use Filterable; private static $whiteListFilter =[ 'username', 'posts.count_post', 'posts.category', 'posts.orders.name', ]; /** * @return \Illuminate\Database\Eloquent\Relations\belongsTo */ public function posts() { return $this->belongsTo('Models\Post'); } public function EloquentFilterCustomDetection(): array { return [ WhereRelationLikeCondition::class ]; } }
- Each of the query params is used to detect in
WhereRelationLikeConditionfor the first time after that check by default detection eloquent filter.
Make method EloquentFilterCustomDetection in the above example and return array conditions class.
/users/list?username[value]=hamza&username[limit]=10&username[email]=hamzawakrimm&username[like_relation_value]=hamza&count_posts=10
select * from "users"
where exists (select * from "posts" where
"users"."post_id" = "posts"."id"
and "comment" like ?) and "username" <> ? and "email" like ? and "count_posts" = ? limit 10
You just run code User::filter(); for see result.
Model::setLoadInjectedDetection(false): You can deactivate custom detection conditions on the fly.
-Note as well, you can set custom detection on the fly by use of the method SetCustomDetection. For example :
$users = User::SetCustomDetection([WhereRelationLikeCondition::class])->filter();
-Note You can disable EloquentFilterCustomDetection on the fly by this code :
User::SetLoadDefaultDetection(false)->filter();
-Note You can set many detection conditions. e.g:
class User extends Model { use Filterable; public function EloquentFilterCustomDetection(): array { return [ WhereRelationLikeCondition::class, WhereRelationLikeVersion2Condition::class, WhereRelationLikeVersion3Condition::class, ]; } }
LaroFilters::getInjectedDetections()gets all of your customs injected detection.
-Note Every custom detection will run before any detections by default eloquent filter.
Configuring
You can publish the configuration file to customize the package further:
Publish Config
php artisan vendor:publish --provider="laroFilters\ServiceProvider"
Config
-
You can disable/enable Laro Filters in the config file (laroFilters.php).
'enabled' => env('EloquentFilter_ENABLED', true), -
Laro Filters recognizes every param of the queries string. Maybe you have a query string that you don't want to recognize by Laro Filters. You can use
ignoreRequestfor his purpose. But we have a clean solution to this problem. You can set paramrequest_filter_keyin the config file. Therefore, every query string will recognize by therequest_filter_keyparam.'request_filter_key' => '', // filter
For example, if you set 'request_filter_key' => 'filter', that Laro Filters recognizes filter query string.
/users/list?filter[email]=hamzawakrimm.developer@gmail.com
-
You can disable/enable all the custom detection of Laro Filters in the config file (laroFilters.php).
'enabled_custom_detection' => env('EloquentFilter_Custom_Detection_ENABLED', true), -
You should set an index array
ignore_requestto ignore all filters.'ignore_request' => [] //[ 'show_query','new_trend' ], -
You had better keep
max_limit. It's a limitation for preventing making awful queries mistakenly by the developer or intentionally by a villain user.'max_limit' => 20 -
With
filtering_keys,You have a place to declare some provided key and use it in filtering.'filtering_keys'=>[ 'title_sport_advanced' => [ 'title' => 'sport', 'created_at' => [ 'start' => '2019-01-01 17:11:46', 'end' => '2019-02-06 10:11:46', ], 'sub_cat' => [ 'news 1', 'news 2' ], ] ]Then you just need to pass
config('laroFilters.filtering_keys.title_sport_advanced')to filter method. -
From now on , we have the ability to record logs by logger instance. Since queries is made dynamically somehow , the need of feature keeping queries with their time is required. So we added it in this version with some other options to better management.
'log' => [ 'has_keeping_query' => false, 'max_time_query' => null, 'type' => 'laroFilters.query' ]
It's disable by default you enable by has_keeping_query, type is type log ,and max_time_query is a value for
keeping queries with high time-executed.
Alias
Sometimes you may want to change some parameters in the URL while those mention a field of the model. e.g. name of the input form is not similar to the model ,or you want to change them for other reasons so the alias as a new feature can be useful.
class Stat extends Model { use Filterable; /** * @var array */ private static $whiteListFilter = [ 'type', 'national_code', ]; /** * @var array */ private $aliasListFilter = [ 'national_code' => 'code', ]; }
Then you should send the code param in the URL for making a query with the national code field of the model readily.
Query Builder Introduction
Great news!
Some people asked me a lot to add new feature to support Laravel query builder. It needed a lot of energy and devoting time , so I decided to implement it. It's quite tough however finally it's almost done now.
We are supporting query builder along with eloquent from now on. Not only you would use query builder ,but also you can use eloquent at the same time.
It's a new feature ,and I'm snowed under the code to fix issues. Anyway this feature is up right now with just some
limitation.
We don't support WhereCustomCondition for query builder at the moment but other conditions were ready
to use.
in addition, we don't have any kind of whitelist , blacklist , custom detectioon or alias.
currently , It's just a simple feature.
- Usage of them is just extremely like model just you need use filter as a method. Obviously, there's no need any change like use trait or etc.
DB::table('users')->filter();
Magic Methods
Magic methods are a collection of methods that you can use as a wrapper in the Laro Filters.
For example, serialize data before filtering or changing data in response and others.
Now Laro Filters have serializeRequestFilter,ResponseFilter and , etc.
Request Methods
Call ignoreRequest (static scope) or ignoreRequestFilter will ignore some requests that you don't want to use in
conditions of eloquent filter.
Change your code the controller of the laravel project as like below example:
$users = User::ignoreRequest(['name']) ->filter() ->with('posts') ->orderByDesc('id') ->paginate(request()->get('perpage'),['*'],'page');
$user = new User(); $users = $user->ignoreRequestFilter(['name','family']) ->filter() ->with('posts') ->orderByDesc('id') ->paginate(request()->get('perpage'),['*'],'page');
-Note The Laro Filters config by default uses the query string to make queries in Laravel.
Although, you can set the collection data in the filter method Model for making your own custom condition without
query string.
-Note Therefore you must unset yourself param as perpage. Just you can set page param for paginate this param ignore from the filter.
- You can ignore some request params via use of the bellow code.
User::ignoreRequest(['perpage']) ->filter() ->paginate(request()->get('perpage'), ['*'], 'page');
e.g: the perpage param will never be in the conditions eloquent filter.
It has to do with to the paginate method. page param ignore by default in Laro Filters of Laravel.
- You are able to filter some request params as acceptable filter`.
Calling AcceptRequest (static scope) or acceptRequestFilter will accept requests in which you want to use in
conditions Laro Filters.
e.g: username and id key will be in the conditions eloquent filter.
`` User::AcceptRequest(['username','id']) ->filter() ->paginate(request()->get('perpage'), ['*'], 'page');
$user = new User(); $user->acceptRequestFilter(['username','id']) ->filter() ->paginate(request()->get('perpage'), ['*'], 'page');
Request Filter
Laro Filters has a magic method for just change requests injected before handling by eloquent filter. This method is
SerializeRequestFilter. You just implement SerializeRequestFilter method in your Model. For example
class User extends Model { use Filterable; private static $whiteListFilter =[ 'username' ]; public function serializeRequestFilter($request) { $request['username'] = trim($request['username']); return $request; } }
As above code, you can modify every query params of the Model in the method serializeRequestFilter before running by
Laro Filters.
That is a practical method when you want to set user_id or convert date or remove space and others.
Request Field Cast Filter
Laro Filters requires a bunch of specific methods for each of the fields before going on filter process.
This feature has been implemented recently. By this filterSet + field method in your model, You
will be able to add some change for that particular field.
class Category extends Model { use Filterable; private static $whiteListFilter =[ 'desc' ]; public function filterSetDesc($value) { return trim($value); } }
Response Filter
Response Filter is an overriding method for changing response right after handle by Laro Filters. The method called
getResponseFilter and You could implement the method getResponseFilter in your Model. e.g:
class User extends Model { use Filterable; public function getResponseFilter($response) { $data['data'] = $response; return $data; } }
- You are capable of passing a callback function to
getResponseFiltermethod to change the response. We only have this feature in query builder DB.
$categories = DB::table('categories')->filter()->getResponseFilter(function ($out) { $data['data'] = $out; return $data; });
Black List Detections
Obviously, you never want all users who are able to get data by manipulating requests. As a result, we'd better have an eloquent control feature. Although we have this ability on request side, we need this feature on Eloquent side as well.
We would set a blacklist detection to prevent making conditions by using it. Therefore, that list has been disabled in making conditions. for example:
namespace App\Http\Controllers; /** * Class UsersController. */ class UsersController { public function list() { $users = User::setBlackListDetection( [ 'WhereCondition', ] )->filter() ->orderByDesc('id') ->paginate(); } }
- You are able to set on Model layer as well.
black_list_detectionsarray is used for this purpose.
<?php namespace Tests\Models; use laroFilters\QueryFilter\ModelFilters\Filterable; use Illuminate\Database\Eloquent\Model; class Car extends Model { use Filterable; private static $whiteListFilter = '*'; protected $black_list_detections = [ 'WhereCondition', ]; }
Macro Methods
-isUsedEloquentFilter is a macro method for builder/DB to check either query used eloquent-filter.
-getDetectionsInjected is a macro method to get list array of injected objects.
e.g:
$users = User::SetCustomDetection([WhereRelationLikeCondition::class])->filter(); echo $users->isUsedEloquentFilter(); // will true echo $users->getDetectionsInjected(); // will showing a list array of injected objects $categories = DB::table('categories')->filter(); echo $categories->isUsedEloquentFilter(); // will true
Rate Limiting
Laro Filters includes a built-in rate limiting feature to protect your application from excessive filter requests. This feature helps prevent abuse and ensures optimal performance.
Configuration
First, publish the configuration file if you haven't already:
php artisan vendor:publish --provider="laroFilters\ServiceProvider"
In your config/eloquent-filter.php file, you can configure rate limiting:
return [ // ... existing config ... 'rate_limit' => [ // Enable or disable rate limiting 'enabled' => true, // Maximum number of attempts within the decay time 'max_attempts' => 60, // Decay time in minutes 'decay_minutes' => 1, // Whether to include rate limit headers in the response 'include_headers' => true, // Custom error message for rate limit exceeded 'error_message' => 'Too many filter requests. Please try again later.', ], ];
Using Rate Limiting
Rate limiting is automatically applied when you use the filter() method on your models. No additional configuration is required in your models.
use App\Models\User; // This query will be rate limited according to your configuration $users = User::filter()->get();
Rate Limit Headers
When rate limiting is enabled and include_headers is set to true, the following information is available in the request attributes:
X-RateLimit-Limit: Maximum number of requests allowedX-RateLimit-Remaining: Number of requests remaining in the current windowX-RateLimit-Reset: Time in seconds until the rate limit resets
Handling Rate Limit Exceeded
When the rate limit is exceeded, a ThrottleRequestsException will be thrown with the configured error message. You can catch this exception in your exception handler:
use Illuminate\Http\Exceptions\ThrottleRequestsException; public function render($request, Throwable $exception) { if ($exception instanceof ThrottleRequestsException) { return response()->json([ 'message' => $exception->getMessage(), ], 429); } return parent::render($request, $exception); }
Custom Rate Limiting
You can customize the rate limiting behavior by modifying the configuration or extending the RateLimiting trait in your own implementation.
Contributing
If you'd like to contribute to Laro Filters, please fork the repository and create a pull request. We welcome contributions of all kinds, including bug fixes, new features, and documentation improvements.
Proposed Features (Under Consideration)
We are constantly working to improve our package and have planned the following features for upcoming releases:
- Configurable Filter Presets: Implement the ability to define and save filter presets. This feature would allow users to quickly apply common sets of filters without having to specify them each time.
Your contributions are always welcome! If you would like to help with the development of these features.
License
Laro Filters is open-source software licensed under the MIT license.
Contact
If you have any questions or feedback about Laro Filters, please feel free to contact us at hamzawakrimm.developer@gmail.com. We'd love to hear from you!
Acknowledgements
We'd like to thank the Laravel community for their support and contributions to this project.
