Skip to content

feat(doctrine): add ChainFilter to compose filters on one parameter (ORM + ODM)#8416

Open
soyuka wants to merge 2 commits into
api-platform:4.4from
soyuka:feature/chain-filter
Open

feat(doctrine): add ChainFilter to compose filters on one parameter (ORM + ODM)#8416
soyuka wants to merge 2 commits into
api-platform:4.4from
soyuka:feature/chain-filter

Conversation

@soyuka

@soyuka soyuka commented Jul 22, 2026

Copy link
Copy Markdown
Member
Q A
Branch? 4.4
Bug fix? no
New feature? yes
Deprecations? no
Issues Related to #8407
License MIT
Doc PR api-platform/docs#2316

What

Adds ChainFilter for Doctrine ORM and MongoDB ODM — a thin composite that holds several filters and applies each in turn on a single query-parameter key:

new QueryParameter(
    key: 'birthdate',
    property: 'birthdate',
    filter: new ChainFilter([
        new ExactFilter(),
        new DateFilter(), // or ComparisonFilter(new ExactFilter())
    ]),
)
  • ?birthdate=1999-12-31 → equality
  • ?birthdate[before]=… / [after] / [strictly_before] / [strictly_after]DateFilter (full null management + date semantics), or [lt]/[gt]/… with ComparisonFilter

Each wrapped filter self-selects by value shapeComparisonFilter/DateFilter ignore scalars, ExactFilter/PartialSearchFilter ignore associative (operator-map) arrays — so the composite just applies all of them; no supports() method needed. getOpenApiParameters() merges every wrapped filter's parameters. ManagerRegistry/Logger are forwarded to aware inner filters (mirroring FreeTextQueryFilter), and ChainFilter's own getDescription() is a no-op — so wrapping a legacy DateFilter also suppresses the cosmetic ManagerRegistry warmup ALERT from #7361.

Why

Users combining equality with comparison/date operators on one property previously had to hand-write a bespoke dispatching decorator (see #8407). ChainFilter makes it declarative and reusable, on the "thin composers over single-responsibility primaries" line of the new filter system (like OrFilter, FreeTextQueryFilter).

Guards

Carries the associative-array guard on ExactFilter/PartialSearchFilter (ORM and ODM): if (\is_array($value) && !array_is_list($value)) return;. It's load-bearing for the chain — without it those filters treat an operator-map as an IN list/LIKE set and corrupt the comparison. The ORM guard also ships standalone on 4.3 in #8415; the two reconcile cleanly on merge-up.

Test

ChainFilterTest (ORM) + ChainFilterMongoDbTest (ODM): exact match, [lt], [gte], and OpenAPI merge of both filters. Both green (mongod exercised). php-cs-fixer clean, PHPStan [OK].

ChainFilter applies each wrapped filter in turn so a single query-parameter key
can accept several value shapes — e.g. equality plus comparison operators —
without a bespoke decorator. Each primary self-selects by value shape
(ComparisonFilter ignores scalars; ExactFilter/PartialSearchFilter ignore
operator-map arrays), so the composite applies all of them and merges their
OpenAPI parameters. ManagerRegistry/Logger are forwarded to aware inner filters,
mirroring FreeTextQueryFilter.

Also adds the associative-array guard on ExactFilter/PartialSearchFilter, which
is load-bearing for the chain (same guard as api-platform#8415 on 4.3; will reconcile on
merge-up).
… filters

Mirror the ORM ChainFilter for MongoDB ODM. Add the operator-map guard to the
ODM ExactFilter and PartialSearchFilter so they self-select by value shape
inside a ChainFilter — an associative operator-map array belongs to
ComparisonFilter/DateFilter, not equality.
@soyuka soyuka changed the title feat(doctrine): add ChainFilter to compose filters on one parameter feat(doctrine): add ChainFilter to compose filters on one parameter (ORM + ODM) Jul 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant