From 4400674a192e0967d55e7c4b354288f66e9d18e0 Mon Sep 17 00:00:00 2001 From: Valmonzo Date: Fri, 15 Nov 2024 16:13:35 +0100 Subject: [PATCH] [Serializer] fix default context in Serializer --- .../Resources/config/serializer.php | 2 +- .../DependencyInjection/SerializerPass.php | 1 + .../Component/Serializer/Serializer.php | 8 +++--- .../SerializerPassTest.php | 7 +++-- .../Serializer/Tests/SerializerTest.php | 26 +++++++++++++++++++ 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php index 85231d0bf3ac0..c29258d527ec3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php @@ -60,7 +60,7 @@ $container->services() ->set('serializer', Serializer::class) - ->args([[], []]) + ->args([[], [], []]) ->alias(SerializerInterface::class, 'serializer') ->alias(NormalizerInterface::class, 'serializer') diff --git a/src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php b/src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php index d0b0deb48cf6d..c2959ecdac397 100644 --- a/src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php +++ b/src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php @@ -56,6 +56,7 @@ public function process(ContainerBuilder $container) } $container->getParameterBag()->remove('serializer.default_context'); + $container->getDefinition('serializer')->setArgument('$defaultContext', $defaultContext); } if ($container->getParameter('kernel.debug') && $container->hasDefinition('serializer.data_collector')) { diff --git a/src/Symfony/Component/Serializer/Serializer.php b/src/Symfony/Component/Serializer/Serializer.php index 7044c2f207be7..e17042097fe3c 100644 --- a/src/Symfony/Component/Serializer/Serializer.php +++ b/src/Symfony/Component/Serializer/Serializer.php @@ -84,10 +84,12 @@ class Serializer implements SerializerInterface, ContextAwareNormalizerInterface /** * @param array $normalizers * @param array $encoders + * @param array $defaultContext */ public function __construct( private array $normalizers = [], array $encoders = [], + private array $defaultContext = [], ) { foreach ($normalizers as $normalizer) { if ($normalizer instanceof SerializerAwareInterface) { @@ -163,12 +165,12 @@ public function normalize(mixed $data, ?string $format = null, array $context = return $data; } - if (\is_array($data) && !$data && ($context[self::EMPTY_ARRAY_AS_OBJECT] ?? false)) { + if (\is_array($data) && !$data && ($context[self::EMPTY_ARRAY_AS_OBJECT] ?? $this->defaultContext[self::EMPTY_ARRAY_AS_OBJECT] ?? false)) { return new \ArrayObject(); } if (is_iterable($data)) { - if ($data instanceof \Countable && ($context[AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS] ?? false) && !\count($data)) { + if ($data instanceof \Countable && ($context[AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS] ?? $this->defaultContext[AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS] ?? false) && !\count($data)) { return new \ArrayObject(); } @@ -220,7 +222,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a throw new NotNormalizableValueException(sprintf('Could not denormalize object of type "%s", no supporting normalizer found.', $type)); } - if (isset($context[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS])) { + if (isset($context[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS]) || isset($this->defaultContext[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS])) { unset($context[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS]); $context['not_normalizable_value_exceptions'] = []; $errors = &$context['not_normalizable_value_exceptions']; diff --git a/src/Symfony/Component/Serializer/Tests/DependencyInjection/SerializerPassTest.php b/src/Symfony/Component/Serializer/Tests/DependencyInjection/SerializerPassTest.php index eb77263f49fc9..b2f4fa7ad6a4c 100644 --- a/src/Symfony/Component/Serializer/Tests/DependencyInjection/SerializerPassTest.php +++ b/src/Symfony/Component/Serializer/Tests/DependencyInjection/SerializerPassTest.php @@ -77,9 +77,11 @@ public function testServicesAreOrderedAccordingToPriority() public function testBindSerializerDefaultContext() { + $context = ['enable_max_depth' => true]; + $container = new ContainerBuilder(); $container->setParameter('kernel.debug', false); - $container->register('serializer')->setArguments([null, null]); + $container->register('serializer')->setArguments([null, null, []]); $container->setParameter('serializer.default_context', ['enable_max_depth' => true]); $definition = $container->register('n1')->addTag('serializer.normalizer')->addTag('serializer.encoder'); @@ -87,7 +89,8 @@ public function testBindSerializerDefaultContext() $serializerPass->process($container); $bindings = $definition->getBindings(); - $this->assertEquals($bindings['array $defaultContext'], new BoundArgument(['enable_max_depth' => true], false)); + $this->assertEquals($bindings['array $defaultContext'], new BoundArgument($context, false)); + $this->assertEquals($context, $container->getDefinition('serializer')->getArgument('$defaultContext')); } public function testNormalizersAndEncodersAreDecoredAndOrderedWhenCollectingData() diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index 8f60ae1d44258..8a8a54e98178a 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -1652,6 +1652,32 @@ public function testPartialDenormalizationWithInvalidVariadicParameter() DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true, ]); } + + public function testEmptyArrayAsObjectDefaultContext() + { + $serializer = new Serializer( + defaultContext: [Serializer::EMPTY_ARRAY_AS_OBJECT => true], + ); + $this->assertEquals(new \ArrayObject(), $serializer->normalize([])); + } + + public function testPreserveEmptyObjectsAsDefaultContext() + { + $serializer = new Serializer( + defaultContext: [AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS => true], + ); + $this->assertEquals(new \ArrayObject(), $serializer->normalize(new \ArrayIterator())); + } + + public function testCollectDenormalizationErrorsDefaultContext() + { + $data = ['variadic' => ['a random string']]; + $serializer = new Serializer([new UidNormalizer(), new ObjectNormalizer()], [], [DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true]); + + $this->expectException(PartialDenormalizationException::class); + + $serializer->denormalize($data, DummyWithVariadicParameter::class); + } } class Model