Laravel-Advanced-Filter
                                
                                 Laravel-Advanced-Filter copied to clipboard
                                
                                    Laravel-Advanced-Filter copied to clipboard
                            
                            
                            
                        Laravel Advanced Filter
Laravel Advanced Filter
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