Skip to content

fix(doctrine): use PHP property name in DQL for modern filters with name converter#8382

Merged
soyuka merged 1 commit into
api-platform:4.3from
soyuka:fix/8380-modern-filter-name-converter
Jul 3, 2026
Merged

fix(doctrine): use PHP property name in DQL for modern filters with name converter#8382
soyuka merged 1 commit into
api-platform:4.3from
soyuka:fix/8380-modern-filter-name-converter

Conversation

@soyuka

@soyuka soyuka commented Jul 3, 2026

Copy link
Copy Markdown
Member

Fixes #8380

Problem

Modern parameter filters (ExactFilter, SortFilter, ComparisonFilter, PartialSearchFilter) use Parameter::getProperty() verbatim to build the DQL/aggregation query. When an api_platform.name_converter (e.g. CamelCaseToSnakeCaseNameConverter) is configured, ParameterResourceMetadataCollectionFactory::setDefaults() normalizes the property (createdAt -> created_at) so the public/OpenAPI parameter name matches the API's naming convention. But Doctrine still knows the entity field by its PHP name, so every request filtering/sorting on a multi-word property fails with HTTP 500:

[Semantical Error] ... Class App\Entity\Book has no field or association named created_at

Single-word properties (status, name, ...) are unaffected because camelCase == snake_case for them, which is why the bug is easy to miss.

This is a follow-up to #7866 / #7877, which fixed the equivalent problem for the legacy AbstractFilter-based filters. The docs currently recommend the modern filters as the fix for the legacy filters' name-converter issues, but on this setup they fail harder (500 instead of a silently ignored filter).

Fix

The public parameter name and the internal query field name legitimately diverge: the Hydra IRI template mapping and OpenAPI docs read getProperty() and must expose the converted (created_at) name, while the query must use the PHP field (createdAt).

  • ParameterResourceMetadataCollectionFactory::setDefaults(): before normalizing, stash the original PHP property name as a query_property extra-property on the Parameter — only when a name converter runs and there is no nested_properties_info (nested paths already skip normalization and keep their existing handling; the no-name-converter path is untouched).
  • ORM NestedPropertyHelperTrait::addNestedParameterJoins() and ODM NestedPropertyHelperTrait::addNestedParameterLookups(): on the flat (non-nested) return, prefer $extraProperties['query_property'] ?? $property. This is the single chokepoint every modern ORM/ODM filter routes through. ComparisonFilter delegates to its inner filter (e.g. ExactFilter), so it is covered transitively.

Test

New functional test NameConverterModernFilterTest (ORM + ODM), using the test app's existing CustomConverter (same infra as the #7877 NameConverterFilterTest), with QueryParameter(filter: new ExactFilter(), property: 'nameConverted') and a SortFilter case. Verified it fails before the fix with the exact reported has no field or association named name_converted 500, and passes after.

…ame converter

Modern parameter filters (ExactFilter, SortFilter, ComparisonFilter,
PartialSearchFilter) used Parameter::getProperty() verbatim to build
DQL/aggregation queries. When a name converter is configured,
ParameterResourceMetadataCollectionFactory::setDefaults() normalizes
that property (e.g. createdAt -> created_at) for the public/OpenAPI
name, but Doctrine still knows the entity field by its PHP name,
causing a 500 "has no field or association named created_at" for any
multi-word property.

Preserve the original PHP property name as a `query_property` extra
property before normalizing, and prefer it over the converted
property in both NestedPropertyHelperTrait implementations (ORM and
ODM), which is the single chokepoint every modern filter routes
through for flat (non-nested) properties. Nested properties already
skip normalization via nested_properties_info and are unaffected.

Follow-up to api-platform#7877, which fixed the equivalent issue for legacy
AbstractFilter-based filters.

Fixes api-platform#8380
@soyuka soyuka merged commit 48e8f97 into api-platform:4.3 Jul 3, 2026
111 of 112 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