coliving / eloquent-filter
The Eloquent Filter is a package for filter data of models by the query string. Easy to use and fully dynamic.
Fund package maintenance!
raw.githubusercontent.com/mehdi-fathi/eloquent-filter/master/donate.png
Requires
- php: ^7.3|^8.0|^8.1
- illuminate/container: 5.8.*|~6.0|~7.0|~8.0|~9.0
- illuminate/database: 5.8.*|~6.20.14|~7.0|~8.0|~9.0
- illuminate/pagination: 5.8.*|~6.0|~7.0|~8.0|~9.0
- illuminate/support: 5.8.*|~6.0|~7.0|~8.0|~9.0
Requires (Dev)
- fzaninotto/faker: ^1.9|1.9.x-dev
- illuminate/macroable: ^8.0|^9.0
- laravel/legacy-factories: 1.0.2|1.0.3|1.0.4|1.0.5|1.1.0
- mockery/mockery: 1.3.*|1.3.*|1.3.*|1.4.x-dev|1.4.x-dev|1.4.2
- orchestra/database: v3.7.0|v3.8.0|v4.0.0|v5.0.0|v6.x-dev
- orchestra/testbench: 3.7.*|3.8.*|4.*|5.*|^6.0|^6.6.0
- phpunit/phpunit: 6.*|7.0.*|7.5|8.3|8.5|9.3
- dev-master
- 3.0.0
- 2.5.7
- 2.5.6
- 2.5.4
- 2.5.3
- 2.5.2
- 2.5.1
- 2.5.0
- 2.4.8
- 2.4.6
- 2.4.5
- 2.4.4
- 2.4.3
- 2.4.2
- 2.4.1
- 2.4.0
- 2.3.9
- 2.3.8
- 2.3.7
- 2.3.5
- 2.3.2
- 2.3.0
- 2.2.5
- 2.2.1
- 2.1.9
- 2.1.5
- 2.1.0
- 2.0.9
- 2.0.0
- 1.6.9
- 1.6.7.x-dev
- 1.6.7
- 1.6.5.x-dev
- 1.6.5
- 1.6.2
- 1.6.0.x-dev
- 1.6.0
- 1.5.8
- 1.5.7
- 1.5.6
- 1.5.5
- 1.5.3.x-dev
- 1.5.3
- 1.5.2.x-dev
- 1.5.2
- 1.5.1.x-dev
- 1.5.1
- 1.5.0.x-dev
- 1.5.0
- 1.4.3
- 1.4.2
- 1.4.1.x-dev
- 1.4.1
- 1.4.0
- 1.3.2
- 1.3.0
- 1.1.9
- 1.1.8
- 1.1.7
- 1.1.6
- 1.1.5
- 1.1.4
- 1.1.3
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.2
- 1.0.1
- 1.0.0
- dev-support_laravel_9
- dev-revert-187-master
- dev-laravel-9
- dev-v-2.4
- dev-analysis-BMaQOr
- dev-analysis-jLboA2
- dev-analysis-d0bvPj
- dev-analysis-nNwZ00
- dev-analysis-QMJD3Z
- dev-analysis-5ZnoAj
- dev-analysis-yvBJrG
- dev-analysis-QMy14w
- dev-analysis-64Y11P
- dev-analysis-64YDd6
- dev-analysis-aj1pyZ
- dev-analysis-m4RDBV
- dev-analysis-0gxgnW
- dev-analysis-m43AaV
- dev-analysis-VrkmpB
- dev-analysis-L3kKOn
- dev-analysis-9m1295
- dev-analysis-YjdPkY
- dev-analysis-64lRQo
- dev-analysis-nNG5jv
- dev-analysis-4xQVwN
- dev-analysis-ajG51o
- dev-analysis-bQ2D2w
- dev-analysis-64lm9M
- dev-v-2.3
- dev-analysis-e7kOa7
- dev-analysis-m46eME
- dev-analysis-4x61je
- dev-analysis-0gDjvw
- dev-analysis-rdMpE3
- dev-analysis-WN3pxN
- dev-analysis-ZlBKpg
- dev-analysis-M1Nr52
- dev-analysis-jLMBrZ
- dev-analysis-ajE5l7
- dev-analysis-wj5Qk9
- dev-analysis-BMQP9L
- dev-analysis-L3xWAk
- dev-analysis-kayoD4
- dev-analysis-Yj0wJy
- dev-v-2
- dev-analysis-ZlrB6Y
- dev-analysis-BMxxr7
- dev-analysis-0gKymM
- dev-analysis-7aQA56
- dev-analysis-4xRmon
- dev-analysis-646w2W
- dev-analysis-7aQW56
- dev-analysis-d0WMNJ
- dev-analysis-jLWBbZ
- dev-analysis-J2J97v
- dev-analysis-YjQ2eo
- dev-analysis-L3ol5n
- dev-analysis-YjMw9A
- dev-analysis-gOeoB1
- dev-analysis-0gAA5j
- dev-analysis-9mynDa
- dev-analysis-e7j7D2
- dev-analysis-2QvelB
- dev-analysis-wj0xnK
- dev-analysis-yvExnj
- dev-analysis-2Qv9gZ
- dev-analysis-rdEoOD
- dev-analysis-gO1Vnk
- dev-analysis-NApk94
- dev-analysis-WNl60e
- dev-analysis-4x7l6n
- dev-analysis-BMyb0W
- dev-mock-test-relation
- dev-analysis-VrY9l3
- dev-analysis-NADlve
- dev-mock-test
- dev-analysis-nNLR6g
- dev-analysis-5ZPy9x
- dev-analysis-3wWojA
- dev-mehdi-fathi-patch-1
- dev-mehdi-travic-ci
- dev-analysis-Px5ZNP
- dev-analysis-Vrjnl6
- dev-mehdi-dev
- dev-analysis-ajVmmB
- dev-analysis-KZoo76
- dev-mehdi-fathi-working-4
- dev-analysis-q1Vobv
- dev-analysis-8AZ3Dl
- dev-analysis-qyyvdN
- dev-analysis-8A0Vw9
- dev-analysis-Xk1bxJ
- dev-analysis-zYGJR9
- dev-analysis-8bw3e2
- dev-analysis-XaPGJo
- dev-analysis-8mQ51V
- dev-analysis-zerKYP
- dev-analysis-86WAgl
- dev-analysis-z922wP
- dev-analysis-8LWdA6
- dev-analysis-qMmmnl
- dev-analysis-qvAA4x
- dev-mehdi-fathi-working-2
- dev-analysis-zRB9wp
- dev-analysis-XZV7JD
- dev-analysis-XkGPe1
- dev-analysis-zOwneB
- dev-analysis-XWOeZP
- dev-mehdi-fathi-working
- dev-analysis-XZV7eg
- dev-analysis-zEZawD
- dev-revert-2-master
- dev-add-stickler-config
This package is not auto-updated.
Last update: 2024-11-13 21:42:53 UTC
README
Eloquent Filter adds custom filters to your Eloquent Models in Laravel. It's easy to use and fully dynamic.
Table of Content
Requirements
- PHP 7.2+, 8.0, 8.1 (new version)
- Laravel 5.8+,6.x,7.x,8.x,9.x(prefer-stable)
🎤 Introduction
Let's say we want to make an advanced search page with multiple filter option params.
A simple implementation without Eloquent Filter
The Request URI could look like this:
http://localhost:8000/users/index?age_more_than=25&gender=male&created_at=25-09-2019
And a simple implementation in the Controller would look like this:
<?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 $users->get(); } }
This solution is simple ,but that works fine. But you'd have to add a condition for each filter you need. Especially with more complex filtering, your code can become a Monster very fast! 💥
A simple implementation with Eloquent Filter
Eloquent Filter can help you to fix that problem. Just you will set query string to work with that. It will save you time and minimize the complexity of your code.
After installing Eloquent Filter the request URI could look like this:
http://localhost:8000/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'd just need that one line:
/** * Class UsersController. */ namespace App\Http\Controllers; use App\User; class UsersController { public function list() { return User::filter()->get(); } }
With this Eloquent filter implementation, you can use all the documented filters!
🔌 Installation
1- Run this Composer command to install the latest version
$ composer require coliving/eloquent-filter
-
Note for Laravel versions older than 5.8 you should install version 2.2.5
$ composer require mehdi-fathi/eloquent-filter:2.2.5
2- Add eloquentFilter\ServiceProvider::class
to provider app.php
'providers' => [ /* * Package Service Providers... */ eloquentFilter\ServiceProvider::class ],
3- Add Facade 'EloquentFilter' => eloquentFilter\Facade\EloquentFilter::class
to aliases app.php
'alias' => [ /* * Facade alias... */ 'EloquentFilter' => eloquentFilter\Facade\EloquentFilter::class, ],
That's it enjoy! 💥
📖 Basic Usage
Config Model and set whitelist
Add The Filterable trait to your models and set fields that you will want to filter in the whitelist array. as well You can override this method in your models.
use eloquentFilter\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 aslike below example:
private static $whiteListFilter = ['*'];
You can add or set $whiteListFilter
on the fly in your method.For example:
Set array to WhiteListFilter
- Note This method override
$whiteListFilter
array
User::setWhiteListFilter(['name']);
Add new field to WhiteListFilter
User::addWhiteListFilter('name');
Use in Controller
Change your code the controller of the laravel project as like below example:
namespace App\Http\Controllers; /** * Class UsersController. */ class UsersController { public function list() { if (!empty(request()->get('username'))) { $users = User::ignoreRequest('perpage')->filter()->with('posts') ->orderByDesc('id')->paginate(request()->get('perpage'),['*'],'page'); } else { $users = User::filter( ['username' => ['mehdi','ali']] )->with('posts')->orderByDesc('id')->paginate(10,['*'],'page'); } } }
-Note The Eloquent Filter config by default uses the query string to make queries in Laravel.
Although, you can set the array to 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 of the request params by use of the bellow code.
User::ignoreRequest(['perpage']) ->filter() ->paginate(request()->get('perpage'), ['*'], 'page');
Call ignoreRequest
that will ignore some requests that you don't want to use in conditions eloquent filter.
For example, the perpage param will never be in the conditions eloquent filter.
it's related to the paginate method. page
param ignore by default in Eloquent Filter of Laravel.
- You can filter some of the request params for using in Eloquent Filter.
User::AcceptRequest(['username','id']) ->filter() ->paginate(request()->get('perpage'), ['*'], 'page');
Call AcceptRequest
will accept requests which you want to use in conditions Eloquent Filter.
For example username
and id
param will be in the conditions eloquent filter. Just notice you must set $whiteListFilter
in Model. This method is useful for query string manipulation by a user.
- Another example use of a filter eloquent filter.
User::filter()->paginate();
-
EloquentFilter::filterRequests()
get all params that used by the Eloquent Filter. You can set key to get specific index. For exampleEloquentFilter::filterRequests('username')
it's getting username index. -
EloquentFilter::getAcceptedRequest()
get all params that set by the AcceptRequest method. -
EloquentFilter::getIgnoredRequest()
get all ignored params that set by the getIgnoreRequest method.
Simple Examples
You just pass data blade form to query string or generate query string in the Controller method. For example:
Simple Where
/users/list?email=mehdifathi.developer@gmail.com
SELECT ... WHERE ... email = 'mehdifathi.developer@gmail.com'
/users/list?first_name=mehdi&last_name=fathi
SELECT ... WHERE ... first_name = 'mehdi' AND last_name = 'fathi'
Where In
This example make method whereIn
.
/users/list?username[]=ali&username[]=ali22&family=ahmadi
SELECT ... WHERE ... username in ('ali','ali22') AND family = 'ahmadi'
OrWhere (New feature 🔥)
This example make method orWhere
.
/users/list?name=mehdi&username=fathi&or[username]=ali
SELECT ... WHERE ... name = 'mehdi' AND username = 'fathi' or username = 'ali'
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]=%John%
SELECT ... WHERE ... first_name LIKE '%John%'
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]=ali
SELECT ... WHERE ... username != 'ali'
/users/list?count_posts[operator]=<&count_posts[value]=25
SELECT ... WHERE ... count_posts < 25
Where the nested relation Model (New feature 🔥)
You can set all nested relation in the query string just by the array of query string. For example, 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_post' and 'posts.orders.name' in the User model.
use eloquentFilter\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=mehdi
select * from "users" where exists
(select * from "posts" where "posts"."user_id" = "users"."id"
and "posts"."count_post" = 876)
and "username" = "mehdi"
- The above example is the same code that you use without the eloquent filter. Check it under code.
$user = new User(); $builder = $user->with('posts'); $builder->whereHas('posts', function ($q) { $q->where('count_post', 876); })->where('username','mehdi');
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=mehdi
select * from "users" where exists
(select * from "posts" where
"posts"."category" in ('php','laravel','jquery') )
and "username" = "mehdi"
Special Params
You can set special params limit
and orderBy
in the query string to make a query by that.
/users/list?f_params[limit]=1
SELECT ... WHERE ... order by `id` desc limit 1 offset 0
/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
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[]=ali&username[]=mehdi&family=ahmadi&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 ('ali', 'mehdi') and
`family` = ahmadi 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
Eloquent Filter doesn't support all of 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 run the command to make a trait and use it on the model:
php artisan eloquentFilter: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 sample_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', ]; }
Custom Detection Condition
Sometimes you want to make your custom condition to make a new query that Eloquent Filter doesn't support that by default. The good news is you can make a custom condition in the eloquent filter from now on.
You can make conditions to generate a new query after checking by that. (New feature 🔥 ). For example :
We must have two classes. The First detects conditions second class generates the query.
- Step 1: Create a class to detect some of the conditions
use eloquentFilter\QueryFilter\Detection\DetectorContract; /** * Class WhereRelationLikeCondition. */ class WhereRelationLikeCondition implements DetectorContract { /** * @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: After that create a class to generate a query. In this example we make
WhereRelationLikeConditionQuery
class:
use eloquentFilter\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
EloquentFilterCustomDetection
for return array detections of the condition in the model.
use eloquentFilter\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
WhereRelationLikeCondition
for 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]=mehdi&username[limit]=10&username[email]=mehdifathi&username[like_relation_value]=mehdi&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.
-Note Also 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. for example:
class User extends Model { use Filterable; public function EloquentFilterCustomDetection(): array { return [ WhereRelationLikeCondition::class, WhereRelationLikeVersion2Condition::class, WhereRelationLikeVersion3Condition::class, ]; } }
EloquentFilter::getInjectedDetections()
gets all of your customs injected detection.
-Note Every custom detection will run before any detections by default eloquent filter.
Configuring
You can generate a config file to configure Eloquent Filter.
Publish Config
php artisan vendor:publish --provider="eloquentFilter\ServiceProvider"
Config
-
You can disable/enable Eloquent Filter in the config file (eloquentFilter.php).
'enabled' => env('EloquentFilter_ENABLED', true),
-
Eloquent Filter recognizes every param of the queries string. Maybe you have a query string that you don't want to recognize by Eloquent Filter. You can use
ignoreRequest
for his purpose. But we have a clean solution to this problem. You can set paramrequest_filter_key
in the config file. Therefore every query string will recognize by therequest_filter_key
param.'request_filter_key' => '', // filter
For example, if you set 'request_filter_key' => 'filter',
that Eloquent Filter recognizes filter
query string.
/users/list?filter[email]=mehdifathi.developer@gmail.com
-
You can disable/enable all of the custom detection of Eloquent Filter in the config file (eloquentFilter.php).
'enabled_custom_detection' => env('EloquentFilter_Custom_Detection_ENABLED', true),
-
You should set the index array in
ignore_request
to ignore by in all filters.'ignore_request' => [] //[ 'show_query','new_trend' ],
Magic Methods
Magic methods are a collection of methods that you can use as a wrapper in the Eloquent Filter.
For example, serialize data before filtering or changing data in response and others.
Now Eloquent Filter have serializeRequestFilter
,ResponseFilter
.
Request Filter
Eloquent Filter 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; 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 Eloquent Filter.
That is a practical method when you want to set user_id or convert date or remove space and others.
Response Filter
Response Filter is a magic method for just changing response after handling by Eloquent Filter. The method called
ResponseFilter
You should implement the method ResponseFilter
in your Model. For example
class User extends Model { use Filterable; public function ResponseFilter($response) { $data['data'] = $response; return $data; } }
- If you have any idea about the Eloquent Filter, I will be glad to hear that.