|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +Guidance for Claude Code on how to contribute safely and effectively to this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +Filterable is a Laravel package that converts HTTP request parameters into composable Eloquent query filters. The abstract `Filter` class in `src/Filterable/Filter.php` orchestrates the pipeline and delegates optional capabilities—validation, caching, logging, rate limiting, query optimisation, memory management, etc.—to traits in `src/Filterable/Concerns/`. Eloquent models opt in via `Filterable\Traits\Filterable`, and the `make:filter` Artisan command (with stubs in `src/Filterable/Console/stubs/`) scaffolds new filters. |
| 8 | + |
| 9 | +## Key Paths |
| 10 | + |
| 11 | +- `src/Filterable/Filter.php` – lifecycle (`apply`, `get`, `runQuery`, `reset`) and feature toggles. |
| 12 | +- `src/Filterable/Concerns/` – concern traits; enable them through `$this->enableFeature()`. |
| 13 | +- `src/Filterable/Contracts/` & `src/Filterable/Traits/` – interfaces and Eloquent integration. |
| 14 | +- `bin/` – executable scripts used by Composer (`lint.sh`, `fix.sh`, `test.sh`). |
| 15 | +- `tests/` – Orchestra Testbench suite with fixtures under `tests/Fixtures/`. |
| 16 | + |
| 17 | +## Development Workflow |
| 18 | + |
| 19 | +```bash |
| 20 | +composer install # install dependencies |
| 21 | +composer lint # run Duster + syntax checks via bin/lint.sh |
| 22 | +composer fix # apply Pint/Duster formatting (logs to file) |
| 23 | +composer test # run PHPUnit through bin/test.sh |
| 24 | + |
| 25 | +./bin/test.sh --filter=HandlesRateLimitingTest # focused tests |
| 26 | +./bin/test.sh --coverage # coverage (requires Xdebug) |
| 27 | +./bin/test.sh --parallel # parallel runs |
| 28 | +./bin/lint.sh --strict # non-zero exit on lint issues |
| 29 | +vendor/bin/phpstan analyse # static analysis (level max) |
| 30 | +``` |
| 31 | + |
| 32 | +`phpunit.xml.dist` defaults to a MySQL connection; provide compatible env vars or stub the driver locally when running the suite. |
| 33 | + |
| 34 | +## Architectural Notes |
| 35 | + |
| 36 | +- Filters transition through states (`initialized` → `applying` → `applied|failed`) and cannot be reused without `reset()`. |
| 37 | +- Constructor dependencies automatically enable features (`Cache` ⇒ `caching`, `LoggerInterface` ⇒ `logging`). |
| 38 | +- Request keys are mapped to camelCase methods via `HandlesFilterables`; override `$filterMethodMap` for custom naming. |
| 39 | +- `InteractsWithCache` builds deterministic cache keys by sorting/sanitising filterables and including user scope; `SmartCaching` augments this with tag support and heuristic caching. |
| 40 | +- `ManagesMemory` exposes `lazy()`, `chunk()`, `cursor()`, `map()`, `filter()`, `reduce()` for large result sets. |
| 41 | +- `SupportsFilterChaining` queues fluent query constraints that execute after request-driven filters. |
| 42 | + |
| 43 | +## Coding Conventions |
| 44 | + |
| 45 | +- Follow PSR-12 (four-space indent, ordered imports, trailing commas in multi-line arrays). |
| 46 | +- Keep namespaces aligned with directory structure (`Filterable\Concerns\InteractsWithCache`). |
| 47 | +- Expose new behaviour through feature flags instead of ad-hoc booleans; extend `$features` map when introducing traits. |
| 48 | +- Reuse logging helpers (`logInfo`, `logWarning`, etc.) rather than invoking the logger directly. |
| 49 | +- Document non-obvious logic (e.g. rate-limit calculations, cache-key overrides) with concise docblocks. |
| 50 | + |
| 51 | +## Testing Expectations |
| 52 | + |
| 53 | +- Mirror existing concern tests (e.g. `CachingTest.php`, `HandlesRateLimitingTest.php`) when adding features; use Mockery for collaborators. |
| 54 | +- Assert filter state via `getDebugInfo()` and ensure both success and failure paths are covered. |
| 55 | +- Strategies that touch caching, rate limiting, or performance should include tests for null users, permission-denied filters, and repeated runs. |
| 56 | +- Run `composer test` and, where relevant, `./bin/test.sh --coverage` before opening PRs. |
| 57 | + |
| 58 | +## Common Patterns |
| 59 | + |
| 60 | +### Creating a Filter |
| 61 | + |
| 62 | +```php |
| 63 | +class PostFilter extends Filter |
| 64 | +{ |
| 65 | + protected array $filters = ['status', 'published_at']; |
| 66 | + |
| 67 | + public function __construct(Request $request) |
| 68 | + { |
| 69 | + parent::__construct($request); |
| 70 | + |
| 71 | + $this->enableFeatures(['validation', 'caching', 'performance']); |
| 72 | + $this->setValidationRules([ |
| 73 | + 'status' => 'in:draft,published,archived', |
| 74 | + 'published_at' => 'date', |
| 75 | + ]); |
| 76 | + } |
| 77 | + |
| 78 | + protected function status(string $value): Builder |
| 79 | + { |
| 80 | + return $this->getBuilder()->where('status', $value); |
| 81 | + } |
| 82 | +} |
| 83 | +``` |
| 84 | + |
| 85 | +### Adding a Concern |
| 86 | + |
| 87 | +1. Create the trait in `src/Filterable/Concerns/YourTrait.php`. |
| 88 | +2. Add a feature flag (e.g. `'yourFeature' => false`) to `$features` in `Filter.php`. |
| 89 | +3. Include the trait in `Filter` and gate logic behind `hasFeature('yourFeature')`. |
| 90 | +4. Cover the behaviour with dedicated PHPUnit tests and update documentation (README/AGENTS). |
| 91 | + |
| 92 | +## Watch-outs |
| 93 | + |
| 94 | +- Never call `apply()` twice without `reset()`—the filter will throw. |
| 95 | +- Avoid using global helpers (`request()`, `auth()`) inside traits; rely on injected `Request` or explicit parameters. |
| 96 | +- Keep generator stubs in sync with new features when altering the base filter API. |
| 97 | +- Do not bypass concern helpers (e.g. building cache keys manually) unless overriding with documented alternatives. |
0 commit comments