Introduce Eloquent Filter 3. x new features in Laravel
Have you ever done a task in which you were supposed to make a lot of queries with advanced options such as combining many conditions like a report page or search page?
Implement Some tasks are like a Jenga game. If your code is not thought-out at the first place, you will face problem.
If you said yes presumably, You know how faced a lot of troubles when you want to implement these kinds of features, which is why Eloquent Filter in Laravel has been developed in recent years and aims to evolve more and more. If you would like to know basically about this package, You had better check it out here or you can see GitHub.
In short, this package is able to generate a bunch of complex queries based on input which can be a query string or an array on Laravel. For instance :
/users/list?email=mehdifathi.developer@gmail.com
SELECT ... WHERE ... email = 'mehdifathi.developer@gmail.com'
In the first place, you should install this 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,
],
That’s it enjoy! I want to introduce some new features that have been done lately.
Custom Detection Conditions
Sometimes you want to make your custom condition to make a new query that Eloquent Filter 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 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 eloquentFilter\QueryFilter\Detection\Contract\DetectorConditionsContract;
/**
* Class WhereRelationLikeCondition.
*/
class WhereRelationLikeCondition implements DetectorConditionsContract
{
/**
* @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
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 the method EloquentFilterCustomDetection
in the above example and return the 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 the code User::filter();
to see the result.
Model::setLoadInjectedDetection(false)
: You can deactivate custom detection conditions on the fly.
-you can set custom detection on the fly by use of the method SetCustomDetection
. For example :
$users = User::SetCustomDetection([WhereRelationLikeCondition::class])->filter();
-You can disable EloquentFilterCustomDetection
on the fly by this code :
User::SetLoadDefaultDetection(false)->filter();
-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,
];
}
}
EloquentFilter::getInjectedDetections()
gets all of your customs injected detection.- 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 query string. Maybe you have a query string that you don’t want to recognize by Eloquent Filter. You can use
ignoreRequest
it for his purpose. But we have a clean solution to this problem. You can set the 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 will recognize filter
query string.
/users/list?filter[email]=mehdifathi.developer@gmail.com
- You can disable/enable all the custom detection of Eloquent Filter in the config file (eloquentFilter.php).
'enabled_custom_detection' => env('EloquentFilter_Custom_Detection_ENABLED', true),
- You should set an index array
ignore_request
to 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
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.
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 the eloquent filter. This method is SerializeRequestFilter. You just implement a method called SerializeRequestFilter
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 an overriding method for changing response right after handling by Eloquent Filter. The method is 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;
}
}
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 the request side, we need this feature on the 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 it on the Model layer as well.
black_list_detections
array is used for this purpose.
<?php
namespace Tests\Models;
use eloquentFilter\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 the builder to check either query using eloquent-filter.
-getDetectionsInjected
is a macro method to get a 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