Skip to content

Commit 9e467a9

Browse files
committed
Add lifecycle events, streaming helpers, and integration test
1 parent 35d4a35 commit 9e467a9

34 files changed

Lines changed: 2640 additions & 1914 deletions

.github/copilot-instructions.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copilot Coding Guidelines
2+
3+
## Domain Context
4+
- This package centres on the abstract `Filter` class in `src/Filterable/Filter.php`, extended by application-specific filters that receive an `Illuminate\Http\Request`.
5+
- Optional behaviour (validation, caching, logging, rate limiting, memory optimisation, etc.) is implemented via traits in `src/Filterable/Concerns/`; Copilot-generated code must compose with these traits instead of duplicating logic.
6+
- Eloquent models opt into filtering by using `Filterable\Traits\Filterable`; Artesian generator stubs live in `src/Filterable/Console/stubs/`.
7+
8+
## Coding Rules
9+
- Follow PSR-12: four-space indentation, trailing commas in multi-line arrays, strict type hints, and ordered imports.
10+
- Prefer fluent APIs and immutable-looking helpers; expose feature toggles via `$this->enableFeature()` rather than bespoke flags.
11+
- When adding new filter methods, camelCase the method name to match the request key (`status``status()`), or map via `$filterMethodMap`.
12+
- Respect existing caches and logging patterns by reusing helpers (`buildCacheKey()`, `logInfo()`); do not access the logger or cache container directly.
13+
- Keep public APIs typed and documented; add succinct docblocks if behaviour is non-obvious (e.g. transforms, rate limits).
14+
15+
## Testing Expectations
16+
- Every new concern or feature flag should be covered by PHPUnit tests under `tests/`, using Orchestra Testbench.
17+
- Mock collaborators (cache, logger, rate limiter) with Mockery, and assert on state using `getDebugInfo()` or dedicated getters.
18+
- Provide happy-path, edge, and failure tests—mirror patterns from existing concern tests like `CachingTest.php` or `HandlesRateLimitingTest.php`.
19+
20+
## Anti-Patterns to Avoid
21+
- Do not re-run `apply()` on the same filter without calling `reset()`.
22+
- Avoid duplicating concern logic directly inside filters; extend or compose existing traits instead.
23+
- Do not introduce framework-specific globals (`request()`, `auth()`) inside reusable traits—inject dependencies through the constructor or method parameters.
24+
- Refrain from adding commands or scripts outside the `bin/` directory or Composer scripts without project-owner approval.

.phpvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
8.2
1+
8.4

AGENTS.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Repository Guidelines
2+
3+
## Project Structure & Module Organization
4+
5+
Source code lives under `src/Filterable/`, centred around the abstract `Filter` base class and trait-based “concerns” under `src/Filterable/Concerns/`. Contracts and Eloquent helpers are in `src/Filterable/Contracts/` and `src/Filterable/Traits/`. The Artisan generator and stubs are in `src/Filterable/Console/`. Executable tooling scripts are stored in `bin/`, shared media in `assets/`, and tests (plus fixtures) in `tests/`, which boot an Orchestra Testbench environment. Composer already maps `Filterable\\` and the testing namespaces; place any new factories inside `database/factories` to maintain autoloading.
6+
7+
## Build, Test, and Development Commands
8+
9+
Run `composer install` to hydrate dependencies, then rely on the Composer scripts: `composer lint` (delegates to `bin/lint.sh` for Duster + syntax checks), `composer fix` (formats via Pint/Duster and saves a log), and `composer test` (wraps `bin/test.sh` which accepts flags such as `--filter=HandlesRateLimitingTest`, `--coverage`, `--parallel`, or `--test=tests/HandlesFilterablesTest.php`). When adding commands, keep the scripts directory executable (`chmod +x bin/*.sh`).
10+
11+
## Coding Style & Naming Conventions
12+
13+
Code follows PSR-12 with four-space indentation enforced by Pint/Duster. Match namespaces to paths (`Filterable\\Concerns\\OptimizesQueries`, etc.) and stick to the existing naming patterns: suffix traits with the capability (`ManagesMemory`), concrete filters with `Filter`, and console commands under `Console`. Keep feature toggles (`$features`) and options arrays cohesive—extend the existing map rather than inventing new flags. Prefer expressive method-level docblocks when behaviour is subtle (e.g. cache key generation), otherwise lean on descriptive naming.
14+
15+
## Testing Guidelines
16+
17+
The suite is PHPUnit-based (`phpunit.xml.dist`) and runs inside Orchestra Testbench. Follow the established pattern of placing concern-specific tests at the project root (e.g. `CachingTest.php`, `HandlesRateLimitingTest.php`) and keep reusable doubles under `tests/Fixtures/`. Use partial mocks for collaborators (cache, logger, rate limiter) and prefer data providers or inline anonymous filters for edge cases. Generate coverage with `./bin/test.sh --coverage --filter=Namespace\\Class` before shipping complex features, and assert on state via `getDebugInfo()` when relevant.
18+
19+
## Commit & Pull Request Guidelines
20+
21+
Commits should be short, imperative sentences (`Add smart caching heuristic`, `Tighten rate limit checks`). Keep behavioural, formatting, and tooling changes in separate commits where practical. In pull requests, outline the capability touched (e.g. “Adds new trait”, “Updates generator stub”), document any newly enabled features or config knobs, and list verification commands (`composer lint`, `composer test`, extra manual checks). Surface breaking changes or migrations explicitly and attach debug output or SQL snippets if they inform reviewers.

