ite/filtration-bundle
ITE FiltrationBundle is a Symfony bundle that adds configurable filtering to Doctrine entity queries. Define text, choice, date, boolean, and relation filters, then apply them to query builders to build dynamic search forms and listings with minimal setup.
Architecture fit — misfiled, and that is the first finding. The request frames this as a Laravel/PHP package; the artifact is a Symfony bundle built on the Symfony DI container and Doctrine. Its integration seam is a Bundle registration class, service definitions, and (typically) annotation-driven filter configuration on Doctrine entities. Laravel has no bundle/container-tag equivalent, so every integration point is manual. Worse, its data layer target is Doctrine’s QueryBuilder and ArrayCollection, not Eloquent or the Laravel query builder. Unless the application already runs laravel-doctrine — a minority configuration — the package’s core value (translate a filter request into a query) never touches our persistence layer. Assessed against our stack, the architecture fit is effectively zero without a port.
What it actually does, and why that matters more than the package. Stripped of the Symfony plumbing, the idea is a declarative filter definition — a whitelist of fields with per-field operators, a sort allowlist, and a pagination envelope — applied uniformly to in-memory collections and to database queries. That dual-source capability is the genuinely interesting part: identical filter definitions in tests (in-memory) and production (database). It is also a pattern, not an implementation, and the implementation behind it is replaceable. A TPM should record the pattern as the durable artifact and treat the repository as a specification.
Integration feasibility — low. Adoption would require: (1) a Doctrine entity/DBAL layer to filter against; (2) reconstructing the filter service graph by hand in Laravel’s container; (3) replacing any Twig-based pagination rendering with Blade/JSON; (4) re-implementing request-to-filter-definition parsing that the bundle inherits from Symfony’s request and config plumbing. That is a rewrite wearing an install, not a dependency.
Technical risk — high and asymmetric.
QueryBuilder interpolation is a direct SQL-injection vector. I would not accept that from an unmaintained package without a full audit — at which point we have paid the cost of writing it ourselves.Key questions for the decision meeting.
ArrayCollection (in-memory) filtering, or only database-side? In-memory is trivial in-house; database-side carries the security and performance risk.Stack fit — none for Laravel; partial for legacy Symfony. On Laravel/Eloquent the honest recommendation is do not integrate. The equivalent capability is covered by maintained, Laravel-native packages (spatie/laravel-query-builder for whitelisted filter/sort/include parsing; lorisleiva/laravel-search-string for human-typed queries) that deliver the same feature set against Eloquent with an active security posture. On a legacy Symfony 3/Doctrine service the calculus shifts slightly — but 0 dependents still means we would be the first production user of an unmaintained bundle.
Migration path — reference implementation, not dependency. Sequence:
FilterDefinition (field → type/operators/allowed) and a ListQuery value object (filters, sorts, page). This contract is the durable artifact; whatever sits behind it is swappable.Compatibility. Budget explicitly for PHP floor, Doctrine ORM/DBAL major version, and the absent Symfony Bundle registration path. Any direct-install attempt should be timeboxed to a half-day Composer spike; on a modern Laravel stack, expect it to fail on constraints, and treat that failure as the decision rather than a puzzle to solve.
Sequencing. Resolve build-vs-buy before any sprint commitment. If the answer is “build,” it is a small, well-bounded internal package — roughly one to two engineer-weeks including tests — not a multi-month effort. If a product team has already prototyped against this bundle, plan a clean-room reimplementation and do not carry its code forward; carrying it forward means inheriting an audit burden with no upstream.
Maintenance. As a dependency: unacceptable. We would inherit an unmaintained codebase with no issue triage and no compatibility cadence, so every PHP or framework upgrade becomes our patch. As a vendored fork: acceptable only with a named internal owner, a pinned patch-series strategy, and an explicit sunset date written down at adoption.
Support. There is no support model — negligible release history, no maintainer responsiveness to plan against, no security disclosure process. Production incidents route to our on-call, not a vendor. That is a fine trade for code we wrote and a poor trade for code we adopted.
Scaling. Two caveats dominate. First, unindexed filter fields become full table scans the moment the UI exposes them; the field whitelist must be paired with an index review, not treated as a security allowlist alone. Second, ArrayCollection in-memory filtering does not scale — it loads the full result set into PHP memory per request, so any endpoint taking that path must be capped or eliminated before launch. LIMIT/OFFSET pagination also degrades on deep pages; plan keyset pagination for large tables.
Failure modes, ranked by likelihood.
Ramp-up. Low, and that is the trap. The API surface is small enough that one engineer integrates it in a day, which makes it easy to adopt well before anyone asks who owns it eighteen months later. The correct TPM posture is to redirect that effort: the problem — declarative, safe, server-driven list filtering with consistent URL and pagination semantics across admin, API, and exports — is genuinely worth a sprint. This specific artifact is not worth a dependency. Capture the pattern, own the code.
How can I help you explore Laravel packages today?