Skip to main content
Back to packages
195 GitHub stars

Thavarshan/filterable

View on GitHub

Description

Enhance Laravel queries with adaptable, customisable filters and intelligent caching to improve both performance and functionality.

1. Generate a filter

php artisan make:filter PostFilter --model=Post

--model wires the stub to your Eloquent model. Use --basic for an empty shell or --force to overwrite an existing class.

2. Implement filtering logic

<?php
 
namespace App\Filters;
 
use Filterable\Filter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Validation\Rule;
 
class PostFilter extends Filter
{
/**
* Request keys that map straight to filter methods.
*
* Methods follow camelCased versions of the keys (e.g. published_after → publishedAfter).
*/
protected array $filters = ['status', 'published_after', 'q'];
 
public function __construct(Request $request)
{
parent::__construct($request);
 
$this->enableFeatures([
'validation',
'optimization',
'filterChaining',
'valueTransformation',
]);
 
$this->setValidationRules([
'status' => ['nullable', Rule::in(['draft', 'published'])],
'published_after' => ['nullable', 'date'],
]);
 
$this->registerTransformer('published_after', fn ($value) => Carbon::parse($value));
$this->registerPreFilters(fn (Builder $query) => $query->where('is_visible', true));
$this->select(['id', 'title', 'status', 'published_at'])->with('author');
}
 
protected function status(string $value): void
{
$this->getBuilder()->where('status', $value);
}
 
protected function publishedAfter(Carbon $date): void
{
$this->getBuilder()->whereDate('published_at', '>=', $date);
}
 
protected function q(string $term): void
{
$this->getBuilder()->where(function (Builder $query) use ($term) {
$query->where('title', 'like', "%{$term}%")
->orWhere('body', 'like', "%{$term}%");
});
}
}

Define protected array $filterMethodMap when you need to alias request keys to method names. Programmatic filters can be appended with appendFilterable('key', $value) before apply() runs. Supplying an Illuminate\Contracts\Cache\Repository or Psr\Log\LoggerInterface to the constructor immediately enables the caching and logging features.

3. Attach the scope to a model

<?php
 
namespace App\Models;
 
use Filterable\Traits\Filterable;
use Illuminate\Database\Eloquent\Model;
 
class Post extends Model
{
use Filterable;
}

4. Run the filter pipeline

<?php
 
namespace App\Http\Controllers;
 
use App\Filters\PostFilter;
use App\Http\Resources\PostResource;
use App\Models\Post;
use Illuminate\Http\Request;
 
class PostController
{
public function index(Request $request, PostFilter $filter)
{
$posts = Post::query()
->filter(
$filter
->forUser($request->user())
->enableFeature('caching')
->setOptions(['chunk_size' => 500])
)
->get();
 
return PostResource::collection($posts);
}
}

apply() may only be called once per instance; call reset() if you need to reuse a filter. Because the Filter base class uses Laravel's Conditionable trait, you can use helpers such as $filter->when($request->boolean('validate'), fn ($filter) => $filter->enableFeature('validation'));.

Recent Courses on Laravel Daily