kettasoft/filterable
Composer 安装命令:
composer require kettasoft/filterable
包简介
A powerful Laravel package for advanced Eloquent query filtering using dedicated filter classes, multiple engines, and clean HTTP request mapping.
README 文档
README
Filterable
A powerful and flexible Laravel package for advanced, clean, and scalable filtering of Eloquent models using multiple customizable engines.
Why Filterable?
Most filtering packages give you one approach and expect you to fit your problem around it. Filterable works the other way — you pick the engine that matches how your frontend sends data, and the package handles the rest.
It ships with four production-ready engines, a full caching system, per-filter authorization, validation, sanitization, sorting, a CLI, and an event system — all while keeping your controllers clean and your filter logic organized and testable.
Installation
composer require kettasoft/filterable
php artisan vendor:publish --provider="Kettasoft\Filterable\Providers\FilterableServiceProvider" --tag="config"
Add the following line to the providers array in config/app.php or bootstrap/providers.php:
'providers' => [ ... Kettasoft\Filterable\Providers\FilterableServiceProvider::class, ];
Quick Start
1. Create a filter class
php artisan filterable:make-filter PostFilter --filters=title,status
2. Define your filters
namespace App\Http\Filters; use Kettasoft\Filterable\Filterable; use Kettasoft\Filterable\Support\Payload; class PostFilter extends Filterable { protected $filters = ['status', 'title']; protected function title(Payload $payload) { return $this->builder->where('title', 'like', $payload->asLike('both')); } protected function status(Payload $payload) { return $this->builder->where('status', $payload->value); } }
3. Apply in your controller
$posts = Post::filter(PostFilter::class)->paginate();
4. Or bind the filter directly to the model
class Post extends Model { use HasFilterable; protected $filterable = PostFilter::class; } // Now just: $posts = Post::filter()->paginate();
Choosing an Engine
Each engine is designed for a different filtering style. Pick the one that fits your use case — or mix and match across different models.
| Engine | Best For | Example Request |
|---|---|---|
| Invokable | Custom logic per field, method-per-filter pattern | ?status=active&title=laravel |
| Ruleset | Clean key/operator/value API queries | ?filter[title][like]=laravel&filter[views][gte]=100 |
| Expression | Ruleset-style + filtering through nested relations | ?filter[author.profile.name][like]=ahmed |
| Tree | Complex AND/OR nested logic sent as JSON | { "and": [{ "field": "status", ... }] } |
Invokable Engine
Map request keys to methods automatically. Add PHP 8 annotations for per-method sanitization, casting, validation, and authorization with zero boilerplate.
class PostFilter extends Filterable { protected $filters = ['status', 'created_at']; #[Cast('integer')] #[DefaultValue(1)] protected function status(Payload $payload) { ... } #[SkipIf('auth()->guest()')] #[Between(min: '2020-01-01', max: 'now')] protected function created_at(Payload $payload) { ... } }
Available annotations: #[Authorize] #[SkipIf] #[Cast] #[Sanitize] #[Trim] #[DefaultValue] #[MapValue] #[Explode] #[Required] #[In] #[Between] #[Regex] #[Scope]
Ruleset Engine
Flat field-operator-value format, ideal for REST APIs where the frontend controls which operator to use.
GET /posts?filter[status]=published
GET /posts?filter[title][like]=%laravel%
GET /posts?filter[views][gte]=100
GET /posts?filter[id][in][]=1&filter[id][in][]=2
Supported operators: eq neq gt gte lt lte like nlike in between
Expression Engine
Everything Ruleset does, plus filtering through deep Eloquent relationships using dot notation.
GET /posts?filter[author.profile.name][like]=ahmed
Filterable::create() ->useEngine('expression') ->allowedFields(['status', 'title']) ->allowRelations(['author.profile' => ['name']]) ->paginate();
Tree Engine
Send a nested AND/OR JSON tree — the engine recursively translates it into Eloquent where / orWhere groups.
{
"filter": {
"and": [
{ "field": "status", "operator": "eq", "value": "active" },
{
"or": [
{ "field": "age", "operator": "gt", "value": 25 },
{ "field": "city", "operator": "eq", "value": "Cairo" }
]
}
]
}
}
Supports depth limiting, strict operator whitelisting, and normalized field keys.
Features
Caching
A complete caching system built into the filter pipeline — not bolted on after the fact.
// Cache for 1 hour Post::filter()->cache(3600)->get(); // User-scoped cache (each user gets their own) Post::filter()->cache(1800)->scopeByUser()->get(); // Tenant-isolated cache Product::filter()->cache(3600)->scopeByTenant(tenant()->id)->get(); // Conditional cache Model::filter()->cacheWhen(!auth()->user()->isAdmin(), 3600)->get(); // Tagged cache with easy invalidation Post::filter()->cache(3600)->cacheTags(['posts', 'content'])->get(); Post::flushCacheByTagsStatic(['posts']); // Reusable profiles defined in config Report::filter()->cacheProfile('heavy_reports')->get();
Auto-invalidation: configure models and tags in config/filterable.php and caches are cleared automatically on create/update/delete.
Authorization
Protect entire filter classes based on roles or permissions.
class AdminFilter extends Filterable { public function authorize(): bool { return auth()->user()?->isSuperAdmin() ?? false; } }
Per-method authorization is also available via the #[Authorize] annotation in the Invokable engine.
Validation & Sanitization
Validation rules and sanitizers are defined directly on the filter class — input is cleaned and validated before any filtering logic runs.
Validation uses Laravel's native rules format via a $rules property:
class PostFilter extends Filterable { protected $rules = [ 'status' => ['required', 'string', 'in:active,pending,archived'], 'title' => ['sometimes', 'string', 'max:32'], ]; }
If validation fails, a ValidationException is thrown automatically —
no extra handling needed in your controller.
Sanitization runs before validation, via dedicated sanitizer classes:
class PostFilter extends Filterable { protected $sanitizers = [ TrimSanitizer::class, // global — applies to all fields 'title' => [ StripTagsSanitizer::class, CapitalizeSanitizer::class, ], ]; }
A sanitizer is a simple class implementing the Sanitizable interface:
class TrimSanitizer implements Sanitizable { public function sanitize(mixed $value): mixed { return is_string($value) ? trim($value) : $value; } }
The execution order is always: sanitize → validate → filter.
Sorting
Built-in sorting support with allowed-field whitelisting.
class PostFilter extends Filterable { protected $sortable = ['created_at', 'views', 'title']; } // GET /posts?sort=-created_at (descending) // GET /posts?sort=views (ascending)
Event System
Hook into the filter lifecycle to add logging, metrics, or custom behavior.
// Fired before filters are applied Event::listen(FilterApplying::class, fn($e) => Log::info('Filtering '.$e->model)); // Fired after filters are applied Event::listen(FilterApplied::class, fn($e) => $metrics->record($e));
Profile Management & Profiler
Save and reuse filter configurations, and inspect exactly what queries each filter generates.
Lifecycle Hooks
initially() and finally() hooks let you modify the query builder before or after filtering runs.
CLI
# Generate a new filter class with interactive setup php artisan filterable:setup PostFilter # Discover and auto-register all filter classes in your app php artisan filterable:discover # List all registered filters php artisan filterable:list # Test a filter class with a sample data string (key=value pairs) php artisan filterable:test {filter} --model=User --data="status=active,age=30" # Inspect a filter class (engines, fields, rules, etc.) php artisan filterable:inspect PostFilter
Requirements
- PHP 8.1+
- Laravel 10.x or higher
- Redis or Memcached recommended for tagged caching
📚 Documentation
For full documentation, installation, and usage examples, visit: kettasoft.github.io/filterable
Contributing
Found a bug or want to add an engine? PRs are welcome — please open an issue first to discuss.
License
MIT © 2024-present Kettasoft
kettasoft/filterable 适用场景与选型建议
kettasoft/filterable 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 76 次下载、GitHub Stars 达 39, 最近一次更新时间为 2023 年 06 月 12 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「search」 「filter」 「query」 「model」 「laravel」 「eloquent」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 kettasoft/filterable 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 kettasoft/filterable 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 kettasoft/filterable 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
A Laravel package to retrieve data from Google Search Console
Nova searchable filter for belongsTo relationships.
Indexed Search Autocomplete - Extends the TYPO3 Core Extension Indexed_Search searchform with an autocomplete feature.
Query filtering in your frontend
Abstraction Layer to index and search entities
Anax Database Active Record module for model classes.
统计信息
- 总下载量: 76
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 40
- 点击次数: 13
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2023-06-12