CHANGELOG.md

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
11
# Release Notes
22

3-
## [Unreleased](https://github.com/Thavarshan/filterable/compare/v2.0.1...HEAD)
3+
## [Unreleased](https://github.com/Thavarshan/filterable/compare/v2.1.0...HEAD)
4+
5+
## [v2.1.0](https://github.com/Thavarshan/filterable/compare/v2.0.1...v2.1.0) - 2025-10-14
6+
7+
### Added
8+
9+
- Publishable configuration defaults (`config/filterable.php`) now seed feature toggles, runtime options, and cache TTLs automatically during filter construction.
10+
- New lifecycle events (`FilterApplying`, `FilterApplied`, `FilterFailed`) fire around `apply()` so listeners can plug into telemetry, metrics, or alerts without overriding the base class.
11+
- Streaming helpers (`stream()`, `streamGenerator()`) expose LazyCollection and generator pipelines for truly memory-safe traversal.
12+
- Rate limiting hooks allow filters to override default attempt counts, windows, and decay values per request.
13+
- Added an end-to-end integration test covering filtering, caching, streaming, and lifecycle signals against the in-memory Testbench harness.
14+
15+
### Changed
16+
17+
- Rate limiter keys incorporate the authenticated user identifier (when provided via `forUser()`), reducing collisions across shared IPs.
18+
- Memory management now streams results under the hood before materialising them during `get()` when enabled.
19+
- Documentation refreshed to surface lifecycle events, streaming helpers, rate limiting overrides, and configuration presets.
20+
21+
### Fixed
22+
23+
- Prevents rate limiter collisions with richer key composition and hookable decay windows.
24+
- Ensures streaming helpers respect the filter lifecycle by requiring `apply()` before invocation.
425

526
## [v2.0.1](https://github.com/Thavarshan/filterable/compare/v2.0.0...v2.0.1) - 2025-05-14
627

@@ -21,7 +42,7 @@
2142
- References the GitHub issue number for traceability
2243
- Includes the exact error message for users who might be searching for a solution
2344

24-
**Full Changelog**: https://github.com/Thavarshan/filterable/compare/2.0.0...2.0.1
45+
**Full Changelog**: <https://github.com/Thavarshan/filterable/compare/2.0.0...2.0.1>
2546

2647
## [v2.0.0](https://github.com/Thavarshan/filterable/compare/v1.2.0...v2.0.0) - 2025-05-13
2748

@@ -143,7 +164,6 @@
143164
- **Updated development dependencies:**
144165
- `phpunit/phpunit` from `^9.0` to `^10.1` for advanced unit testing capabilities.
145166
- `vimeo/psalm` from `5.0.0` to `5.16.0` for improved static analysis and code quality checks.
146-
147167

148168
### Fixed
149169

@@ -158,7 +178,6 @@
158178
- **Integration with `Psr\Log\LoggerInterface`**: Ensured flexibility in logging implementations by integrating with the standard PSR-3 logger interface. Developers can now inject any compatible logging library that adheres to this standard, facilitating customized logging strategies.
159179
- **Conditional Log Statements**: Added conditional logging throughout the filter application process to provide granular insights into key actions and decisions. This feature is designed to help in pinpointing issues and understanding filter behavior under various conditions.
160180
- **Unit Tests for Logging**: Extended the test suite to include tests verifying that logging behaves as expected under different configurations, ensuring that the new functionality is robust and reliable.
161-
162181

163182
### Changed
164183

CLAUDE.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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.

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2024 Jerome Thayananthajothy <tjthavarshan@gmail.com>
3+
Copyright (c) 2024-2025 Jerome Thayananthajothy <tjthavarshan@gmail.com>
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

0 commit comments

Comments
 (0)