All Projects → aldemeery → Sieve

aldemeery / Sieve

Licence: mit
A simple, clean and elegant way to filter Eloquent models.

Projects that are alternatives of or similar to Sieve

Searchable
Search/filter functionality for Laravel's Eloquent models
Stars: ✭ 113 (-8.13%)
Mutual labels:  eloquent, laravel, filter
Lara Eye
Filter your Query\Builder using a structured query language
Stars: ✭ 39 (-68.29%)
Mutual labels:  eloquent, laravel, filter
Eloquent Filter
This simple package helps you filter Eloquent data using query filters.
Stars: ✭ 24 (-80.49%)
Mutual labels:  eloquent, laravel, filter
Eloquentfilter
An Eloquent Way To Filter Laravel Models And Their Relationships
Stars: ✭ 1,113 (+804.88%)
Mutual labels:  eloquent, laravel, filter
Requent
A GraphQL like interface to map a request to eloquent query with data transformation for Laravel.
Stars: ✭ 78 (-36.59%)
Mutual labels:  eloquent, laravel
Laravel Schedulable
Schedule and unschedule eloquent models elegantly without cron jobs
Stars: ✭ 78 (-36.59%)
Mutual labels:  eloquent, laravel
Laravel Approvable
Easily add an approval process to any laravel model.
Stars: ✭ 79 (-35.77%)
Mutual labels:  eloquent, laravel
Laravel Prefixed Ids
Friendly prefixed IDs for Laravel models
Stars: ✭ 88 (-28.46%)
Mutual labels:  eloquent, laravel
Eloquent Settings
Eloquent Settings allows you to bind key-value pairs to any Laravel Eloquent model. It supports even casting for boolean, float or integer types.
Stars: ✭ 71 (-42.28%)
Mutual labels:  eloquent, laravel
Flattable
It helps you manage de-normalized tables
Stars: ✭ 81 (-34.15%)
Mutual labels:  eloquent, laravel
Laravel Likeable
Rate Eloquent models with Likes and Dislikes in Laravel. Development moved to Laravel Love package!
Stars: ✭ 95 (-22.76%)
Mutual labels:  eloquent, laravel
Laravel Lucene Search
Laravel 4.2, 5.* package for full-text search over Eloquent models based on ZF2 Lucene.
Stars: ✭ 75 (-39.02%)
Mutual labels:  eloquent, laravel
Laravel Ownership
Laravel Ownership simplify management of Eloquent model's owner.
Stars: ✭ 71 (-42.28%)
Mutual labels:  eloquent, laravel
Eloquent Approval
Approval process for Laravel Eloquent models
Stars: ✭ 79 (-35.77%)
Mutual labels:  eloquent, laravel
Elasticquent
Maps Laravel Eloquent models to Elasticsearch types
Stars: ✭ 1,172 (+852.85%)
Mutual labels:  eloquent, laravel
Laravel Nullable Fields
Handles saving empty fields as null for Eloquent models
Stars: ✭ 88 (-28.46%)
Mutual labels:  eloquent, laravel
Guardian
Eloquent Guardian is a simple permissions system for your users. While there are many other packages for permissions, this one solves everything in the most eloquent way.
Stars: ✭ 121 (-1.63%)
Mutual labels:  eloquent, laravel
Laravel Translatable
Making Eloquent models translatable
Stars: ✭ 1,390 (+1030.08%)
Mutual labels:  eloquent, laravel
Laravel Settings
Store key value pair in database as settings
Stars: ✭ 107 (-13.01%)
Mutual labels:  eloquent, laravel
Watchable
Enable users to watch various models in your application.
Stars: ✭ 65 (-47.15%)
Mutual labels:  eloquent, laravel

Sieve - Clean & Easy Eloquent Filtration

Build Status Total Downloads Latest Stable Version License

This package allows you to filter retrieved records based on query string values.

Once installed filtration shrinks down from this:

