> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eloquentfiltering.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Filters

## Overview

This package provides the ability for you to create two different types of custom filters.

* [Field Filter](#field-filter).
* [Custom Filter](#custom-filter).

<Note>
  You must register your filter classes in the config file `eloquent-filtering.php`
</Note>

```php theme={null}
'custom_filters' => [
    YourCustomFilter::class,
],
```

## Field Filter

```bash theme={null}
php artisan make:eloquent-filter LowerCaseFilter --type=field
```

### Class

```php theme={null}
class LowerCaseFilter implements FilterMethod, Targetable
{
    use FieldFilter;

    public function __construct(
        protected string $value,
    ) {
    }

    /*
     * The unique identifier of the filter.
     */
    public static function type(): string
    {
        return '$lowercase';
    }

    /*
     * The format that the filter data must adhere to.
     * Defined as laravel validator rules.
     * On fail: throws MalformedFilterFormatException.
     */
    public static function format(): array
    {
        return [
            'value' => ['required', 'string'],
        ];
    }

    /*
     * Apply the filter logic.
     */
    public function apply(Builder $query): Builder
    {
        $target = $this->eloquentContext->qualifyColumn($this->target);

        return $query->where(
            DB::raw("LOWER({$target})"),
            strtolower($this->value)
        );
    }
}
```

### Usage

```php theme={null}
public function allowedFilters(): AllowedFilterList
{
    return Filter::only(
        Filter::field('name', ['$lowercase']),
    );
}
```

## Custom Filter

<Tip>
  Generally for use when there is no user specified target.
</Tip>

```bash theme={null}
php artisan make:eloquent-filter AdminFilter --type=custom
```

### Class

```php theme={null}
class AdminFilter implements FilterMethod
{
    use CustomFilter;

    /*
     * The unique identifier of the filter.
     */
    public static function type(): string
    {
        return '$admin';
    }

    /*
     * Apply the filter logic.
     */
    public function apply(Builder $query): Builder
    {
        return $query->where(
            $this->eloquentContext()->qualifyColumn('admin'),
            true
        );
    }
}
```

### Usage

```php theme={null}
public function allowedFilters(): AllowedFilterList
{
    return Filter::only(
        Filter::custom('$admin'),
    );
}
```

## Custom Filter Notes

### Format/Validation

To specify validation messages and attributes along with the rules, you may return a `IndexZer0\EloquentFiltering\Filter\Validation\ValidatorProvider` from the `::format()` method.

```php theme={null}
public static function format(): ValidatorProvider
{
    return ValidatorProvider::from([
        'value' => ['required', 'string'],
    ], [
        'string' => 'The :attribute must be a string.',
    ], [
        'value' => 'value attribute',
    ]);
}
```

### Modifiers

Adding modifiers to your custom filters is achieved by:

* Implement interface:
  * `IndexZer0\EloquentFiltering\Filter\Contracts\FilterMethod\Modifiable`
* Use trait:
  * `IndexZer0\EloquentFiltering\Filter\Traits\FilterMethod\Composables\HasModifiers`
* Define `supportedModifiers()` method on the filter class.
* Using `$this->hasModifier('modifier_name')` in the `apply()` implementation.

```php {4,7,11-14,18} theme={null}
class YourFilterWithModifiers implements
    FilterMethod,
    Targetable,
    Modifiable
{
    use FieldFilter;
    use HasModifiers;

    //...

    public static function supportedModifiers(): array
    {
        return ['special'];
    }

    public function apply(Builder $query): Builder
    {
        if ($this->hasModifier('special')) {
            // Perform your special logic.
        } else {
            // Perform your regular logic.
        }
    }

    //...
}
```

### Qualifying Columns

All `FilterMethod` classes have access to an `EloquentContext` object that allows you to `qualifyColumn` of the target.

* Use this method to ensure your query is prefixing the column name with the database table.

Benefits of using this method:

* Prevents ambiguous columns in queries where you're also joining to another table with the same column.
* Handles using the correct table name for `->pivot()` allowed field filters.

```php {4} theme={null}
public function apply(Builder $query): Builder
{
    return $query->where(
        $this->eloquentContext()->qualifyColumn($this->target),
        true
    );
}
```
