From 4d4668268333aa32cf400cd289fd7672b8a0783f Mon Sep 17 00:00:00 2001 From: Valmonzo Date: Sat, 18 Jan 2025 22:29:43 +0100 Subject: [PATCH] [Serializer] fix default context in Serializer --- .../DependencyInjection/SerializerPass.php | 1 + .../Component/Serializer/Serializer.php | 21 ++++++++++++++--- .../SerializerPassTest.php | 15 ++++++++++++ .../Serializer/Tests/SerializerTest.php | 23 +++++++++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php b/src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php index d0b0deb48cf6d..06de74c636e91 100644 --- a/src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php +++ b/src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php @@ -55,6 +55,7 @@ public function process(ContainerBuilder $container) $definition->setBindings(['array $defaultContext' => new BoundArgument($defaultContext, false)] + $definition->getBindings()); } + $container->getDefinition('serializer')->addMethodCall('setDefaultContext', [$defaultContext]); $container->getParameterBag()->remove('serializer.default_context'); } diff --git a/src/Symfony/Component/Serializer/Serializer.php b/src/Symfony/Component/Serializer/Serializer.php index 7044c2f207be7..e5c8a8d38d220 100644 --- a/src/Symfony/Component/Serializer/Serializer.php +++ b/src/Symfony/Component/Serializer/Serializer.php @@ -81,6 +81,11 @@ class Serializer implements SerializerInterface, ContextAwareNormalizerInterface */ private array $normalizerCache = []; + /** + * @var array + */ + private array $defaultContext = []; + /** * @param array $normalizers * @param array $encoders @@ -163,12 +168,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 +225,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']; @@ -430,4 +435,14 @@ public function supportsDecoding(string $format, array $context = []): bool { return $this->decoder->supportsDecoding($format, $context); } + + /** + * @internal + * + * @param array $defaultContext + */ + public function setDefaultContext(array $defaultContext): void + { + $this->defaultContext = $defaultContext; + } } diff --git a/src/Symfony/Component/Serializer/Tests/DependencyInjection/SerializerPassTest.php b/src/Symfony/Component/Serializer/Tests/DependencyInjection/SerializerPassTest.php index eb77263f49fc9..970c4e1623775 100644 --- a/src/Symfony/Component/Serializer/Tests/DependencyInjection/SerializerPassTest.php +++ b/src/Symfony/Component/Serializer/Tests/DependencyInjection/SerializerPassTest.php @@ -115,4 +115,19 @@ public function testNormalizersAndEncodersAreDecoredAndOrderedWhenCollectingData $this->assertEquals(new Reference('e'), $traceableEncoderDefinition->getArgument(0)); $this->assertEquals(new Reference('serializer.data_collector'), $traceableEncoderDefinition->getArgument(1)); } + + public function testSetDefaultContext() + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.debug', false); + $container->setParameter('serializer.default_context', ['enable_max_depth' => true]); + $container->register('serializer')->setArguments([null, null]); + $container->register('n')->addTag('serializer.normalizer'); + $container->register('e')->addTag('serializer.encoder'); + + $serializerPass = new SerializerPass(); + $serializerPass->process($container); + + $this->assertSame([['setDefaultContext', [['enable_max_depth' => true]]]], $container->getDefinition('serializer')->getMethodCalls()); + } } diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index 8f60ae1d44258..31a7a7f4bed59 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -1652,6 +1652,29 @@ public function testPartialDenormalizationWithInvalidVariadicParameter() DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true, ]); } + + public function testEmptyArrayAsObjectDefaultContext() + { + $serializer = new Serializer(); + $serializer->setDefaultContext([Serializer::EMPTY_ARRAY_AS_OBJECT => true]); + $this->assertEquals(new \ArrayObject(), $serializer->normalize([])); + } + + public function testPreserveEmptyObjectsAsDefaultContext() + { + $serializer = new Serializer(); + $serializer->setDefaultContext([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()], []); + $serializer->setDefaultContext([DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true]); + $this->expectException(PartialDenormalizationException::class); + $serializer->denormalize($data, DummyWithVariadicParameter::class); + } } class Model