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

We'd Love Your Feedback

Tell us what you like or what we can improve

Feel free to share anything you like or dislike about this page or the platform in general.