Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Jsonapi Rql Finder Bundle Laravel Package

mnugter/jsonapi-rql-finder-bundle

Symfony/PHP bundle that integrates an RQL finder into JSON:API resources, letting clients filter, sort, and paginate with expressive query expressions. It bridges RQL parsing and Doctrine queries so endpoints return consistent, spec-compliant responses with less custom code.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is an adapter, not a standalone API: it plugs RQL filter syntax (eq, and, or, in, like, …) into the finder/query layer of paknahad/jsonapi-bundle. You need that bundle installed and at least one JSON:API resource (model/endpoint) working before this adds value.

  1. Install alongside the base bundle, on PHP 8

    composer require paknahad/jsonapi-bundle mnugter/jsonapi-rql-finder-bundle:^3.0
    

    3.0.0 is the PHP 8 release. The release note is a single line — "Support for PHP 8" — with no changelog and no stated breaking changes, but a major-version bump for what looks like a platform requirement almost certainly means PHP 7.x is dropped from the composer.json php constraint. Check that constraint before you plan the upgrade, and if you're still on PHP 7.4 stay on the pre-3.0 line (pin it exactly). For PHP 8 projects, ^3.0 is the right constraint; for anything you intend to keep, pin to the exact tag and diff the src/ between your old and new version yourself — the release notes won't tell you what moved.

  2. Wire it in. The package is shipped as a bundle, so in a Symfony host app you register it in config/bundles.php and import any config file the README documents. If you're coming from Laravel (as most readers will), there is no ServiceProvider here — you either run the underlying paknahad/jsonapi-bundle if it is Laravel-native, or lift the RQL parser/operator classes out of src/ and bind them in a provider. Do that evaluation before writing feature code; the parser is the reusable part, the container wiring is not.

  3. Where to look first — in this order:

    • the README (operator list and the exact filter query-param shape),
    • src/ for the finder class and the operator map (this is what decides which RQL functions exist and how they translate to query builder calls),
    • the tests (the best documentation of accepted syntax),
    • paknahad/jsonapi-bundle's finder/query contract, since that is the seam this package hooks into.
  4. First use case. Take an existing endpoint and replace hand-rolled query params:

    GET /api/articles?filter=eq(status,published)
    GET /api/articles?filter=and(eq(status,published),gt(views,100))
    

    Confirm the generated SQL through the Symfony profiler (or Laravel's query log) before trusting it. If those two work, or, in, and like will too — they exercise the same code path.

Implementation Patterns

Use filter as one opaque string, not a bag of params. The whole point of the package is that ?status=published&views_gt=100 becomes ?filter=and(eq(status,published),gt(views,100)). Build it client-side with http_build_query(['filter' => $rql]) so parentheses, commas, and * are encoded; never hand-concatenate URLs.

Compose, don't override, the JSON:API params. Keep RQL in filter and leave sort, page[number], page[size], include, and fields[...] to the base bundle. Do not try to smuggle sort(...) or limit(...) through filter unless the README explicitly documents that — you'll end up with two competing pagination mechanisms and mismatched meta.total counts.

Allowlist what can be filtered. The finder will happily map RQL field names onto columns. Add a per-resource map (config or a small resolver class) of exposed fields and permitted operators, so eq(password_hash,...) or like(api_token,*a*) is rejected with a 400 rather than executed. This is the single most important integration step and the one most likely to be missing from a small package's defaults.

Keep the controller thin. The resource/controller should receive the document request, hand the filter to the finder, and serialize the result. If you find yourself parsing the RQL string in a controller, you're duplicating what the bundle already does and you'll drift from its grammar.

Front-end contract: build a tiny RQL serializer. Filter chips in a UI map cleanly to an AST ({and: [{eq: ['status','published']}, {gt: ['views',100]}]}) that serializes to RQL. Centralizing this avoids every screen inventing its own string format and makes the query string cacheable/normalizable (sorted operands = stable ETag/cache key).

Custom operators as the extension point. Where you need domain semantics (eq(tag,php) on a pivot table, full-text, isnull), register a custom operator/scope rather than post-processing results in PHP — post-processing breaks pagination counts. On 3.0.0 you can use PHP 8 syntax (constructor promotion, union types, named arguments) in your own operator classes, but check the base classes' signatures — if the package's own interfaces are still untyped for BC with 7.x-era code, your overriding method must match the parent's laxer signature or PHP throws a fatal.

Test at the boundary. Feature tests that assert on the emitted query bindings for a handful of representative filters (and, nested or, in, a quoted string containing a comma) catch more regressions than unit-testing the parser internals. Add one negative test for a disallowed field and one for malformed RQL.

Map parse failures to JSON:API errors. A malformed filter should produce a 400 with an errors[] object, not a 500. Wrap the finder call and translate the parser exception.

Gotchas and Tips

  • Maintenance risk is still the headline, but it's shifted shape. A 3.0.0 exists, so the package isn't abandoned — however it's still a very small user base (single-digit stars, no dependents) and the release note is one sentence. Assume you are the first person to hit any given edge case. Vendor the package or fork it into your repo, and read src/ end to end before you build on it — the source is the documentation.
  • Upgrading to 3.0.0 is unverified by the community. A major bump whose only documented change is PHP 8 support may also carry rewritten internals. Diff the operator map and finder class against your previous version, run your filter test suite against both, and treat the upgrade as a code change to review — not a composer update to wave through.
  • PHP 8 minor-version drift. "Support for PHP 8" doesn't say which PHP 8. If the package's constraint is ^8.0, it may never have been run on 8.2/8.3, where dynamic properties, ${var} interpolation in strings, and implicit nullable parameters all emit deprecations. Suppress nothing until you've read the deprecation log once; a 2022-era codebase commonly trips these in query-builder glue code.
  • Framework mismatch. If you're a Laravel developer, "Bundle" is literal: expect Symfony DI, config/bundles.php, and HttpFoundation-oriented services. Budget time for either adapting the parser into a service provider or accepting a second framework in your stack. Don't assume composer require + auto-discovery just works.
  • URL/param parsing quirks. Some clients send filter[field]=value (array), which arrives as an array, not a string — the parser will choke. Normalize filter to a string at the edge. Watch for , and ) being truncated by proxies or unencoded clients, and for * in like() being eaten by shell/curl tests.
  • Injection surface. Verify operators bind parameters rather than interpolating. Send eq(name,' OR 1=1 --) and check the query log. If any operator concatenates raw input, wrap or replace it.
  • Type coercion. Dates (gt(created_at,2022-01-01)), booleans, and nulls are the usual failure points, and MySQL/Postgres disagree on casting. Use isnull/explicit equality forms where the grammar supports them, and test both engines if you deploy both.
  • Relationships are likely out of scope. Expect filtering on local columns/FKs only. Filtering on a related resource's attributes usually needs a custom operator mapping to a whereHas/join, and joins will change your total count query — verify counts on filtered, relation-filtered sets.
  • DoS-shaped inputs. Deeply nested and(or(and(...))) strings and very long in() lists can recurse or blow up SQL. Cap filter length and nesting depth before parsing.
  • Pagination counts. The count query must apply the same filter as the data query. If your base bundle builds the count separately, check it — off-by-filter totals are the most common post-integration bug report.
  • Config/service ordering. If you decorate or override the finder, registration order relative to the paknahad bundle matters. If filters appear to be ignored, dump the container and confirm your service is the one actually injected.
  • Debugging: log the received filter string, the parsed AST, and the resulting SQL bindings at debug level. Three lines of logging will save hours against a package with no community answers.
  • Extension points worth knowing: the operator map (add domain operators), the finder/query strategy (swap for a custom repository), and any input-normalization listener (sanitize/allowlist before parsing). Everything else is a fork.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core