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);
}