diff --git a/src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php b/src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php index 179b7a3d92e9d..a4f66e71fbdb3 100644 --- a/src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php +++ b/src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php @@ -19,6 +19,7 @@ use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\Serializer\Debug\TraceableEncoder; use Symfony\Component\Serializer\Debug\TraceableNormalizer; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\SerializerInterface; @@ -204,30 +205,37 @@ private function buildChildNameConverterDefinition(ContainerBuilder $container, private function buildChildDefinitions(ContainerBuilder $container, string $serializerName, array $services, array $config): array { foreach ($services as &$id) { - $childId = $id.'.'.$serializerName; - - $definition = $container->registerChild($childId, (string) $id) - ->setClass($container->getDefinition((string) $id)->getClass()) - ; - - if (null !== $nameConverterIndex = $this->findNameConverterIndex($container, (string) $id)) { - $definition->replaceArgument($nameConverterIndex, new Reference($config['name_converter'])); - } - - $id = new Reference($childId); + $id = $this->buildChildDefinition($container, $serializerName, (string) $id, $config); } return $services; } - private function findNameConverterIndex(ContainerBuilder $container, string $id): int|string|null + private function buildChildDefinition(ContainerBuilder $container, string $serializerName, string $id, array $config): Reference { - foreach ($container->getDefinition($id)->getArguments() as $index => $argument) { - if ($argument instanceof Reference && self::NAME_CONVERTER_METADATA_AWARE_ID === (string) $argument) { - return $index; + $childId = $id.'.'.$serializerName; + + $definition = $container->getDefinition($id); + $childDefinition = $container->registerChild($childId, $id) + ->setClass($definition->getClass()) + ; + + foreach ($definition->getArguments() as $index => $argument) { + if (!$argument instanceof Reference) { + continue; + } + + if (self::NAME_CONVERTER_METADATA_AWARE_ID === (string) $argument) { + $childDefinition->replaceArgument($index, new Reference($config['name_converter'])); + } elseif ( + $container->hasDefinition($argument) + && is_a(($argDefinition = $container->getDefinition($argument))->getClass(), NormalizerInterface::class, true) + && !$argDefinition->hasTag('serializer.normalizer') + ) { + $childDefinition->replaceArgument($index, $this->buildChildDefinition($container, $serializerName, (string) $argument, $config)); } } - return null; + return new Reference($childId); } } diff --git a/src/Symfony/Component/Serializer/Tests/DependencyInjection/SerializerPassTest.php b/src/Symfony/Component/Serializer/Tests/DependencyInjection/SerializerPassTest.php index 88ec02b87c57d..1f1761968a1ee 100644 --- a/src/Symfony/Component/Serializer/Tests/DependencyInjection/SerializerPassTest.php +++ b/src/Symfony/Component/Serializer/Tests/DependencyInjection/SerializerPassTest.php @@ -20,6 +20,7 @@ use Symfony\Component\Serializer\Debug\TraceableSerializer; use Symfony\Component\Serializer\DependencyInjection\SerializerPass; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; +use Symfony\Component\Serializer\Normalizer\PropertyNormalizer; use Symfony\Component\Serializer\SerializerInterface; /** @@ -113,8 +114,7 @@ public function testBindObjectNormalizerDefaultContext(array $parameters, array $container->setParameter('kernel.debug', false); $container->register('serializer')->setArguments([null, null, []]); $container->getParameterBag()->add($parameters); - $definition = $container->register('serializer.normalizer.object') - ->setClass(ObjectNormalizer::class) + $definition = $container->register('serializer.normalizer.object', ObjectNormalizer::class) ->addTag('serializer.normalizer') ->addTag('serializer.encoder') ; @@ -620,8 +620,7 @@ public function testBindNamedSerializerObjectNormalizerDefaultContext(array $def $container->register('serializer')->setArguments([null, null, []]); $container->getParameterBag()->add($parameters); - $container->register('serializer.normalizer.object') - ->setClass(ObjectNormalizer::class) + $container->register('serializer.normalizer.object', ObjectNormalizer::class) ->addTag('serializer.normalizer', ['serializer' => '*']) ->addTag('serializer.encoder', ['serializer' => '*']) ; @@ -702,4 +701,34 @@ public function testNormalizersAndEncodersAreDecoratedAndOrderedWhenCollectingDa $this->assertEquals(new Reference('serializer.data_collector'), $traceableEncoderDefinition->getArgument(1)); $this->assertSame('api', $traceableEncoderDefinition->getArgument(2)); } + + public function testPropertyNormalizerChildDefinitionIsRegisteredWhenUsingNamedSerializer() + { + $container = new ContainerBuilder(); + + $container->setParameter('kernel.debug', false); + $container->setParameter('.serializer.named_serializers', [ + 'api' => ['name_converter' => 'my.name_converter'], + ]); + + $container->register('serializer')->setArguments([null, null]); + $container->register('serializer.normalizer.property', PropertyNormalizer::class) + ->setArguments([null, new Reference('serializer.name_converter.metadata_aware')]) + ; + $container->register('n1') + ->addArgument(new Reference('serializer.normalizer.property')) + ->addTag('serializer.normalizer', ['serializer' => '*']) + ->addTag('serializer.encoder', ['serializer' => '*']) + ; + + $serializerPass = new SerializerPass(); + $serializerPass->process($container); + + $this->assertEquals(new Reference('serializer.normalizer.property'), $container->getDefinition('n1')->getArgument(0)); + $this->assertEquals(new Reference('serializer.normalizer.property.api'), $container->getDefinition('n1.api')->getArgument(0)); + + $nameConverter = (string) $container->getDefinition('serializer.normalizer.property.api')->getArgument(1); + $this->assertStringStartsWith('serializer.name_converter.metadata_aware.', $nameConverter); + $this->assertEquals(new Reference('my.name_converter'), $container->getDefinition($nameConverter)->getArgument(0)); + } }