Skip to content

fix(graphql): build filter args from parameters#8347

Merged
soyuka merged 1 commit into
api-platform:mainfrom
soyuka:fix/graphql-filters
Jun 23, 2026
Merged

fix(graphql): build filter args from parameters#8347
soyuka merged 1 commit into
api-platform:mainfrom
soyuka:fix/graphql-filters

Conversation

@soyuka

@soyuka soyuka commented Jun 23, 2026

Copy link
Copy Markdown
Member

What

Unifies GraphQL field-argument generation in FieldsBuilder so filters declared via #[QueryParameter] reach full parity with the legacy #[ApiFilter] path.

Problem

FieldsBuilder built GraphQL arguments from two divergent code paths:

  • legacy Operation::getFilters() (#[ApiFilter]) — supported nested-collection args (colors(prop:)) and operator forms;
  • canonical Operation::getParameters() (#[QueryParameter]) — flattened dotted keys (colors.prop) into root args and never exposed ComparisonFilter operator forms.

So migrating fixtures from #[ApiFilter] to QueryParameter (the 4.4/bc-filter work) silently dropped nested-collection and operator arguments over GraphQL. The legacy FilterTest suite only stayed green because DummyCar still uses #[ApiFilter].

Change

One intermediate arg-tree (#name/#list/#nonNull markers) feeds one converter, replacing getFilterArgs/getParameterArgs/parameterToObjectType/getParameterType/mergeFilterArgs/convertFilterArgsToTypes. Both filter and parameter sources feed the same tree.

QueryParameter parity:

  • nested collection args (colors(prop:)) from the related resource's own parameters via the existing depth recursion (also fixes a latent bug where parameter args were sourced from the root operation instead of the resource operation);
  • operator forms (gt/gte/lt/lte/ne) derived from JsonSchemaFilterInterface::getSchema() instead of the empty deprecated getDescription();
  • scalar leaf types from the parameter's native type (an int property yields GraphQL Int).

Sort filters are list-shaped (order: [{...}]) because GraphQL input-object fields are unordered and cannot preserve multi-key ordering, whereas every other bracketed filter (search/comparison/date/exists) stays a single input object. This is recognized through a new backend-agnostic ApiPlatform\Metadata\SortFilterInterface, implemented by the Doctrine ORM/ODM SortFilter and the Laravel OrderFilter — so FieldsBuilder depends only on Metadata, not on any persistence layer.

Runtime is unchanged — ReadProvider/ParameterProvider/FilterExtension/ParameterExtension already apply both paths.

Tests

New ParameterFilterParityTest + GraphQlFilteredResource(Color) fixtures (ORM + ODM) declare DummyCar-equivalent filters via QueryParameter and assert nested search, ComparisonFilter operators (gt: 10Int), root exact and order list shape — failing before, green after. Legacy DummyCar/FilterTest left untouched as the BC anchor.

Green (ORM): GraphQl FilterTest 13/13, ParameterFilterParityTest 4/4, Issue7966Test, full tests/Functional/GraphQl 159/159, tests/Functional/Parameters 406/406 (16 ODM skips). ODM mirror not run locally (no doctrine/mongodb-odm-bundle).

FieldsBuilder generated GraphQL field arguments from two divergent
paths: legacy Operation::getFilters() (#[ApiFilter]) and canonical
Operation::getParameters() (#[QueryParameter]). The parameter path
flattened dotted keys (colors.prop) into root arguments and never
exposed ComparisonFilter operator forms, so migrating filters to
QueryParameter silently dropped nested-collection and operator
arguments over GraphQL.

Unify both into a single arg-tree pipeline so QueryParameter reaches
parity with the legacy path:
- nested collection args (colors(prop:)) from the related resource's
  own parameters via the existing depth recursion
- operator forms (gt/gte/lt/lte/ne) from JsonSchemaFilterInterface
- scalar leaf types from the parameter native type (int yields Int)

Sort filters implement the backend-agnostic Metadata
SortFilterInterface so the builder can list-shape sequence-sensitive
order arguments (order: [{...}]) without depending on a persistence
layer; GraphQL input-object fields are unordered and cannot preserve
multi-key ordering.
@soyuka soyuka force-pushed the fix/graphql-filters branch from 7bc45fc to 43b55ca Compare June 23, 2026 13:50
@soyuka soyuka merged commit 9b7ace5 into api-platform:main Jun 23, 2026
83 of 96 checks passed
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