theofidry/loopback-api-bundle
A Symfony bundle for building LoopBack-style REST APIs, helping you expose application resources through configurable endpoints. It streamlines model-driven routing and integration, making it easier to add JSON-friendly API endpoints to Symfony apps with less boilerplate.
Before installing anything, understand the context: this bundle is archived (last release 2015-10-01) and self-described as [DEPRECATED]. It was a proof of concept that swapped DunglasApiBundle's default filtering for LoopBack-style filter[...] query syntax. It targets Symfony 2.x/3.x + the original dunglas/api-bundle (which later became API Platform), not API Platform 1.x+, and certainly not API Platform 2/3. If you are starting something new, stop here and use API Platform's built-in QueryParameter filters instead — they cover the same use cases and are maintained.
Use this only if you are maintaining an existing Symfony 2.8/3.x app where the bundle is already wired in, or you are specifically reproducing the filter[where][...] contract for a legacy client.
Minimal steps for a legacy integration:
composer.json in the repo for the pinned constraints; PHP 5.5/7.0-era syntax).
composer require theofidry/loopback-api-bundle:"@dev" dunglas/api-bundle:"@dev"
app/AppKernel.php (or bundles.php on 3.4+), after DunglasApiBundle and DoctrineBundle.Resources/config/services.xml and the DependencyInjection/ extension — this is where the collection extension is tagged and where any filtering config (enabled resources, whitelist) is exposed.curl 'http://localhost/app_dev.php/api/books?filter[where][status]=published&filter[limit]=10'
First use case: filter a collection endpoint by one or more scalar fields, with pagination via filter[limit] / filter[skip]. Confirm it works before touching order or include, which are the parts most likely to be half-implemented or unmaintained.
Where to look first, in order: the README (short), DependencyInjection/Configuration.php (what's actually configurable), the Doctrine extension class (where query building happens), and Tests/ (the best documentation of supported filter shapes in this repo).
Global vs. per-resource enabling. The bundle hooks into DunglasApiBundle's collection extension mechanism. Depending on version, you either tag the extension globally (every Doctrine collection gets LoopBack filtering) or associate it with specific resources. For anything user-facing, prefer per-resource opt-in; a global extension means any collection endpoint silently accepts filter[...], which is exactly the kind of surface you don't want to expose accidentally.
Whitelist the filterable fields. The core risk with a free-form filter[where][field]=value parser is that the client chooses the field name. Whatever the bundle does, wrap or configure it so that only declared fields (and operators) are accepted per resource. If the bundle has no whitelist config, add a thin listener that validates the filter query parameter against an allowlist before the extension runs.
Typical request shapes to support and test:
?filter[where][status]=published
?filter[where][price][gte]=10
?filter[where][or][0][status]=draft&filter[where][or][1][status]=review
?filter[limit]=25&filter[skip]=50
?filter[order]=createdAt DESC
?filter[fields][title]=true&filter[fields][author]=true
Write a fixture test per shape against a real entity. The parser is the most fragile component and the repo's tests are the only reliable spec.
Compose with DunglasApi pagination carefully. DunglasApi already applies pagination. If filter[limit]/filter[skip] are honored by this bundle, make sure they win over (or are reconciled with) the bundle's pagination config, otherwise you get double-limiting or a setMaxResults overwrite. The cleanest pattern is to disable controller-level pagination for resources where LoopBack filtering is enabled and let the filter drive the result window.
include (relation loading) is where you'll do the most work. If supported, use it sparingly and pair it with explicit Doctrine fetch-joins or EntityGraph hints on the affected relations. Otherwise a single ?filter[include]=author on a 200-row collection becomes 200 queries. If the feature is missing or broken in your version, implement it as a separate opt-in extension rather than patching the filter parser.
Integration tip — keep the parser isolated. The useful half of this package is the filter[...] → Doctrine QueryBuilder translation. If you are stuck on legacy code, treat that translation as a standalone service: inject it into your own QueryCollectionExtensionInterface implementation so you can upgrade/abandon the bundle without rewriting request handling.
Testing pattern. Use functional tests that hit a real kernel with a SQLite fixture database and assert both the response payload and the generated SQL (via the Doctrine SQLLogger). Filter translation bugs usually show up as wrong joins or missing setParameter bindings, not as errors.
api-platform/core. If a dependency conflict forces you off the pinned DunglasApiBundle version, this bundle will not follow you.DunglasApiBundle was renamed and restructured into API Platform. Any snippet, blog post, or README example you find from this era may reference classes that no longer exist under that name. Confirm the exact FQCNs against the installed version in vendor/ before copying anything.parse_str handles filter[where][field][gte]=10 fine, but proxies, API gateways, and some HTTP clients mangle deeply nested bracket notation or re-encode it. If filters silently do nothing in production but work locally, log the raw $_GET/Request::query contents first.setParameter. Field/operator names must come from a whitelist map, not from the request.between, inq, like, near, regexp) is implemented. Enumerate what the parser actually recognizes from its tests/config and reject anything else with a 400 rather than ignoring it — silent ignores produce wrong data, which is worse than an error.order and fields are easy to get subtly wrong. Validate sort fields against the same allowlist, and be aware that fields projection can conflict with DunglasApi's serializer normalization (e.g., required Hydra fields missing from the response).doctrine.dbal.logging / use the Symfony profiler's Doctrine panel to inspect the final SQL, and set %kernel.debug% so the parser throws on unrecognized syntax instead of swallowing it. A one-line dump() in the extension's apply() method is often faster than reading the parser.QueryCollectionExtensionInterface implementation wrapping the bundle's translator, (b) a request listener that validates/normalizes the filter parameter, and (c) Doctrine EntityGraph metadata for include handling. Avoid forking the bundle; the whole value is ~a few hundred lines you can reimplement in a day if needed.QueryParameter-based filter is a far better long-term investment than resurrecting a 2015 archived bundle with zero dependents.How can I help you explore Laravel packages today?