public function index(Request $request)
{
    $query = Product::query();

    if ($request->has('color')) {
        $query->where('color', $request->get('color'));
    }

    if ($request->has('condition')) {
        $query->where('condition', $request->get('condition'));
    }

    if ($request->has('price')) {
        $direction = $request->get('price') === 'highest' ? 'desc' : 'asc';
        $query->orderBy('price', $direction);
    }

    return $query->get();
}

to this:

public function index(Request $request)
{
    return Product::filter($request)->get();
}

Installation

This package can be used in Laravel 5.8 or higher. You can install the package via composer:

composer require aldemeery/sieve

The service provider will automatically get registered. Or you may manually add the service provider in your config/app.php file:

'providers' => [
    // ...
    Aldemeery\Sieve\FiltersServiceProvider::class,
];

Usage

Enabling filtration for a model is as easy as adding the Aldemeery\Sieve\Concerns\Filterable trait to your model(s):

use Aldemeery\Sieve\Concerns\Filterable;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use Filterable;

    // ...
}

The Filterable trait adds a filter local scope to your model which accepts an instance of Illuminate\Htpp\Request so it can be used for filtration like this:

public function index(Request $request)
{
    return Product::filter($request)->get();
}

Once you have added the trait to your model, and used the filter method , you just need to start creating filters.

Creating filters

A filter class is a class that extends Aldemeery\Sieve\Filter.

You can manually create a filter class and place wherever you like, or use the make:filter artisan command to create a filter which will be placed inside app/Http/Filters directory.

php artisan make:filter Product/ColorFilter

This will typically create the following class:

<?php

namespace App\Http\Filters\Product;

use Aldemeery\Sieve\Filter;
use Illuminate\Database\Eloquent\Builder;

class ColorFilter extends Filter
{
    /**
     * Values mappings.
     *
     * @var array
     */
    protected $mappings = [
        // Silence is golden...
    ];

    /**
     * Filter records based on a given value.
     *
     * @param \Illuminate\Database\Eloquent\Builder $builder Eloquent builder instance.
     * @param string $value The resolved value of the filtration key sent in the query string.
     *
     * @return void
     */
    public function filter(Builder $builder, $value)
    {
        //
    }
}

The filter method inside a filter class, is where you should put your filtration logic. The $value parameter is holding the value passed in the query string for this specific filter key.

/**
 * Filter records based on a given value.
 *
 * @param \Illuminate\Database\Eloquent\Builder $builder Eloquent builder instance.
 * @param string $value The resolved value of the filtration key sent in the query string.
 *
 * @return void
 */
public function filter(Builder $builder, $value)
{
    // Assuming the URL is https://example.com/products?color=red
    // $value here is equal to 'red'

    return $builder->where('color', $value);
}

Note: the key 'color' in the above example is defined when you actually use the filter

Because you have an instance of Illuminate\Database\Eloquent\Builder, you have all of its power, which means you can do all different sorts of things:

  • Ordering
public function filter(Builder $builder, $value)
{
    return $builder->orderBy('price', $value);
}
  • Filtering by relations
public function filter(Builder $builder, $value)
{
    return $builder->whereHas('category', function($query) use ($value){
        return $query->where('name', $value);
    });
}

Mappings

Sometimes you might want to use more meaningful values for your query string keys, however these values could be different from the values you actually need for filtration, this is where the $mappings comes to help.

You can define your values mappings in the $mappings array , and they will be automatically resolved before being passed to the filter method, keep reading...

Example: Let's assume you would like to order a list of products by their price, and you don't want to have: ..?price=asc or ..?price=desc in your URL, instead you would like to have something like: ..?price=lowest or ..?price=highest

to achieve this you have the following filter class:

<?php

namespace App\Http\Filters\Product;

use Aldemeery\Sieve\Filter;
use Illuminate\Database\Eloquent\Builder;

class ColorFilter extends Filter
{

