Eloquent Filters

Suggest edit

Introduction

Eloquent Filters are powerful tools for creating complex queries in Laravel. They allow you to easily manage and customize your search criteria. You can use Eloquent filters to filter your product catalog based on attributes, brands, and other criteria.

To create a new Eloquent filter, you can use the php artisan orchid:filter command followed by the desired filter name. This command will generate a new filter class in the app/Orchid/Filters folder.

Here’s an example of creating an EmailFilter:

php artisan orchid:filter EmailFilter

The generated filter class will look like this:

namespace App\Http\Filters;

use Orchid\Filters\Filter;
use Illuminate\Database\Eloquent\Builder;

class EmailFilter extends Filter
{
    /**
     * The array of matched parameters.
     *
     * @var array
     */
    public $parameters = ['email'];

    /**
     * Apply filter if the request parameters were satisfied.
     * 
     * @param Builder $builder
     *
     * @return Builder
     */
    public function run(Builder $builder): Builder
    {
        return $builder->where('email', $this->request->get('email'));
    }

    /**
     * Get the display fields.
     *
     * @return Field[]
     */
    public function display(): array
    {
        return [
            Input::make('email')
                ->type('text')
                ->value($this->request->get('email'))
                ->placeholder('Search...')
                ->title('Search')
        ];
    }
}

To use filters in your own models, you need to connect the trait Orchid\Filters\Filterable and pass an array of classes to the filtersApply function:

use App\Model;

Model::filters([EmailFilter::class])->simplePaginate();

Using Filters for Different Models

One of the great advantages of filters is that you can reuse the same filter class for different models. This allows you to define a filter once and apply it to multiple models, reducing code duplication. Simply specify the filter class when applying filters to your models:

User::filters([EmailFilter::class])->simplePaginate();

Customer::filters([EmailFilter::class])->simplePaginate();

Running the Filter Always

By default, filters are applied only when the corresponding parameters are specified. However, if you want a filter to run on every request, you can leave the $parameters property as an empty array in your filter class. This way, the filter will be applied to all queries. For instance:

public $parameters = [];

Parameter Patterns

Filter provides the capability to define parameter patterns using a convenient syntax. This allows you to create custom patterns and perform advanced filtering based on specific patterns. For example:

/**
 * The array of matched parameters.
 *
 * @var null|array
 */
public $parameters = [
    'pattern.*',
];

In the above example, the filter will match any parameter that follows the pattern pattern.*. This allows you to handle a wide range of dynamic parameters in your filters.

Selection

The “Selection” layer provides a convenient way to group and organize filters for both displaying and applying them to a model. This layer acts as an intermediary between the user interface and the model, simplifying the process of managing filters.

To create a “Selection” layer, you can use the following command:

php artisan orchid:selection MailingSelection

This command will generate a new PHP file called MailingSelection in the App\Orchid\Layouts directory. Inside this class, you will find a single method called filters(). This method is where you should list all the filters that need to be displayed and applied.

For example, let’s say you want to display and apply two filters: a email filter and a created filter. Your MailingSelection class would look like this:

namespace App\Orchid\Layouts;

use App\Orchid\Filters\EmailFilter;
use App\Orchid\Filters\CreatedFilter;
use Orchid\Screen\Layouts\Selection;

class MailingSelection extends Selection
{
    /**
     * @return Filter[]
     */
    public function filters(): array
    {
        return [
          EmailFilter::class,
          CreatedFilter::class
        ];
    }
}

Once you have defined your filters in the MailingSelection class, you can apply them to a model by using the filters() method. For example:

Model::filters(MailingSelection::class)->simplePaginate();

By calling the filters() method on your model and passing MailingSelection::class as the argument, you can apply the filters defined in the MailingSelection class to the model.

Displaying on a Screen

The “Selection” layer can also be used to display filters on a screen. In the layout() method of your screen, you can include the MailingSelection class to display the filters on the screen. For example:

use App\Orchid\Layouts\MailingSelection;

public function layout(): array
{
    return [
        MailingSelection::class,
    ];
}

