From a1d0264cf3aa949cac2e643a47eaefb60df14c40 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Mon, 12 Jan 2026 17:13:59 +0100 Subject: [PATCH 1/3] Simplest solution --- ...meterResourceMetadataCollectionFactory.php | 4 --- .../Fixtures/TestBundle/Document/Chicken.php | 22 +++++++++++++++ .../Document/FilteredBooleanParameter.php | 28 +++++++++++++++++++ tests/Fixtures/TestBundle/Entity/Chicken.php | 22 +++++++++++++++ .../Entity/FilteredBooleanParameter.php | 28 +++++++++++++++++++ .../Parameters/BooleanFilterTest.php | 16 +++++++++++ .../Functional/Parameters/ExactFilterTest.php | 24 ++++++++++++++++ 7 files changed, 140 insertions(+), 4 deletions(-) diff --git a/src/Metadata/Resource/Factory/ParameterResourceMetadataCollectionFactory.php b/src/Metadata/Resource/Factory/ParameterResourceMetadataCollectionFactory.php index 656d82ca215..cd9929f91a3 100644 --- a/src/Metadata/Resource/Factory/ParameterResourceMetadataCollectionFactory.php +++ b/src/Metadata/Resource/Factory/ParameterResourceMetadataCollectionFactory.php @@ -259,10 +259,6 @@ private function setDefaults(string $key, Parameter $parameter, ?object $filter, $parameter = $parameter->withProperty($key); } - if ($this->nameConverter && $property = $parameter->getProperty()) { - $parameter = $parameter->withProperty($this->nameConverter->normalize($property)); - } - if (isset($properties[$currentKey]) && ($eloquentRelation = ($properties[$currentKey]->getExtraProperties()['eloquent_relation'] ?? null)) && isset($eloquentRelation['foreign_key'])) { $parameter = $parameter->withProperty($eloquentRelation['foreign_key']); } diff --git a/tests/Fixtures/TestBundle/Document/Chicken.php b/tests/Fixtures/TestBundle/Document/Chicken.php index 2fe846ecae3..32d394a4a13 100644 --- a/tests/Fixtures/TestBundle/Document/Chicken.php +++ b/tests/Fixtures/TestBundle/Document/Chicken.php @@ -33,6 +33,10 @@ filter: new PartialSearchFilter(), property: 'name', ), + 'nameConverted' => new QueryParameter(filter: new ExactFilter()), + 'nameConvertedAlias' => new QueryParameter(filter: new ExactFilter(), property: 'nameConverted'), + 'nameNotConverted' => new QueryParameter(filter: new ExactFilter()), + 'nameNotConvertedAlias' => new QueryParameter(filter: new ExactFilter(), property: 'nameNotConverted'), 'autocomplete' => new QueryParameter(filter: new FreeTextQueryFilter(new OrFilter(new ExactFilter())), properties: ['name', 'ean']), 'q' => new QueryParameter(filter: new FreeTextQueryFilter(new PartialSearchFilter()), properties: ['name', 'ean']), ], @@ -45,6 +49,12 @@ class Chicken #[ODM\Field(type: 'string')] private string $name; + #[ODM\Field(type: 'string')] + private string $nameConverted; + + #[ODM\Field(type: 'string')] + private string $nameNotConverted; + #[ODM\Field(type: 'string', nullable: true)] private ?string $ean; @@ -64,10 +74,22 @@ public function getName(): ?string public function setName(string $name): self { $this->name = $name; + $this->nameConverted = $name; + $this->nameNotConverted = $name; return $this; } + public function getNameConverted(): ?string + { + return $this->nameConverted; + } + + public function getNameNotConverted(): ?string + { + return $this->nameNotConverted; + } + public function getEan(): ?string { return $this->ean; diff --git a/tests/Fixtures/TestBundle/Document/FilteredBooleanParameter.php b/tests/Fixtures/TestBundle/Document/FilteredBooleanParameter.php index 8964c3d49da..b6b78fce77e 100644 --- a/tests/Fixtures/TestBundle/Document/FilteredBooleanParameter.php +++ b/tests/Fixtures/TestBundle/Document/FilteredBooleanParameter.php @@ -33,11 +33,35 @@ property: 'active', nativeType: new BuiltinType(TypeIdentifier::BOOL), ), + 'nameConverted' => new QueryParameter( + filter: new BooleanFilter(), + nativeType: new BuiltinType(TypeIdentifier::BOOL), + ), + 'nameNotConverted' => new QueryParameter( + filter: new BooleanFilter(), + nativeType: new BuiltinType(TypeIdentifier::BOOL), + ), + 'aliasWithNameConverter' => new QueryParameter( + filter: new BooleanFilter(), + property: 'nameConverted', + nativeType: new BuiltinType(TypeIdentifier::BOOL), + ), + 'aliasWithoutNameConverter' => new QueryParameter( + filter: new BooleanFilter(), + property: 'nameNotConverted', + nativeType: new BuiltinType(TypeIdentifier::BOOL), + ), ], )] #[ODM\Document] class FilteredBooleanParameter { + #[ODM\Field(type: 'bool', nullable: true)] + private ?bool $nameConverted; + + #[ODM\Field(type: 'bool', nullable: true)] + private ?bool $nameNotConverted; + public function __construct( #[ODM\Id(type: 'int', strategy: 'INCREMENT')] public ?int $id = null, @@ -45,6 +69,8 @@ public function __construct( #[ODM\Field(type: 'bool', nullable: true)] public ?bool $active = null, ) { + $this->nameConverted = $this->active; + $this->nameNotConverted = $this->active; } public function getId(): ?int @@ -60,5 +86,7 @@ public function isActive(): bool public function setActive(?bool $active): void { $this->active = $active; + $this->nameConverted = $active; + $this->nameNotConverted = $active; } } diff --git a/tests/Fixtures/TestBundle/Entity/Chicken.php b/tests/Fixtures/TestBundle/Entity/Chicken.php index f3533f59801..d8b339b4a78 100644 --- a/tests/Fixtures/TestBundle/Entity/Chicken.php +++ b/tests/Fixtures/TestBundle/Entity/Chicken.php @@ -33,6 +33,10 @@ filter: new PartialSearchFilter(), property: 'name', ), + 'nameConverted' => new QueryParameter(filter: new ExactFilter()), + 'nameConvertedAlias' => new QueryParameter(filter: new ExactFilter(), property: 'nameConverted'), + 'nameNotConverted' => new QueryParameter(filter: new ExactFilter()), + 'nameNotConvertedAlias' => new QueryParameter(filter: new ExactFilter(), property: 'nameNotConverted'), 'autocomplete' => new QueryParameter(filter: new FreeTextQueryFilter(new OrFilter(new ExactFilter())), properties: ['name', 'ean']), 'q' => new QueryParameter(filter: new FreeTextQueryFilter(new PartialSearchFilter()), properties: ['name', 'ean']), ], @@ -47,6 +51,12 @@ class Chicken #[ORM\Column(type: 'string', length: 255)] private string $name; + #[ORM\Column(type: 'string', length: 255)] + private string $nameConverted; + + #[ORM\Column(type: 'string', length: 255)] + private string $nameNotConverted; + #[ORM\Column(type: 'string', length: 255, nullable: true)] private ?string $ean; @@ -67,10 +77,22 @@ public function getName(): ?string public function setName(string $name): self { $this->name = $name; + $this->nameConverted = $name; + $this->nameNotConverted = $name; return $this; } + public function getNameConverted(): ?string + { + return $this->nameConverted; + } + + public function getNameNotConverted(): ?string + { + return $this->nameNotConverted; + } + public function getEan(): ?string { return $this->ean; diff --git a/tests/Fixtures/TestBundle/Entity/FilteredBooleanParameter.php b/tests/Fixtures/TestBundle/Entity/FilteredBooleanParameter.php index 259c2aafa48..da335f92633 100644 --- a/tests/Fixtures/TestBundle/Entity/FilteredBooleanParameter.php +++ b/tests/Fixtures/TestBundle/Entity/FilteredBooleanParameter.php @@ -33,11 +33,35 @@ property: 'active', nativeType: new BuiltinType(TypeIdentifier::BOOL), ), + 'nameConverted' => new QueryParameter( + filter: new BooleanFilter(), + nativeType: new BuiltinType(TypeIdentifier::BOOL), + ), + 'nameNotConverted' => new QueryParameter( + filter: new BooleanFilter(), + nativeType: new BuiltinType(TypeIdentifier::BOOL), + ), + 'aliasWithNameConverter' => new QueryParameter( + filter: new BooleanFilter(), + property: 'nameConverted', + nativeType: new BuiltinType(TypeIdentifier::BOOL), + ), + 'aliasWithoutNameConverter' => new QueryParameter( + filter: new BooleanFilter(), + property: 'nameNotConverted', + nativeType: new BuiltinType(TypeIdentifier::BOOL), + ), ], )] #[ORM\Entity] class FilteredBooleanParameter { + #[ORM\Column(nullable: true)] + private ?bool $nameConverted; + + #[ORM\Column(nullable: true)] + private ?bool $nameNotConverted; + public function __construct( #[ORM\Column] #[ORM\Id] @@ -47,6 +71,8 @@ public function __construct( #[ORM\Column(nullable: true)] public ?bool $active = null, ) { + $this->nameConverted = $this->active; + $this->nameNotConverted = $this->active; } public function getId(): ?int @@ -62,5 +88,7 @@ public function isActive(): bool public function setActive(?bool $isActive): void { $this->active = $isActive; + $this->nameConverted = $isActive; + $this->nameNotConverted = $isActive; } } diff --git a/tests/Functional/Parameters/BooleanFilterTest.php b/tests/Functional/Parameters/BooleanFilterTest.php index a856ea33790..fed061151ae 100644 --- a/tests/Functional/Parameters/BooleanFilterTest.php +++ b/tests/Functional/Parameters/BooleanFilterTest.php @@ -74,6 +74,22 @@ public static function booleanFilterScenariosProvider(): \Generator yield 'enabled_alias_false' => ['/filtered_boolean_parameters?enabled=false', 1, false]; yield 'enabled_alias_numeric_1' => ['/filtered_boolean_parameters?enabled=1', 2, true]; yield 'enabled_alias_numeric_0' => ['/filtered_boolean_parameters?enabled=0', 1, false]; + yield 'name_converted_true' => ['/filtered_boolean_parameters?nameConverted=true', 2, true]; + yield 'name_converted_false' => ['/filtered_boolean_parameters?nameConverted=false', 1, false]; + yield 'name_converted_numeric_1' => ['/filtered_boolean_parameters?nameConverted=1', 2, true]; + yield 'name_converted_numeric_0' => ['/filtered_boolean_parameters?nameConverted=0', 1, false]; + yield 'name_not_converted_true' => ['/filtered_boolean_parameters?nameNotConverted=true', 2, true]; + yield 'name_not_converted_false' => ['/filtered_boolean_parameters?nameNotConverted=false', 1, false]; + yield 'name_not_converted_numeric_1' => ['/filtered_boolean_parameters?nameNotConverted=1', 2, true]; + yield 'name_not_converted_numeric_0' => ['/filtered_boolean_parameters?nameNotConverted=0', 1, false]; + yield 'alias_name_converted_true' => ['/filtered_boolean_parameters?aliasWithNameConverter=true', 2, true]; + yield 'alias_name_converted_false' => ['/filtered_boolean_parameters?aliasWithNameConverter=false', 1, false]; + yield 'alias_name_converted_numeric_1' => ['/filtered_boolean_parameters?aliasWithNameConverter=1', 2, true]; + yield 'alias_name_converted_numeric_0' => ['/filtered_boolean_parameters?aliasWithNameConverter=0', 1, false]; + yield 'alias_name_not_converted_true' => ['/filtered_boolean_parameters?aliasWithoutNameConverter=true', 2, true]; + yield 'alias_name_not_converted_false' => ['/filtered_boolean_parameters?aliasWithoutNameConverter=false', 1, false]; + yield 'alias_name_not_converted_numeric_1' => ['/filtered_boolean_parameters?aliasWithoutNameConverter=1', 2, true]; + yield 'alias_name_not_converted_numeric_0' => ['/filtered_boolean_parameters?aliasWithoutNameConverter=0', 1, false]; } #[DataProvider('booleanFilterNullAndEmptyScenariosProvider')] diff --git a/tests/Functional/Parameters/ExactFilterTest.php b/tests/Functional/Parameters/ExactFilterTest.php index 61e16f9bddd..9badad6c4d3 100644 --- a/tests/Functional/Parameters/ExactFilterTest.php +++ b/tests/Functional/Parameters/ExactFilterTest.php @@ -103,6 +103,30 @@ public static function exactSearchFilterProvider(): \Generator 0, [], ]; + + yield 'filter by nameConverted' => [ + '/chickens?nameConverted=Gertrude', + 1, + ['Gertrude'], + ]; + + yield 'filter by nameConvertedAlias' => [ + '/chickens?nameConvertedAlias=Gertrude', + 1, + ['Gertrude'], + ]; + + yield 'filter by nameNotConverted' => [ + '/chickens?nameNotConverted=Gertrude', + 1, + ['Gertrude'], + ]; + + yield 'filter by nameNotConvertedAlias' => [ + '/chickens?nameNotConvertedAlias=Gertrude', + 1, + ['Gertrude'], + ]; } /** From 2723a5311d6fec5418c0863da3fb1a4d07e172de Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Mon, 12 Jan 2026 17:14:35 +0100 Subject: [PATCH 2/3] With NCA --- .../Filter/NameConverterAwareInterface.php | 25 ++++++++++++++++ .../Common/ParameterExtensionTrait.php | 7 +++++ .../Odm/Extension/ParameterExtension.php | 3 ++ src/Doctrine/Odm/Filter/AbstractFilter.php | 22 +++++++++++++- src/Doctrine/Odm/composer.json | 2 +- .../Orm/Extension/ParameterExtension.php | 3 ++ src/Doctrine/Orm/Filter/AbstractFilter.php | 30 +++++++++++++++---- src/Doctrine/Orm/composer.json | 2 +- .../Resources/config/doctrine_mongodb_odm.php | 1 + .../Bundle/Resources/config/doctrine_orm.php | 1 + 10 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 src/Doctrine/Common/Filter/NameConverterAwareInterface.php diff --git a/src/Doctrine/Common/Filter/NameConverterAwareInterface.php b/src/Doctrine/Common/Filter/NameConverterAwareInterface.php new file mode 100644 index 00000000000..dee651fe539 --- /dev/null +++ b/src/Doctrine/Common/Filter/NameConverterAwareInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Doctrine\Common\Filter; + +use Symfony\Component\Serializer\NameConverter\NameConverterInterface; + +interface NameConverterAwareInterface +{ + public function hasNameConverter(): bool; + + public function getNameConverter(): NameConverterInterface; + + public function setNameConverter(NameConverterInterface $nameConverter): void; +} diff --git a/src/Doctrine/Common/ParameterExtensionTrait.php b/src/Doctrine/Common/ParameterExtensionTrait.php index 4d865a8730f..57f1ff140c0 100644 --- a/src/Doctrine/Common/ParameterExtensionTrait.php +++ b/src/Doctrine/Common/ParameterExtensionTrait.php @@ -15,11 +15,13 @@ use ApiPlatform\Doctrine\Common\Filter\LoggerAwareInterface; use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface; +use ApiPlatform\Doctrine\Common\Filter\NameConverterAwareInterface; use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface; use ApiPlatform\Metadata\Parameter; use Doctrine\Persistence\ManagerRegistry; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\Serializer\NameConverter\NameConverterInterface; trait ParameterExtensionTrait { @@ -28,6 +30,7 @@ trait ParameterExtensionTrait protected ContainerInterface $filterLocator; protected ?ManagerRegistry $managerRegistry = null; protected ?LoggerInterface $logger = null; + protected ?NameConverterInterface $nameConverter = null; /** * @param object $filter the filter instance to configure @@ -43,6 +46,10 @@ private function configureFilter(object $filter, Parameter $parameter): void $filter->setLogger($this->logger); } + if ($this->nameConverter && $filter instanceof NameConverterAwareInterface && !$filter->hasNameConverter()) { + $filter->setNameConverter($this->nameConverter); + } + if ($filter instanceof PropertyAwareFilterInterface) { $properties = []; // Check if the filter has getProperties method (e.g., if it's an AbstractFilter) diff --git a/src/Doctrine/Odm/Extension/ParameterExtension.php b/src/Doctrine/Odm/Extension/ParameterExtension.php index d841fb9240e..a9d2ac4c4ec 100644 --- a/src/Doctrine/Odm/Extension/ParameterExtension.php +++ b/src/Doctrine/Odm/Extension/ParameterExtension.php @@ -22,6 +22,7 @@ use Doctrine\ODM\MongoDB\Aggregation\Builder; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\Serializer\NameConverter\NameConverterInterface; /** * Reads operation parameters and execute its filter. @@ -36,10 +37,12 @@ public function __construct( ContainerInterface $filterLocator, ?ManagerRegistry $managerRegistry = null, ?LoggerInterface $logger = null, + ?NameConverterInterface $nameConverter = null, ) { $this->filterLocator = $filterLocator; $this->managerRegistry = $managerRegistry; $this->logger = $logger; + $this->nameConverter = $nameConverter; } /** diff --git a/src/Doctrine/Odm/Filter/AbstractFilter.php b/src/Doctrine/Odm/Filter/AbstractFilter.php index 75b85b9ac47..17e8b8fc046 100644 --- a/src/Doctrine/Odm/Filter/AbstractFilter.php +++ b/src/Doctrine/Odm/Filter/AbstractFilter.php @@ -14,6 +14,7 @@ namespace ApiPlatform\Doctrine\Odm\Filter; use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface; +use ApiPlatform\Doctrine\Common\Filter\NameConverterAwareInterface; use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface; use ApiPlatform\Doctrine\Common\PropertyHelperTrait; use ApiPlatform\Doctrine\Odm\PropertyHelperTrait as MongoDbOdmPropertyHelperTrait; @@ -32,7 +33,7 @@ * * @author Alan Poulain */ -abstract class AbstractFilter implements FilterInterface, PropertyAwareFilterInterface, ManagerRegistryAwareInterface +abstract class AbstractFilter implements FilterInterface, PropertyAwareFilterInterface, ManagerRegistryAwareInterface, NameConverterAwareInterface { use MongoDbOdmPropertyHelperTrait; use PropertyHelperTrait; @@ -136,4 +137,23 @@ protected function normalizePropertyName(string $property): string return implode('.', array_map($this->nameConverter->normalize(...), explode('.', $property))); } + + public function hasNameConverter(): bool + { + return $this->nameConverter instanceof NameConverterInterface; + } + + public function getNameConverter(): NameConverterInterface + { + if (!$this->hasNameConverter()) { + throw new RuntimeException('NameConverter must be initialized before accessing it.'); + } + + return $this->nameConverter; + } + + public function setNameConverter(NameConverterInterface $nameConverter): void + { + $this->nameConverter = $nameConverter; + } } diff --git a/src/Doctrine/Odm/composer.json b/src/Doctrine/Odm/composer.json index cbca401032d..ccf77e59162 100644 --- a/src/Doctrine/Odm/composer.json +++ b/src/Doctrine/Odm/composer.json @@ -25,7 +25,7 @@ ], "require": { "php": ">=8.2", - "api-platform/doctrine-common": "^4.2.9", + "api-platform/doctrine-common": "^4.2.13", "api-platform/metadata": "^4.2", "api-platform/state": "^4.2.4", "doctrine/mongodb-odm": "^2.10", diff --git a/src/Doctrine/Orm/Extension/ParameterExtension.php b/src/Doctrine/Orm/Extension/ParameterExtension.php index c21c1018ce9..f9a4f95dcce 100644 --- a/src/Doctrine/Orm/Extension/ParameterExtension.php +++ b/src/Doctrine/Orm/Extension/ParameterExtension.php @@ -22,6 +22,7 @@ use Doctrine\Persistence\ManagerRegistry; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\Serializer\NameConverter\NameConverterInterface; /** * Reads operation parameters and execute its filter. @@ -36,10 +37,12 @@ public function __construct( ContainerInterface $filterLocator, ?ManagerRegistry $managerRegistry = null, ?LoggerInterface $logger = null, + ?NameConverterInterface $nameConverter = null, ) { $this->filterLocator = $filterLocator; $this->managerRegistry = $managerRegistry; $this->logger = $logger; + $this->nameConverter = $nameConverter; } /** diff --git a/src/Doctrine/Orm/Filter/AbstractFilter.php b/src/Doctrine/Orm/Filter/AbstractFilter.php index 0f9e7417dd1..6d334bcf296 100644 --- a/src/Doctrine/Orm/Filter/AbstractFilter.php +++ b/src/Doctrine/Orm/Filter/AbstractFilter.php @@ -14,6 +14,7 @@ namespace ApiPlatform\Doctrine\Orm\Filter; use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface; +use ApiPlatform\Doctrine\Common\Filter\NameConverterAwareInterface; use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface; use ApiPlatform\Doctrine\Common\PropertyHelperTrait; use ApiPlatform\Doctrine\Orm\PropertyHelperTrait as OrmPropertyHelperTrait; @@ -26,7 +27,7 @@ use Psr\Log\NullLogger; use Symfony\Component\Serializer\NameConverter\NameConverterInterface; -abstract class AbstractFilter implements FilterInterface, PropertyAwareFilterInterface, ManagerRegistryAwareInterface +abstract class AbstractFilter implements FilterInterface, PropertyAwareFilterInterface, ManagerRegistryAwareInterface, NameConverterAwareInterface { use OrmPropertyHelperTrait; use PropertyHelperTrait; @@ -111,19 +112,38 @@ protected function isPropertyEnabled(string $property, string $resourceClass): b protected function denormalizePropertyName(string|int $property): string { - if (!$this->nameConverter instanceof NameConverterInterface) { + if (!$this->hasNameConverter()) { return (string) $property; } - return implode('.', array_map($this->nameConverter->denormalize(...), explode('.', (string) $property))); + return implode('.', array_map($this->getNameConverter()->denormalize(...), explode('.', (string) $property))); } protected function normalizePropertyName(string $property): string { - if (!$this->nameConverter instanceof NameConverterInterface) { + if (!$this->hasNameConverter()) { return $property; } - return implode('.', array_map($this->nameConverter->normalize(...), explode('.', $property))); + return implode('.', array_map($this->getNameConverter()->normalize(...), explode('.', $property))); + } + + public function hasNameConverter(): bool + { + return $this->nameConverter instanceof NameConverterInterface; + } + + public function getNameConverter(): NameConverterInterface + { + if (!$this->hasNameConverter()) { + throw new RuntimeException('NameConverter must be initialized before accessing it.'); + } + + return $this->nameConverter; + } + + public function setNameConverter(NameConverterInterface $nameConverter): void + { + $this->nameConverter = $nameConverter; } } diff --git a/src/Doctrine/Orm/composer.json b/src/Doctrine/Orm/composer.json index 0fb956e21f9..0e51ae9f793 100644 --- a/src/Doctrine/Orm/composer.json +++ b/src/Doctrine/Orm/composer.json @@ -24,7 +24,7 @@ ], "require": { "php": ">=8.2", - "api-platform/doctrine-common": "^4.2.9", + "api-platform/doctrine-common": "^4.2.13", "api-platform/metadata": "^4.2", "api-platform/state": "^4.2.4", "doctrine/orm": "^2.17 || ^3.0" diff --git a/src/Symfony/Bundle/Resources/config/doctrine_mongodb_odm.php b/src/Symfony/Bundle/Resources/config/doctrine_mongodb_odm.php index dd74180d259..57abb8970a2 100644 --- a/src/Symfony/Bundle/Resources/config/doctrine_mongodb_odm.php +++ b/src/Symfony/Bundle/Resources/config/doctrine_mongodb_odm.php @@ -156,6 +156,7 @@ service('api_platform.filter_locator'), service('doctrine_mongodb')->nullOnInvalid(), service('logger')->nullOnInvalid(), + service('api_platform.name_converter')->nullOnInvalid(), ]) ->tag('api_platform.doctrine_mongodb.odm.aggregation_extension.collection', ['priority' => 32]) ->tag('api_platform.doctrine_mongodb.odm.aggregation_extension.item'); diff --git a/src/Symfony/Bundle/Resources/config/doctrine_orm.php b/src/Symfony/Bundle/Resources/config/doctrine_orm.php index 57504522571..e477ac2542d 100644 --- a/src/Symfony/Bundle/Resources/config/doctrine_orm.php +++ b/src/Symfony/Bundle/Resources/config/doctrine_orm.php @@ -168,6 +168,7 @@ service('api_platform.filter_locator'), service('doctrine')->nullOnInvalid(), service('logger')->nullOnInvalid(), + service('api_platform.name_converter')->nullOnInvalid(), ]) ->tag('api_platform.doctrine.orm.query_extension.collection', ['priority' => -16]) ->tag('api_platform.doctrine.orm.query_extension.item', ['priority' => -9]); From 4c2cbac57665a495044101a67b6237469d23a7f2 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Mon, 12 Jan 2026 17:14:57 +0100 Subject: [PATCH 3/3] Revert "With NCA" This reverts commit 2723a5311d6fec5418c0863da3fb1a4d07e172de. --- .../Filter/NameConverterAwareInterface.php | 25 ---------------- .../Common/ParameterExtensionTrait.php | 7 ----- .../Odm/Extension/ParameterExtension.php | 3 -- src/Doctrine/Odm/Filter/AbstractFilter.php | 22 +------------- src/Doctrine/Odm/composer.json | 2 +- .../Orm/Extension/ParameterExtension.php | 3 -- src/Doctrine/Orm/Filter/AbstractFilter.php | 30 ++++--------------- src/Doctrine/Orm/composer.json | 2 +- .../Resources/config/doctrine_mongodb_odm.php | 1 - .../Bundle/Resources/config/doctrine_orm.php | 1 - 10 files changed, 8 insertions(+), 88 deletions(-) delete mode 100644 src/Doctrine/Common/Filter/NameConverterAwareInterface.php diff --git a/src/Doctrine/Common/Filter/NameConverterAwareInterface.php b/src/Doctrine/Common/Filter/NameConverterAwareInterface.php deleted file mode 100644 index dee651fe539..00000000000 --- a/src/Doctrine/Common/Filter/NameConverterAwareInterface.php +++ /dev/null @@ -1,25 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace ApiPlatform\Doctrine\Common\Filter; - -use Symfony\Component\Serializer\NameConverter\NameConverterInterface; - -interface NameConverterAwareInterface -{ - public function hasNameConverter(): bool; - - public function getNameConverter(): NameConverterInterface; - - public function setNameConverter(NameConverterInterface $nameConverter): void; -} diff --git a/src/Doctrine/Common/ParameterExtensionTrait.php b/src/Doctrine/Common/ParameterExtensionTrait.php index 57f1ff140c0..4d865a8730f 100644 --- a/src/Doctrine/Common/ParameterExtensionTrait.php +++ b/src/Doctrine/Common/ParameterExtensionTrait.php @@ -15,13 +15,11 @@ use ApiPlatform\Doctrine\Common\Filter\LoggerAwareInterface; use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface; -use ApiPlatform\Doctrine\Common\Filter\NameConverterAwareInterface; use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface; use ApiPlatform\Metadata\Parameter; use Doctrine\Persistence\ManagerRegistry; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; -use Symfony\Component\Serializer\NameConverter\NameConverterInterface; trait ParameterExtensionTrait { @@ -30,7 +28,6 @@ trait ParameterExtensionTrait protected ContainerInterface $filterLocator; protected ?ManagerRegistry $managerRegistry = null; protected ?LoggerInterface $logger = null; - protected ?NameConverterInterface $nameConverter = null; /** * @param object $filter the filter instance to configure @@ -46,10 +43,6 @@ private function configureFilter(object $filter, Parameter $parameter): void $filter->setLogger($this->logger); } - if ($this->nameConverter && $filter instanceof NameConverterAwareInterface && !$filter->hasNameConverter()) { - $filter->setNameConverter($this->nameConverter); - } - if ($filter instanceof PropertyAwareFilterInterface) { $properties = []; // Check if the filter has getProperties method (e.g., if it's an AbstractFilter) diff --git a/src/Doctrine/Odm/Extension/ParameterExtension.php b/src/Doctrine/Odm/Extension/ParameterExtension.php index a9d2ac4c4ec..d841fb9240e 100644 --- a/src/Doctrine/Odm/Extension/ParameterExtension.php +++ b/src/Doctrine/Odm/Extension/ParameterExtension.php @@ -22,7 +22,6 @@ use Doctrine\ODM\MongoDB\Aggregation\Builder; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; -use Symfony\Component\Serializer\NameConverter\NameConverterInterface; /** * Reads operation parameters and execute its filter. @@ -37,12 +36,10 @@ public function __construct( ContainerInterface $filterLocator, ?ManagerRegistry $managerRegistry = null, ?LoggerInterface $logger = null, - ?NameConverterInterface $nameConverter = null, ) { $this->filterLocator = $filterLocator; $this->managerRegistry = $managerRegistry; $this->logger = $logger; - $this->nameConverter = $nameConverter; } /** diff --git a/src/Doctrine/Odm/Filter/AbstractFilter.php b/src/Doctrine/Odm/Filter/AbstractFilter.php index 17e8b8fc046..75b85b9ac47 100644 --- a/src/Doctrine/Odm/Filter/AbstractFilter.php +++ b/src/Doctrine/Odm/Filter/AbstractFilter.php @@ -14,7 +14,6 @@ namespace ApiPlatform\Doctrine\Odm\Filter; use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface; -use ApiPlatform\Doctrine\Common\Filter\NameConverterAwareInterface; use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface; use ApiPlatform\Doctrine\Common\PropertyHelperTrait; use ApiPlatform\Doctrine\Odm\PropertyHelperTrait as MongoDbOdmPropertyHelperTrait; @@ -33,7 +32,7 @@ * * @author Alan Poulain */ -abstract class AbstractFilter implements FilterInterface, PropertyAwareFilterInterface, ManagerRegistryAwareInterface, NameConverterAwareInterface +abstract class AbstractFilter implements FilterInterface, PropertyAwareFilterInterface, ManagerRegistryAwareInterface { use MongoDbOdmPropertyHelperTrait; use PropertyHelperTrait; @@ -137,23 +136,4 @@ protected function normalizePropertyName(string $property): string return implode('.', array_map($this->nameConverter->normalize(...), explode('.', $property))); } - - public function hasNameConverter(): bool - { - return $this->nameConverter instanceof NameConverterInterface; - } - - public function getNameConverter(): NameConverterInterface - { - if (!$this->hasNameConverter()) { - throw new RuntimeException('NameConverter must be initialized before accessing it.'); - } - - return $this->nameConverter; - } - - public function setNameConverter(NameConverterInterface $nameConverter): void - { - $this->nameConverter = $nameConverter; - } } diff --git a/src/Doctrine/Odm/composer.json b/src/Doctrine/Odm/composer.json index ccf77e59162..cbca401032d 100644 --- a/src/Doctrine/Odm/composer.json +++ b/src/Doctrine/Odm/composer.json @@ -25,7 +25,7 @@ ], "require": { "php": ">=8.2", - "api-platform/doctrine-common": "^4.2.13", + "api-platform/doctrine-common": "^4.2.9", "api-platform/metadata": "^4.2", "api-platform/state": "^4.2.4", "doctrine/mongodb-odm": "^2.10", diff --git a/src/Doctrine/Orm/Extension/ParameterExtension.php b/src/Doctrine/Orm/Extension/ParameterExtension.php index f9a4f95dcce..c21c1018ce9 100644 --- a/src/Doctrine/Orm/Extension/ParameterExtension.php +++ b/src/Doctrine/Orm/Extension/ParameterExtension.php @@ -22,7 +22,6 @@ use Doctrine\Persistence\ManagerRegistry; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; -use Symfony\Component\Serializer\NameConverter\NameConverterInterface; /** * Reads operation parameters and execute its filter. @@ -37,12 +36,10 @@ public function __construct( ContainerInterface $filterLocator, ?ManagerRegistry $managerRegistry = null, ?LoggerInterface $logger = null, - ?NameConverterInterface $nameConverter = null, ) { $this->filterLocator = $filterLocator; $this->managerRegistry = $managerRegistry; $this->logger = $logger; - $this->nameConverter = $nameConverter; } /** diff --git a/src/Doctrine/Orm/Filter/AbstractFilter.php b/src/Doctrine/Orm/Filter/AbstractFilter.php index 6d334bcf296..0f9e7417dd1 100644 --- a/src/Doctrine/Orm/Filter/AbstractFilter.php +++ b/src/Doctrine/Orm/Filter/AbstractFilter.php @@ -14,7 +14,6 @@ namespace ApiPlatform\Doctrine\Orm\Filter; use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface; -use ApiPlatform\Doctrine\Common\Filter\NameConverterAwareInterface; use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface; use ApiPlatform\Doctrine\Common\PropertyHelperTrait; use ApiPlatform\Doctrine\Orm\PropertyHelperTrait as OrmPropertyHelperTrait; @@ -27,7 +26,7 @@ use Psr\Log\NullLogger; use Symfony\Component\Serializer\NameConverter\NameConverterInterface; -abstract class AbstractFilter implements FilterInterface, PropertyAwareFilterInterface, ManagerRegistryAwareInterface, NameConverterAwareInterface +abstract class AbstractFilter implements FilterInterface, PropertyAwareFilterInterface, ManagerRegistryAwareInterface { use OrmPropertyHelperTrait; use PropertyHelperTrait; @@ -112,38 +111,19 @@ protected function isPropertyEnabled(string $property, string $resourceClass): b protected function denormalizePropertyName(string|int $property): string { - if (!$this->hasNameConverter()) { + if (!$this->nameConverter instanceof NameConverterInterface) { return (string) $property; } - return implode('.', array_map($this->getNameConverter()->denormalize(...), explode('.', (string) $property))); + return implode('.', array_map($this->nameConverter->denormalize(...), explode('.', (string) $property))); } protected function normalizePropertyName(string $property): string { - if (!$this->hasNameConverter()) { + if (!$this->nameConverter instanceof NameConverterInterface) { return $property; } - return implode('.', array_map($this->getNameConverter()->normalize(...), explode('.', $property))); - } - - public function hasNameConverter(): bool - { - return $this->nameConverter instanceof NameConverterInterface; - } - - public function getNameConverter(): NameConverterInterface - { - if (!$this->hasNameConverter()) { - throw new RuntimeException('NameConverter must be initialized before accessing it.'); - } - - return $this->nameConverter; - } - - public function setNameConverter(NameConverterInterface $nameConverter): void - { - $this->nameConverter = $nameConverter; + return implode('.', array_map($this->nameConverter->normalize(...), explode('.', $property))); } } diff --git a/src/Doctrine/Orm/composer.json b/src/Doctrine/Orm/composer.json index 0e51ae9f793..0fb956e21f9 100644 --- a/src/Doctrine/Orm/composer.json +++ b/src/Doctrine/Orm/composer.json @@ -24,7 +24,7 @@ ], "require": { "php": ">=8.2", - "api-platform/doctrine-common": "^4.2.13", + "api-platform/doctrine-common": "^4.2.9", "api-platform/metadata": "^4.2", "api-platform/state": "^4.2.4", "doctrine/orm": "^2.17 || ^3.0" diff --git a/src/Symfony/Bundle/Resources/config/doctrine_mongodb_odm.php b/src/Symfony/Bundle/Resources/config/doctrine_mongodb_odm.php index 57abb8970a2..dd74180d259 100644 --- a/src/Symfony/Bundle/Resources/config/doctrine_mongodb_odm.php +++ b/src/Symfony/Bundle/Resources/config/doctrine_mongodb_odm.php @@ -156,7 +156,6 @@ service('api_platform.filter_locator'), service('doctrine_mongodb')->nullOnInvalid(), service('logger')->nullOnInvalid(), - service('api_platform.name_converter')->nullOnInvalid(), ]) ->tag('api_platform.doctrine_mongodb.odm.aggregation_extension.collection', ['priority' => 32]) ->tag('api_platform.doctrine_mongodb.odm.aggregation_extension.item'); diff --git a/src/Symfony/Bundle/Resources/config/doctrine_orm.php b/src/Symfony/Bundle/Resources/config/doctrine_orm.php index e477ac2542d..57504522571 100644 --- a/src/Symfony/Bundle/Resources/config/doctrine_orm.php +++ b/src/Symfony/Bundle/Resources/config/doctrine_orm.php @@ -168,7 +168,6 @@ service('api_platform.filter_locator'), service('doctrine')->nullOnInvalid(), service('logger')->nullOnInvalid(), - service('api_platform.name_converter')->nullOnInvalid(), ]) ->tag('api_platform.doctrine.orm.query_extension.collection', ['priority' => -16]) ->tag('api_platform.doctrine.orm.query_extension.item', ['priority' => -9]);