From 3fffa96928655a3ab335c45c3f36d183320a5221 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 16 Aug 2020 09:55:33 +0200 Subject: [PATCH] [Serializer] Fix variadic support when using type hints --- .../Normalizer/AbstractObjectNormalizer.php | 2 +- .../VariadicConstructorTypedArgsDummy.php | 1 + .../Normalizer/AbstractNormalizerTest.php | 42 ++++++++++++++++--- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 78a297b347..c252f4cdbc 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -304,7 +304,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer */ protected function denormalizeParameter(\ReflectionClass $class, \ReflectionParameter $parameter, $parameterName, $parameterData, array $context, $format = null) { - if (null === $this->propertyTypeExtractor || null === $this->propertyTypeExtractor->getTypes($class->getName(), $parameterName)) { + if ((method_exists($parameter, 'isVariadic') && $parameter->isVariadic()) || null === $this->propertyTypeExtractor || null === $this->propertyTypeExtractor->getTypes($class->getName(), $parameterName)) { return parent::denormalizeParameter($class, $parameter, $parameterName, $parameterData, $context, $format); } diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/VariadicConstructorTypedArgsDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/VariadicConstructorTypedArgsDummy.php index 9c6fd980a1..020fd0d229 100644 --- a/src/Symfony/Component/Serializer/Tests/Fixtures/VariadicConstructorTypedArgsDummy.php +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/VariadicConstructorTypedArgsDummy.php @@ -20,6 +20,7 @@ class VariadicConstructorTypedArgsDummy $this->foo = $foo; } + /** @return Dummy[] */ public function getFoo() { return $this->foo; diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php index b9af165a5e..00b80bbc75 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php @@ -4,6 +4,8 @@ namespace Symfony\Component\Serializer\Tests\Normalizer; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; +use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Mapping\AttributeMetadata; use Symfony\Component\Serializer\Mapping\ClassMetadata; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; @@ -135,19 +137,49 @@ class AbstractNormalizerTest extends TestCase } /** + * @dataProvider getNormalizer + * * @requires PHP 5.6 */ - public function testObjectWithVariadicConstructorTypedArguments() + public function testObjectWithVariadicConstructorTypedArguments(AbstractNormalizer $normalizer) { - $normalizer = new PropertyNormalizer(); - $normalizer->setSerializer(new Serializer([$normalizer])); - $data = ['foo' => [['foo' => 'Foo', 'bar' => 'Bar', 'baz' => 'Baz', 'qux' => 'Qux'], ['foo' => 'FOO', 'bar' => 'BAR', 'baz' => 'BAZ', 'qux' => 'QUX']]]; - $dummy = $normalizer->denormalize($data, VariadicConstructorTypedArgsDummy::class); + $d1 = new Dummy(); + $d1->foo = 'Foo'; + $d1->bar = 'Bar'; + $d1->baz = 'Baz'; + $d1->qux = 'Quz'; + $d2 = new Dummy(); + $d2->foo = 'FOO'; + $d2->bar = 'BAR'; + $d2->baz = 'BAZ'; + $d2->qux = 'QUZ'; + $obj = new VariadicConstructorTypedArgsDummy($d1, $d2); + $serializer = new Serializer([$normalizer], [new JsonEncoder()]); + $normalizer->setSerializer($serializer); + $data = $serializer->serialize($obj, 'json'); + $dummy = $normalizer->denormalize(json_decode($data, true), VariadicConstructorTypedArgsDummy::class); + $this->assertInstanceOf(VariadicConstructorTypedArgsDummy::class, $dummy); + $this->assertCount(2, $dummy->getFoo()); + foreach ($dummy->getFoo() as $foo) { + $this->assertInstanceOf(Dummy::class, $foo); + } + + $dummy = $serializer->deserialize($data, VariadicConstructorTypedArgsDummy::class, 'json'); $this->assertInstanceOf(VariadicConstructorTypedArgsDummy::class, $dummy); $this->assertCount(2, $dummy->getFoo()); foreach ($dummy->getFoo() as $foo) { $this->assertInstanceOf(Dummy::class, $foo); } } + + public function getNormalizer() + { + $extractor = new PhpDocExtractor(); + + yield [new PropertyNormalizer()]; + yield [new PropertyNormalizer(null, null, $extractor)]; + yield [new ObjectNormalizer()]; + yield [new ObjectNormalizer(null, null, null, $extractor)]; + } }