Please note that filters with empty fields will not be rendered, ensuring a clean and user-friendly interface.

Automatic HTTP Filtering and Sorting

To automatically filter and sort your application’s data based on user-supplied HTTP parameters, package provides a powerful and flexible set of tools. The key to using these tools effectively is to ensure that your model includes the Filterable trait, and implements a whitelist of acceptable filter and sort parameters.

For example, here’s how you might set up an App\Models\Post model to be filterable:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Orchid\Filters\Filterable;
use Orchid\Filters\Types\Like;
use Orchid\Filters\Types\Where;
use Orchid\Filters\Types\WhereDate;
use Orchid\Filters\Types\WhereMaxMin;
use Orchid\Filters\Types\WhereDateStartEnd;

class Post extends Model
{
    use Filterable;

    /**
     * @var array
     */
    protected $allowedFilters = [
        'id'            => Where::class,
        'user_id'       => WhereIn::class,
        'rating'        => WhereMaxMin::class,
        'content'       => Like::class,
        'publish_at'    => WhereDate::class,
        'created_at'    => WhereDateStartEnd::class,
        'deleted_at'    => WhereDateStartEnd::class,
    ];

    /**
     * @var array
     */
    protected $allowedSorts = [
        'id',
        'user_id',
        'rating',
        'publish_at',
        'created_at',
        'deleted_at',
    ];
}

Once your model is properly configured, using the filter and sort functionality is as simple as a method call to filters(), like so:

Post::filters()->defaultSort('id')->paginate();

This code will automatically apply any filters or sorting rules that were included in the user’s HTTP request.

In order to use this feature effectively, it’s important to have a solid understanding of how the HTTP parameters are translated into database queries. For example:

http://example.com/demo?filter[id]=1
$model->where('id', '=', 1)

This query will apply a where clause to the id column of your model, filtering out any records that don’t match the value provided by the user.

http://example.com/demo?filter[name]=A
$model->where('name', 'like', '%A%')

This query will apply a like clause to the name column of your model, searching for any records that contain the letter “A” in their name.

http://example.com/demo?filter[id]=1,2,3,4,5
$model->whereIn('id', [1,2,3,4,5]);

This query will apply a wherein clause to the id column of your model, filtering for any records that match one of the specified IDs.

http://example.com/demo?filter[id][min]=1&filter[id][max]=5
$model->whereBetween('id', [1,5]);

This query will apply a wherebetween clause to the id column of your model, filtering for records where the ID is between 1 and 5.

http://example.com/demo?filter[id][]=1&filter[id][]=2&filter[id][]=3
$model->whereIn('id', [1,2,3]);

This query will apply a whereIn clause to the id column of your model, filtering for records where the ID is one of the specified values.

http://example.com/demo?filter[rating][min]=1&filter[rating][max]=5
$model->where('rating', '>=', 1)
    ->where('rating', '<=', 5);

This query will apply two separate where clauses to the rating column of your model, filtering for records where the rating is between 1 and 5.

http://example.com/demo?filter[rating][min]=1
$model->where('rating', '>=', 1);

This query will apply a single where clause to the rating column of your model, filtering for records where the rating is greater than or equal to 1.

http://example.com/demo?filter[publish_at]=2023-02-02
$model->where('publish_at', '2023-02-02')

This query will apply a single where clause to the publish_at column of your model, filtering for records where the publish_at date is exactly equal to February 2, 2023.

http://example.com/demo?filter[created_at][start]=2023-01-01&filter[created_at][end]=2023-02-02
$model->whereDate('created_at', '>=', '2023-01-01')
    ->whereDate('created_at', '<=', '2023-02-02');

This query will apply two separate whereDate clauses to the created_at column of your model, filtering for records where the created_at date falls within the specified range.

http://example.com/demo?filter[created_at][start]=2023-01-01
$model->whereDate('created_at', '>=', '2023-01-01')

This query will apply a single whereDate clause to the created_at column of your model, filtering for records where the created_at date is greater than or equal to January 1, 2023.

HTTP filters or sorting do not have separate display templates. You can see an example of this use in the table headers.