    /**
     * Values mappings.
     *
     * @var array
     */
    protected $mappings = [
        'lowest' => 'asc',
        'highest' => 'desc',
    ];

    /**
     * Filter records based on a given value.
     *
     * @param \Illuminate\Database\Eloquent\Builder $builder Eloquent builder instance.
     * @param string $value The resolved value of the filtration key sent in the query string.
     *
     * @return void
     */
    public function filter(Builder $builder, $value)
    {
        // URL: https://example.com/products?price=lowest

        // $value is automatically set to be 'asc' instead of 'lowest'
        if ($this->validateValue($value)) {
            $builder->orderBy('price', $value);
        }
    }

    /**
     * Determine if a given value is valid.
     *
     * @param string $value Value to validate.
     *
     * @return bool
     */
    private validateValue($value)
    {
        return in_array($value, ['asc', 'desc']);
    }
}

Using "individual" filters

Once you have created your filter and defined your filtration logic, It's time now to actually use the filter, which can be done in three ways:

Passing a filters array to filter:

Use this when you want to apply a filter to a single query:

public function index(Request $request)
{
    return Product::filter($request,[
        // "color" here is the key to be used in the query string
        // e.g. https://example.com/products?color=red
        "color" => \App\Http\Filters\Product\ColorFilter::class,
    ])->get();
}

In the above example the filter will look for the value of the key color in the query string for this query only, and pass it to the filter method inside the filter class where you have put your filtration logic.

Defining model filters:

The Filterable trait providers a filters method that should return an array of "keys" and "filters" to be applied to the model every time the filter method is called.

<?php

namespace App;

use Aldemeery\Sieve\Concerns\Filterable;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use Filterable;

    /**
     * List of individual filters to be used by the model.
     *
     * @return array
     */
    protected function filters()
    {
        return [
            'color' => \App\Http\Filters\Product\ColorFilter::class,
        ];
    }
}

Now everytime you call the filter method on the model, you will have the ColorFilter applied on your query without passing any external arguments.

public function index(Request $request)
{
    // The ColorFilter is automatically applied.
    return Product::filter($request)->get();
}

Filter Bags

Sometimes you might have a large list of filters that is making your model look messy, or you might want to group a list of filters so you can share them between different models. This is when you want to have a filter bag.

A filter bag is a class that extends Aldemeery\Sieve\FilterBag and contains an array of filters that are always applied together.

Again you can manually create your filter bag class and place it wherever you like, or use the make:filter-bag command to create a filter bag class that is placed inside the app\Http\Filters directory.

php artisan make:filter-bag Product/ProductFilters

This will typically create the following class:

<?php

namespace App\Http\Filters\Product;

use Aldemeery\Sieve\FilterBag;

class ProductFilters extends FilterBag
{
    /**
     * Filters to be applied.
     *
     * @var array
     */
    protected static $filters = [
        //
    ];
}

Again, put your "key" and "filter" pairs inside the $filters array:

/**
 * Filters to be applied.
 *
 * @var array
 */
protected static $filters = [
    'color' => \App\Http\Filters\Product\ColorFilter::class,
    'condition' => \App\Http\Filters\Product\UsedFilter::class,
    'q' => \App\Http\Filters\Product\NameFilter::class,
    't' => \App\Http\Filters\TrashedFilter::class,
];

And once you have done that, you just need to override the filterBag method from the Filterable trait inside your model, to return which filter bag should be used.

<?php

namespace App;

use Aldemeery\Sieve\Concerns\Filterable;
use App\Http\Filters\Product\ProductFilters;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use Filterable;

    /**
     * Filter bag used by the model.
     *
     * @return string
     */
    protected function filterBags()
    {
        return [
            ProductFilters::class,
        ];
    }
}

Now everytime the filter method is called on the model, all the filters inside the ProductFilters will be applied.

public function index(Request $request)
{
    // The filters from ProductFilters are automatically applied.
    return Product::filter($request)->get();
}

License

The MIT License (MIT). Please see License File for more information.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].