diff --git a/src/Metadata/Property/Factory/SerializerPropertyMetadataFactory.php b/src/Metadata/Property/Factory/SerializerPropertyMetadataFactory.php index e539a8906da..9a92fd75e52 100644 --- a/src/Metadata/Property/Factory/SerializerPropertyMetadataFactory.php +++ b/src/Metadata/Property/Factory/SerializerPropertyMetadataFactory.php @@ -17,6 +17,7 @@ use ApiPlatform\Metadata\Exception\ResourceClassNotFoundException; use ApiPlatform\Metadata\ResourceClassResolverInterface; use ApiPlatform\Metadata\Util\ResourceClassInfoTrait; +use Doctrine\ORM\Mapping\DiscriminatorMap; use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface as SerializerClassMetadataFactoryInterface; @@ -30,7 +31,7 @@ final class SerializerPropertyMetadataFactory implements PropertyMetadataFactory { use ResourceClassInfoTrait; - public function __construct(private readonly SerializerClassMetadataFactoryInterface $serializerClassMetadataFactory, private readonly PropertyMetadataFactoryInterface $decorated, ?ResourceClassResolverInterface $resourceClassResolver = null) + public function __construct(private readonly SerializerClassMetadataFactoryInterface $serializerClassMetadataFactory, private readonly PropertyMetadataFactoryInterface $decorated, ?ResourceClassResolverInterface $resourceClassResolver = null, private readonly ?bool $normalizeChildClassAttributeGroups = null) { $this->resourceClassResolver = $resourceClassResolver; } @@ -203,6 +204,18 @@ private function getClassSerializerGroups(string $class): array $groups[] = $serializerAttributeMetadata->getGroups(); } + if (true === $this->normalizeChildClassAttributeGroups) { + foreach ($serializerClassMetadata->getReflectionClass()->getAttributes() as $reflectionAttribute) { + if (DiscriminatorMap::class !== $reflectionAttribute->getName()) { + continue; + } + + foreach ($reflectionAttribute->getArguments()[0] as $class) { + $groups = [...$groups, $this->getClassSerializerGroups($class)]; + } + } + } + return array_unique(array_merge(...$groups)); } } diff --git a/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php b/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php index c07c6a07db3..9d02012cb85 100644 --- a/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php +++ b/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php @@ -257,6 +257,7 @@ private function registerCommonConfiguration(ContainerBuilder $container, array $container->setParameter('api_platform.description', $config['description']); $container->setParameter('api_platform.version', $config['version']); $container->setParameter('api_platform.show_webby', $config['show_webby']); + $container->setParameter('api_platform.normalize_child_class_attribute_groups', $config['normalize_child_class_attribute_groups']); $container->setParameter('api_platform.url_generation_strategy', $config['defaults']['url_generation_strategy'] ?? UrlGeneratorInterface::ABS_PATH); $container->setParameter('api_platform.exception_to_status', $config['exception_to_status']); $container->setParameter('api_platform.formats', $formats); diff --git a/src/Symfony/Bundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/DependencyInjection/Configuration.php index 1c55ae97501..f68a728370a 100644 --- a/src/Symfony/Bundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/DependencyInjection/Configuration.php @@ -88,6 +88,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->booleanNode('show_webby')->defaultTrue()->info('If true, show Webby on the documentation page')->end() ->booleanNode('event_listeners_backward_compatibility_layer')->defaultNull()->info('If true API Platform uses Symfony event listeners instead of providers and processors.')->end() ->booleanNode('use_symfony_listeners')->defaultNull()->info(sprintf('Uses Symfony event listeners instead of the %s.', MainController::class))->end() + ->booleanNode('normalize_child_class_attribute_groups')->defaultNull()->info('Search in child classes groups for normalization')->end() ->scalarNode('name_converter')->defaultNull()->info('Specify a name converter to use.')->end() ->scalarNode('asset_package')->defaultNull()->info('Specify an asset package name to use.')->end() ->scalarNode('path_segment_name_generator')->defaultValue('api_platform.metadata.path_segment_name_generator.underscore')->info('Specify a path name generator to use.')->end() diff --git a/src/Symfony/Bundle/Resources/config/metadata/property.xml b/src/Symfony/Bundle/Resources/config/metadata/property.xml index 1a0e221399a..47fd1110516 100644 --- a/src/Symfony/Bundle/Resources/config/metadata/property.xml +++ b/src/Symfony/Bundle/Resources/config/metadata/property.xml @@ -21,6 +21,7 @@ + %api_platform.normalize_child_class_attribute_groups% diff --git a/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php b/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php index c7259d7b7de..73a02fe9b96 100644 --- a/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php +++ b/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php @@ -232,6 +232,7 @@ private function runDefaultConfigTests(array $doctrineIntegrationsToLoad = ['orm 'use_symfony_listeners' => false, 'handle_symfony_errors' => false, 'enable_link_security' => false, + 'normalize_child_class_attribute_groups' => null, ], $config); }