asemalalami / laravel-advanced-filter
Laravel Advanced Filter
Installs: 792
Dependents: 0
Suggesters: 0
Security: 0
Stars: 32
Watchers: 2
Forks: 2
Open Issues: 0
Type:project
pkg:composer/asemalalami/laravel-advanced-filter
Requires
- ext-json: *
- illuminate/database: ^5.8|^6.0|^7.0|^8.0
- illuminate/support: ^5.8|^6.0|^7.0|^8.0
Requires (Dev)
- orchestra/testbench: 5.x-dev
- phpunit/phpunit: 8.5.x-dev
README
This package allows you to filter on laravel models
You can choose fields to filtering and customize its data-types, aliases and excepted operators, you can add/customize your request format, and you add new operators or overwrite the existed operators
Installation
You can install the package via composer:
composer require asemalalami/laravel-advanced-filter
The package will automatically register its service provider.
You can optionally publish the config file with:
php artisan vendor:publish --provider="AsemAlalami\LaravelAdvancedFilter\AdvancedFilterServiceProvider" --tag="config"
These default config file that will be published: Config File
Usage
- use
HasFiltertrait in the model - add fields in the implementation of the abstract function
setupFilter - call the
filterscope in your controller
class Order extends Model { use HasFilter; protected $casts = [ 'void' => 'boolean', ]; public function channel() { return $this->belongsTo(Channel::class); } public function orderLines() { return $this->hasMany(OrderLine::class); } public function setupFilter() { $this->addField('void'); // will cast to 'boolean' from the model casts $this->addField('total')->setDatatype('numeric'); $this->addFields(['source', 'subsource', 'order_date']); // field from relation $this->addFields(['channel.created_at' => 'channel_create'])->setDatatype('date'); $this->addField('orderLines.product.sku', 'product_sku'); // field from relation count $this->addCountField('orderLines'); // custom field (raw sql) $this->addCustomField('my_total', '(shipping_cost + subtotal)'); // enable general search $this->addGeneralSearch(['source', 'orderLines.product.sku'], 'startsWith'); } // customize field filter by custom scope public function scopeWhereSource(Builder $builder, Field $field, string $operator, $value, $conjunction = 'and') { if ($operator == 'Equal') { return $builder->where(function (Builder $builder) use ($value) { $builder->where('source', $value) ->orWhere('subsource', $value); }); } // default behavior return $builder->applyOperator($operator, $field, $value, $conjunction); } } ... class OrderController extends Controller { public function index() { return Order::filter()->paginate(); // you can pass your custom request } }
Query Format
Query format is the shape that you want to send your query(filters) in the request. the package support 3 formats, and you can create a new format.
-
json(default): the filters will send as json in the requestfilters=[{"field":"email","operator":"equal","value":"abc"}] -
array: the filters will send as array in the requestfilters[email][value]=abc&filters[email][operator]=equal -
separator: the filters will send as well as in thearrayformat, but separated by a separator(^default)the format sets with a separator symbol
separator:^filters^email^value=abc&filters^email^operator=equal
set the default query format in the config file
query_formatattribute
Create a new query format:
- create a new class and extends it from
QueryFormat:class MyFormat extends QueryFormat - implement the abstract function
formatthat returnsFilterRequestobject - add the class to the config file in
custom_query_formatattribute:'custom_query_format' => MyFormat::class,
Fields
Normal Field options:
-
field name is the column name
-
alias is the key that you want to send in the request
-
data-type: by default it set from model
casts, if you want to set custom data-type, usesetDatatype -
operators: the field will accept all operators unless you use
setExceptedOperatorsto exclude some operators -
a relational field: only set the field name by
.separatorchannel.name,channel.type.nameyou can define field name by
.separator, but you want to consider it as a non relational field by passfalseforinRelationparameter (used in NoSQL DB or join between tables)$this->addField('channels.name', 'channel_name', false);
-
customize a field query, you can make a scope for the field to customize the filter behavior. scope name must be combined 3 sections :
- scope
- the value of
prefix_scope_functionkey in config file (whereis the default) - field name(or relation name) for example
email
public function scopeWhereEmail(Builder $builder, Field $field, string $operator, $value, $conjunction = 'and')
you can customize a relational field by define the scope in the relation model OR define scope by relation name
OrderLine.php public function scopeWherePrice(Builder $builder, Field $field, string $operator, $value, $conjunction = 'and') OR Order.php public function scopeWhereOrderLines(Builder $builder, Field $field, string $operator, $value, $conjunction = 'and')
you can use
applyOperatorfunction to use the default behavior$builder->applyOperator($operator, $field, $value, $conjunction);
You can add fields to a model by using 4 functions:
addField(string $field, string $alias = null, ?bool $inRelation = null): by default alias value same as field name value$this->addField('total')->setDatatype('numeric');
addFields($fields): accept an array of field and aliases:$this->addFields(['created_at' => 'create_date', 'order_date'])->setDatatype('date');
addCountField(string $relation, string $alias = null, callable $callback = null): add a field from count of relation, use can customize the count query and alias(by default is concat relation name(snake case) and_count)$this->addCountField('orderLines'); $this->addCountField('orderLines', 'lines_count', function (Builder $builder) { $builder->where('quantity', '>', 1); });
addCustomField(string $alias, string $sqlRaw, $relation = null): add a field from raw sql query$this->addCustomField('my_total', '(`shipping_cost` + `subtotal`)'); $this->addCustomField('line_subtotal', '(`price` + `quantity`)', 'orderLines'); // inside "orderLines" relation
General Search
You can enable general search on some fields, and you can specify the operator (startsWith is the default operator)
$this->addGeneralSearch(['source', 'orderLines.product.sku'], 'startsWith');
Conjunction
Currently, the package support one conjunction between all fields
and | or, default conjunction attribute in the config file default_conjunction
Operators
The package has many operators, you can create new operators, and you can customize the operators aliases that you want to send in the request
- Equals (
=,equals) - NotEquals (
!=,notEquals) - GreaterThan (
>,greater) - GreaterThanOrEqual (
>=,greaterOrEqual) - LessThan (
<,less) - LessThanOrEqual (
<=,lessOrEqual) - In (
|,in) - NotIn (
!|,notIn) - Contains (
*,contains) - NotContains (
!*,notContains) - StartsWith (
^,startsWith) - NotStartsWith (
!^,notStartsWith) - EndsWith (
$,endsWith) - NotEndsWith (
!$,notEndsWith) - Between (
><,between)
Create a new Operator:
- create a new class and extends it from
Operator:class MyOperator extends Operator - implement the abstract function
applyandgetSqlOperator(used as a default sql operator for count and custom field) - add the class in the config file in
custom_operatorsattribute:'custom_operators' => [MyOperator::class => ['my-op', '*']],
Data Types:
- boolean
- date
- datetime
- numeric
- string