From laravel-api-tool-kit
Adds filtering, sorting, search to existing model list endpoint: detects structure, creates/binds filter class, populates filters, updates controller.
How this command is triggered — by the user, by Claude, or both
Slash command
/laravel-api-tool-kit:add-filterlaravel-api-tool-kit/workflows/The summary Claude sees in its command listing — used to decide when to auto-load this command
# Workflow: Add Filtering to an Existing Model
Use this when an existing model needs filtering, sorting, or search added to its list endpoint.
---
## Step 0 — Detect Project Structure
- `Domain/` present → **DDD**: filters live in `app/Domain/{Model}/Filters/{Model}Filters.php`
- No `Domain/` → **Standard**: filters live in `app/Filters/{Model}Filters.php`
Check the existing model file to confirm — it will have `protected string $default_filters = ...` pointing to the correct namespace if a filter already exists.
---
## Step 1 — Check if a Filter class already exists
Standard: loo...Use this when an existing model needs filtering, sorting, or search added to its list endpoint.
ls app/
Domain/ present → DDD: filters live in app/Domain/{Model}/Filters/{Model}Filters.phpDomain/ → Standard: filters live in app/Filters/{Model}Filters.phpCheck the existing model file to confirm — it will have protected string $default_filters = ... pointing to the correct namespace if a filter already exists.
Standard: look for app/Filters/{Model}Filters.php
DDD: look for app/Domain/{Model}/Filters/{Model}Filters.php
Follow rules/filters.md for the correct structure.
Standard: app/Filters/CarFilters.php
DDD: app/Domain/Car/Filters/CarFilters.php
Open the Model and ensure:
use App\Filters\CarFilters;
use Essa\APIToolKit\Filters\Filterable;
class Car extends Model
{
use Filterable;
protected string $default_filters = CarFilters::class;
}
Both use Filterable and protected string $default_filters are required.
Based on the requirement, fill in the appropriate arrays:
Add equality filters (?color=red&is_active=1):
protected array $allowedFilters = ['color', 'is_active', 'user_id'];
Add sort columns (?sorts=name or ?sorts=-created_at):
protected array $allowedSorts = ['name', 'created_at'];
Add eager-load includes (?includes=user,tags):
protected array $allowedIncludes = ['user', 'tags'];
Add text search columns (?search=keyword):
protected array $columnSearch = ['name', 'description'];
Add relationship search (?search=keyword):
protected array $relationSearch = [
'user' => ['first_name', 'last_name'],
];
Add a custom filter for non-trivial conditions:
// ?year=2023
public function year(string $term): void
{
$this->builder->whereYear('manufactured_at', $term);
}
Open the controller's index method and replace any manual query building with:
public function index(): AnonymousResourceCollection
{
return CarResource::collection(Car::useFilters()->dynamicPaginate());
}
Do NOT hardcode ->with(['user', 'tags']) here if those relationships are in $allowedIncludes. The client requests them via ?includes=user,tags and the filter class handles eager loading automatically. Hardcoding with() always loads relations even when not needed.
Filterable trait is on the model$default_filters is bound on the model$allowedFilters / $allowedSorts are populateduseFilters()->dynamicPaginate() — not ->get() or ->paginate()$this->builder — they return nothingnpx claudepluginhub ahmedesa/laravel-api-tool-kit/tableGenerates FilamentPHP v4 table configurations with columns, filters, search, sorting, row/bulk actions from a description. Supports --resource ResourceName [--for widget|relation-manager].
/laravel-api-resourcesImplements Laravel API Resources with pagination by exactly following the laravel:api-resources-and-pagination skill.
/laravelBuilds, configures, and optimizes Laravel apps with Eloquent models, service layers, queues, events, broadcasting, Sanctum/Passport auth, and Pest tests. Supports API, auth, queue, model gen, optimization, upgrade, audit flags.