SkillAgentSearch skills...

Filterable

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

Install / Use

/learn @Thavarshan/Filterable
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Filterable

About Filterable

Latest Version on Packagist Tests Lint CodeQL PHPStan PHP Version License Total Downloads GitHub Stars

Filterable is a Laravel package for turning HTTP request parameters into rich, composable Eloquent query filters. The base Filter class exposes a stateful pipeline that you can extend, toggle, and compose with traits to add validation, caching, logging, rate limiting, memory management, and more. Everything is opt-in, so you enable only the behaviour you need while keeping type-safe, testable filters.

Requirements

  • PHP 8.3, 8.4, or 8.5
  • Laravel 11.x, 12.x, or 13.x components (illuminate/cache, illuminate/contracts, illuminate/database, illuminate/http, illuminate/support)
  • A configured cache store when you enable caching features
  • A PSR-3 logger when you enable logging (optional)

Installation & Setup

composer require jerome/filterable

Package auto-discovery registers the FilterableServiceProvider, which contextual-binds the current Request into resolved filters and exposes the make:filter Artisan command. Publish the configuration to set global feature defaults, cache behaviour, or runtime options:

php artisan vendor:publish --tag=filterable-config

Stubs live under src/Filterable/Console/stubs/ and can be overridden by placing copies in your application's stubs directory.

Highlights

  • Publishable configuration (config/filterable.php) to set default feature bundles, runtime options, and cache TTLs that the base filter reads during construction.
  • Stateful lifecycle with apply, get, runQuery, reset, rich debug output via getDebugInfo(), lifecycle events (FilterApplying, FilterApplied, FilterFailed), and configurable exception handling.
  • Opt-in concerns for validation, permissions, rate limiting, caching (with heuristics), logging, performance metrics, query optimisation, memory management, value transformation, and fluent filter chaining.
  • Drop-in Filterable Eloquent scope trait so any model can accept a filter instance.
  • Smart caching that builds deterministic cache keys, supports tags, memoises counts, and can decide automatically when to cache complex queries.
  • Contextual binding in FilterableServiceProvider makes sure container-resolved filters receive the current HTTP Request; injecting a cache repository or PSR-3 logger auto-enables the relevant features.
  • Memory-friendly helpers (lazy, stream, streamGenerator, lazyEach, cursor, chunk, map, filter, reduce) when the memoryManagement feature is enabled.
  • First-party Artisan generator with --basic, --model, and --force options to rapidly scaffold filters.

Repository Layout

  • src/Filterable/Filter.php – abstract base class orchestrating the filter lifecycle and feature toggles.
  • src/Filterable/Concerns/ – traits implementing discrete behaviour (filter discovery, validation, caching, logging, performance, optimisation, rate limiting, etc.).
  • src/Filterable/Contracts/ – interfaces for the filter pipeline and the Eloquent scope signature.
  • src/Filterable/Traits/Filterable.php – model scope that forwards to a Filter instance.
  • src/Filterable/Console/MakeFilterCommand.php & src/Filterable/Console/stubs/ – Artisan generator and overrideable stub templates.
  • src/Filterable/Providers/FilterableServiceProvider.php – registers the package and console command via spatie/laravel-package-tools.
  • bin/ – executable scripts executed by the Composer lint, fix, and test commands.
  • tests/ – Orchestra Testbench suite with concern-focused tests and reusable fixtures in tests/Fixtures/.
  • assets/ – shared media used in documentation.
  • config/filterable.php – publishable defaults for feature toggles, cache TTL, and runtime options.
  • database/factories/ – reserved for additional factories should you extend the package.

Quick Start

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'));.

Lifecycle & Core API

  • apply(Builder $builder, ?array $options = []) binds the filter to a query, merges options, runs enabled concerns, and transitions the state from initializedapplyingapplied. Re-applying without reset() raises a RuntimeException.
  • get() returns an Illuminate\Support\Collection of results, delegating to caching or memory-managed helpers when those features are active. runQuery() is a convenience wrapper for apply() + get().
  • count() respects smart caching (including tagged caches and memoised counts when enabled). toSql() exposes the raw SQL for debugging.
  • enableFeature(), enableFeatures(), disableFeature(), hasFeature() toggle concerns per instance; defaults may be set in config/filterable.php and are applied in the constructor.
  • setOption(), setOptions() persist runtime flags (for example chunk_size, use_chunking) that concerns such as OptimizesQueries and ManagesMemory consume.
  • reset() returns the filter to the initialized state so it can be applied again. getDebugInfo() surfaces state, filters applied, options, SQL/bindings, and metrics.

Feature Guides & API

Validation & Value Transformation

  • Enable with enableFeature('validation') and configure with setValidationRules(), addValidationRule(), and setValidationMessages().
View on GitHub
GitHub Stars192
CategoryData
Updated12d ago
Forks10

Languages

PHP

Security Score

100/100

Audited on Mar 19, 2026

No findings