ruwork/filter-bundle
Symfony bundle that integrates the RuWork filter component, letting you define reusable filters and apply them to Doctrine queries from request parameters. It provides bundle configuration and service wiring to add flexible, maintainable filtering to Symfony applications.
Reality check before anything else. This package is effectively unmaintained: low stars, no dependents, no community. The 0.2.0 release is a single-line changelog entry — treat it as evidence of a heartbeat, not of maintenance. It does not come with a support promise, a security policy, or a track record of Symfony/PHP compatibility work. The first step is not composer require — it is deciding whether you actually need it or whether you are reverse-engineering someone's side project.
composer.json first. Confirm the PHP and Symfony version constraints. The 0.1.x line targeted roughly PHP 7.1 and Symfony 3.3–4.0; check whether 0.2.0 moved any of that (the changelog suggests it did not). On PHP 8.x or Symfony 6/7, expect composer require to fail on constraints and expect the code to fail on modern deprecations even if you force-install with --ignore-platform-reqs.Form. So look first for a form type, a FormTypeExtension, or PRE_SUBMIT/SUBMIT event listeners in src/ — that is the real entry point. Then read DependencyInjection/*Extension.php, the configuration tree, and tests/.config/bundles.php on Flex, or AppKernel::registerBundles() on 3.x. Dump the tree with bin/console config:dump-reference <alias> — for a package this size it is probably nearly empty.QueryBuilder so a listing page can be filtered by a handful of request parameters. Build it on a branch, and include the case where the form is submitted with invalid data.Minimum viable spike:
composer require ruwork/filter-bundle:0.2.0 --dry-run # pin exact; read resolution errors carefully
If resolution succeeds, register the bundle, and reproduce the smallest example from tests/ verbatim — then reproduce it again with an invalid form submission, since that is what 0.2.0 changed. If either case does not pass on your platform, stop: you are now maintaining a fork, and you should price that in.
The day-to-day value of a bundle like this is entirely in how it turns request/form input into query constraints. The patterns worth using:
One filter object per use case, hydrated from a form. Keep the filter a plain object (scalars, nullable properties, sensible defaults). Let a FormType map request data onto it. Do the HTTP-side work (handleRequest, reading query params) at the controller boundary, never inside the filter, so the same filter can be built from a console command or a test without faking a request.
Let the form own input, but do not trust it to own correctness. Since 0.2.0 explicitly ignores submit and valid states, the package will happily hand you a partially-populated filter. Validate explicitly — Symfony Validator on the filter object, or a separate isValid() check feeding your error display — and decide deliberately what "no filters applied" means versus "filters rejected."
Apply, don't build. The filter describes intent ("status is active", "created after X"); a separate applier translates that into QueryBuilder calls. Keeping them apart is what makes filters unit-testable: you assert on the filter, and you assert on the builder with a mocked or in-memory connection.
Compose small filters rather than one god-filter. If the package exposes an interface, implement it repeatedly and apply filters in a loop over tagged services. Adding a filter becomes "add a class," not "edit the repository." If collection injection isn't wired out of the box, a small compiler pass is the legitimate extension point and cheaper than forking.
Repository scoping. Apply inside a dedicated repository method (findFiltered(Filter $f, int $page, int $perPage)) rather than in the controller. Pagination, ordering, and filtering live together, and it is obvious where to look when a query goes wrong.
Bound the input. Cap page size, whitelist sortable fields, reject inverted date ranges. A filter bundle gives you no protection here, and unbounded LIMIT/ORDER BY from request data is the usual way these listings become a production incident. This matters more now that the package ignores the form's valid state by design.
Test at three levels. Unit-test the filter (input → normalized values), functionally test one repository method per filter against a real database (SQLite or a test container), and add a test for the invalid submission path — empty form, one bad field, submit button only. That third test is your regression guard on the 0.2.0 behaviour and on any future release.
Isolate the dependency. Wrap the bundle's types behind your own interface in App\Filter. One afternoon of work, and the eventual migration goes from "rewrite every listing" to "swap one applier implementation."
0.2.0, not ^0.2) — 0.x carries no BC promise — commit the lock file, and keep the dependency in your risk register.isValid() was true). After, those are skipped. Consequences to check: (a) filters now apply from invalid forms, so bad input reaches the QueryBuilder unless you validate; (b) error messages may no longer surface because the package stopped caring about validity; (c) a filter that previously required a fully valid form may now apply partially — verify generated SQL for the half-filled case, not just the happy path.0.1.x → 0.2.0 is a minor bump on a 0.x package, which conventionally permits breaking changes. Diff the public API before upgrading; do not assume additive.--ignore-platform-reqs installs it and then deprecations bite at runtime; do not do this in production without a full functional test pass that includes the invalid-submission case.src/ for interface and abstract first — those are the seams you can build on.bin/console debug:container --tag=<tag> and debug:container <service-id> tell you whether it is registered, public, and tagged. Most "the filter does nothing" bugs are missing tags or a compiler pass that never ran.Expr behaviour changed across ORM 2.5 → 2.13+. If the bundle builds Expr conditions or uses getRootAliases(), re-test every generated query on your actual Doctrine version.Criteria, API Platform query-parameter filters (if you use it), or a ~150-line hand-rolled criteria object applied to a QueryBuilder. Because the surface here is small, the honest recommendation for a new project is to skip the dependency and write those 150 lines — you get better typing, modern PHP, and a maintainer you can talk to.How can I help you explore Laravel packages today?