Introduce Eloquent Filter 2 in Laravel

Mehdi Fathi
5 min readJun 12, 2020

Introduction

Have you ever experienced make an advanced search page in programming? if your answer is yes maybe you know this feature has many conditions to make a query database. Especially when you are using a relational DB as MySQL in your project at that time our task will get hard. I was searching for it. Eventually, I found a clean way to implement this feature in the Laravel project. The Eloquent Filter version 2 is the only stable solution for laravel project.

What’s the main problem?

The main problem is that you will make many conditions for every situation. Writing a lot of terms will surely reduce the readability of your code and increase the possibility of making a mistake.

Practical example:

Suppose we want to get the list of the users with the requested parameters as in laravel follows:

//GET users/search?age_more_than=25&gender=male&created_at=25-09-2019

The Request parameter will be as follows:

[ 
'age_more_than' => '25',
'gender' => 'male',
'created_at' => '25-09-2019',
]
Implement this feature in UsersController

We check out a condition for each request.

In the future, if your project will need more filter requests at that time you should add many conditions to the above code. Imagine some of the queries may be advanced therefore your code to be like Monster!

Discover away

Everything began from just a tutorial video called `Eloquent Techniques` in largest. It was about a new way to make an advanced filter through the use of the query string. It has to separate layer filters from the controller and model. It made an Eloquent query by the use of the query string. Advanced Eloquent rescued the readability of your code by a filter class. It was very good but you had to make a method for every condition. It’s boring for creative developers. You don’t have a dynamic query and you have to write many methods for per condition just in the separated layer.

Eloquent Filter is your solution

Imagine you will install a package composer and make queries by query string without write where for every condition. Actually, you just enter query string according to the principles of that package. Therefore the package will make every condition by the query string. If you want to write a custom query in a separate layer you can do it. You can set fields of your model to allow build queries by the query string. Note that the query string must be sync with the fields of your Model. Isn’t great in your opinion !?. This package saves your time and your code. Fortunately, like package eloquent-filter is rare in GitHub.

Installation

Run the Composer command

$ composer require mehdi-fathi/eloquent-filter

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,
],

Just this the Elqouent Filter is ready for use.

Basic Usage

Add Filterable trait to your models and set fields that you will want to filter in the whitelist. You can override this method in your models.

User model

You can set * char for filter in all fields as like below example:

private static $whiteListFilter = ['*'];

Use in Controller

Change your code on the controller as like below example:

UserV2Controller.php
  • Note that the Eloquent Filter in laravel by default using the query string to make queries. Also, you can set the array to filter method Model for making your own custom condition without query string.
  • Note that you must unset your own param as the `perpage`. Just you can set page param for paginating this param ignore from the filter.

You can ignore some of the request params by use of code it.

User::ignoreRequest(['perpage'])->filter()
->paginate(request()->get('perpage'), ['*'], 'page');

Call ignoreRequest will ignore some requests that you don't want to use in conditions eloquent filter. For example, `perpage` param will never be in the conditions eloquent filter. it's related to the paginate method. page param ignore by default in the Eloquent filter.

  • Another example use of a filter eloquent filter.

User::filter()->paginate();

Done it!

Simple Example

You just pass the data blade form to a query string or generate a query string in the controller method. For example:

Simple Where

/users/list?email=mehdifathi.developer@gmail.comSELECT ... WHERE ... email = 'mehdifathi.developer@gmail.com'/users/list?first_name=mehdi&last_name=fathiSELECT ... WHERE ... first_name = 'mehdi' AND last_name = 'fathi'/users/list?username[]=ali&username[]=ali22&family=ahmadiSELECT ... WHERE ... username = 'ali' OR username = 'ali22' AND family = 'ahmadi'

Whereby operator

You can set any operator MySQL in the query string.

/users/list?count_posts[operator]=>&count_posts[value]=35SELECT ... WHERE ... count_posts > 35/users/list?username[operator]=!=&username[value]=aliSELECT ... WHERE ... username != 'ali'/users/list?count_posts[operator]=<&count_posts[value]=25SELECT ... WHERE ... count_posts < 25

Where the nested relation Model (New feature version 2 🔥)

You can set all nested relations in the query string just by the array query string. For example, the user model has a relation with posts. and posts table has a relation with orders. 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.

/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 as 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');

Special Parameters

You can set special parameters limit and orderBy in the query string for make query by that.

/users/list?f_params[limit]=1SELECT ... WHERE ... order by `id` desc limit 1 offset 0/users/list?f_params[orderBy][field]=id&f_params[orderBy][type]=ASCSELECT ... WHERE ... order by `id` ASC limit 10 offset 0

Where between

If you are going to make a query whereBetween. You must fill in keys start and end in the query string. you can set it on query string as you know.

/users/list?created_at[start]=2016/05/01&created_at[end]=2017/10/01SELECT ... 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

Just note that fields of query string be the same rows table database in $whiteListFilter your model or declare a method in your model as the override method. The overriding method can be considered a custom query filter.

Custom query filter

If you are going to make yourself a query filter you can do it easily. You just make a trait and use it on the model:

Note that fields of query string be the same methods of the trait. Use a trait in your model:

/users/list?username_like=aselect * from `users` where `username` like %a% order by `id` desc limit 10 offset 0

You can make every filter with eloquent-filter.

For more details check out GitHub repository

You can make every filter with eloquent-filter. If you think the eloquent-filter is useful so give a ⭐️ to that by click on the link

Good luck and thank you for sharing your valuable time with me. I hope the Eloquent Filter is useful for your code. If you have any idea or opinion I glade to know it.

--

--