Filter Groups
Spatie laravel-query-builder v7.3.0 / PR #1060 — JSON:API Fancy Filter compositions with explicit AND/OR conjunctions, surfaced as a single shorthand parameter on the client.
Why this matters
Before Filter Groups, expressing "search across name OR full_name" required either:
- A custom filter on the server (boilerplate per-search-field combination), or
- An operator-level OR smuggled into a generic
qstring parser (fragile, easy to leak SQL precedence bugs).
Filter Groups make that compositions a first-class declaration on the server, with the client just sending the shorthand.
The contract
Server (Spatie ≥ 7.3.0):
use Spatie\QueryBuilder\AllowedFilter;
QueryBuilder::for(User::class)
->allowedFilters(
AllowedFilter::groupOr('q', [
AllowedFilter::partial('name'),
AllowedFilter::partial('full_name'),
]),
);Client (crisp-oquent):
await User.crispy().filterGroup('q', 'John').get();Wire format:
GET /users?filter[q]=JohnResulting SQL:
WHERE (LOWER(name) LIKE '%john%' OR LOWER(full_name) LIKE '%john%')groupOr vs groupAnd
// All members must match — useful for combining several constraints under one shorthand.
AllowedFilter::groupAnd('strict_search', [
AllowedFilter::partial('name'),
AllowedFilter::exact('verified'),
]);The client shorthand is identical:
await User.crispy().filterGroup('strict_search', 'value').get();The conjunction lives on the server. The client never has to know.
Composing with regular filters
Multiple groups and top-level filters AND-compose:
await User.crispy()
.filter('status', 'active') // top-level filter
.filterGroup('q', 'John') // group OR
.filterGroup('region_search', 'Istanbul') // another group OR
.get();Wire:
GET /users?filter[status]=active&filter[q]=John&filter[region_search]=IstanbulSQL precedence (server-side):
WHERE status = 'active'
AND (name LIKE '%John%' OR full_name LIKE '%John%')
AND (city LIKE '%Istanbul%' OR region LIKE '%Istanbul%')Outer-where(closure) wrappers around each group preserve precedence — see the #1060 PR description for the SQL-shape regression test.
Standards anchor — JSON:API Fancy Filters
The Filter Groups feature is anchored on the JSON:API Fancy Filters recommendation, which Drupal's JSON:API module ships in production.
The base JSON:API spec leaves the filter parameter family intentionally extension-friendly — Fancy Filters is the established standards anchor for groups / conditions with explicit AND/OR conjunctions.
Roadmap — full Fancy Filters URL syntax
The current Spatie implementation supports the shorthand form (?filter[q]=value). The full Fancy Filters URL syntax (?filter[g1][conjunction]=OR&filter[g1][conditions][...]) is listed as a follow-up in #1060's "Out of scope" section.
When it lands in a future Spatie minor, crisp-oquent will gain the corresponding builder DSL — likely under an opt-in flag until both sides agree on the wire format.