8000 [Serializer] Fix denormalization of arrays · symfony/symfony@99c582b · GitHub
[go: up one dir, main page]

Skip to content

Commit 99c582b

Browse files
dunglasfabpot
authored andcommitted
[Serializer] Fix denormalization of arrays
1 parent d7f8ca7 commit 99c582b

File tree

4 files changed

+70
-13
lines changed

4 files changed

+70
-13
lines changed

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,18 @@ private function validateAndDenormalize($currentClass, $attribute, $data, $forma
248248
return;
249249
}
250250

251-
$builtinType = $type->getBuiltinType();
252-
$class = $type->getClassName();
251+
if ($type->isCollection() && null !== ($collectionValueType = $type->getCollectionValueType()) && Type::BUILTIN_TYPE_OBJECT === $collectionValueType->getBuiltinType()) {
252+
$builtinType = Type::BUILTIN_TYPE_OBJECT;
253+
$class = $collectionValueType->getClassName().'[]';
254+
255+
if (null !== $collectionKeyType = $type->getCollectionKeyType()) {
256+
$context['key_type'] = $collectionKeyType;
257+
}
258+
} else {
259+
$builtinType = $type->getBuiltinType();
260+
$class = $type->getClassName();
261+
}
262+
253263
$expectedTypes[Type::BUILTIN_TYPE_OBJECT === $builtinType && $class ? $class : $builtinType] = true;
254264

255265
if (Type::BUILTIN_TYPE_OBJECT === $builtinType) {

src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Serializer\Exception\BadMethodCallException;
1515
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
16+
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
1617
use Symfony\Component\Serializer\SerializerAwareInterface;
1718
use Symfony\Component\Serializer\SerializerInterface;
1819

@@ -30,6 +31,8 @@ class ArrayDenormalizer implements DenormalizerInterface, SerializerAwareInterfa
3031

3132
/**
3233
* {@inheritdoc}
34+
*
35+
* @throws UnexpectedValueException
3336
*/
3437
public function denormalize($data, $class, $format = null, array $context = array())
3538
{
@@ -46,12 +49,16 @@ public function denormalize($data, $class, $format = null, array $context = arra
4649
$serializer = $this->serializer;
4750
$class = substr($class, 0, -2);
4851

49-
return array_map(
50-
function ($data) use ($serializer, $class, $format, $context) {
51-
return $serializer->denormalize($data, $class, $format, $context);
52-
},
53-
$data
54-
);
52+
$builtinType = isset($context['key_type']) ? $context['key_type']->getBuiltinType() : null;
53+
foreach ($data as $key => $value) {
54+
if (null !== $builtinType && !call_user_func('is_'.$builtinType, $key)) {
55+
throw new UnexpectedValueException(sprintf('The type of the key "%s" must be "%s" ("%s" given).', $key, $builtinType, gettype($key)));
56+
}
57+
58+
$data[$key] = $serializer->denormalize($value, $class, $format, $context);
59+
}
60+
61+
return $data;
5562
}
5663

5764
/**

src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212
namespace Symfony\Component\Serializer\Tests\Normalizer;
1313

1414
use Doctrine\Common\Annotations\AnnotationReader;
15+
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
1516
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
17+
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
1618
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
1719
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
20+
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
1821
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
1922
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
2023
use Symfony\Component\Serializer\Serializer;
@@ -525,13 +528,21 @@ public function testThrowUnexpectedValueException()
525528

526529
public function testDenomalizeRecursive()
527530
{
528-
$normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor());
529-
$serializer = new Serializer(array(new DateTimeNormalizer(), $normalizer));
531+
$extractor = new PropertyInfoExtractor(array(), array(new PhpDocExtractor(), new ReflectionExtractor()));
532+
$normalizer = new ObjectNormalizer(null, null, null, $extractor);
533+
$serializer = new Serializer(array(new ArrayDenormalizer(), new DateTimeNormalizer(), $normalizer));
534+
535+
$obj = $serializer->denormalize(array(
536+
'inner' => array('foo' => 'foo', 'bar' => 'bar'),
537+
'date' => '1988/01/21',
538+
'inners' => array(array('foo' => 1), array('foo' => 2)),
539+
), ObjectOuter::class);
530540

531-
$obj = $serializer->denormalize(array('inner' => array('foo' => 'foo', 'bar' => 'bar'), 'date' => '1988/01/21'), ObjectOuter::class);
532541
$this->assertEquals('foo', $obj->getInner()->foo);
533542
$this->assertEquals('bar', $obj->getInner()->bar);
534543
$this->assertEquals('1988-01-21', $obj->getDate()->format('Y-m-d'));
544+
$this->assertEquals(1, $obj->getInners()[0]->foo);
545+
$this->assertEquals(2, $obj->getInners()[1]->foo);
535546
}
536547

537548
/**
@@ -546,6 +557,19 @@ public function testRejectInvalidType()
546557
$serializer->denormalize(array('date' => 'foo'), ObjectOuter::class);
547558
}
548559

560+
/**
561+
* @expectedException UnexpectedValueException
562+
* @expectedExceptionMessage The type of the key "a" must be "int" ("string" given).
563+
*/
564+
public function testRejectInvalidKey()
565+
{
566+
$extractor = new PropertyInfoExtractor(array(), array(new PhpDocExtractor(), new ReflectionExtractor()));
567+
$normalizer = new ObjectNormalizer(null, null, null, $extractor);
568+
$serializer = new Serializer(array(new ArrayDenormalizer(), new DateTimeNormalizer(), $normalizer));
569+
570+
$serializer->denormalize(array('inners' => array('a' => array('foo' => 1))), ObjectOuter::class);
571+
}
572+
549573
public function testExtractAttributesRespectsFormat()
550574
{
551575
$normalizer = new FormatAndContextAwareNormalizer();
@@ -740,6 +764,11 @@ class ObjectOuter
740764
private $inner;
741765
private $date;
742766

767+
/**
768+
* @var ObjectInner[]
769+
*/
770+
private $inners;
771+
743772
public function getInner()
744773
{
745774
return $this->inner;
@@ -759,6 +788,16 @@ public function getDate()
759788
{
760789
return $this->date;
761790
}
791+
792+
public function setInners(array $inners)
793+
{
794+
$this->inners = $inners;
795+
}
796+
797+
public function getInners()
798+
{
799+
return $this->inners;
800+
}
762801
}
763802

764803
class ObjectInner

src/Symfony/Component/Serializer/composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@
2424
"symfony/property-access": "~2.8|~3.0",
2525
"symfony/http-foundation": "~2.8|~3.0",
2626
"symfony/cache": "~3.1",
27-
"symfony/property-info": "~2.8|~3.0",
27+
"symfony/property-info": "~3.1",
2828
"doctrine/annotations": "~1.0",
29-
"doctrine/cache": "~1.0"
29+
"doctrine/cache": "~1.0",
30+
"phpdocumentor/reflection-docblock": "~3.0"
3031
},
3132
"conflict": {
3233
"symfony/property-access": ">=3.0,<3.0.4|>=2.8,<2.8.4"

0 commit comments

Comments
 (0)
0