8000 Add support for nested attributes · symfony/symfony@b142c32 · GitHub
[go: up one dir, main page]

Skip to content

Commit b142c32

Browse files
committed
Add support for nested attributes
1 parent 527bc77 commit b142c32

File tree

3 files changed

+99
-16
lines changed

3 files changed

+99
-16
lines changed

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

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,11 @@ protected function isAllowedAttribute($classOrObject, $attribute, $format = null
240240
return false;
241241
}
242242

243+
if (isset($context['attributes'][$attribute])) {
244+
// Nested attributes
245+
return true;
246+
}
247+
243248
if (isset($context['attributes']) && is_array($context['attributes'])) {
244249
return in_array($attribute, $context['attributes'], true);
245250
}
@@ -332,7 +337,7 @@ protected function instantiateObject(array &$data, $class, array &$context, \Ref
332337
$key = $this->nameConverter ? $this->nameConverter->normalize($paramName) : $paramName;
333338

334339
$allowed = $allowedAttributes === false || in_array($paramName, $allowedAttributes);
335-
$ignored = in_array($paramName, $this->ignoredAttributes);
340+
$ignored = !$this->isAllowedAttribute($class, $paramName, $format, $context);
336341
if (method_exists($constructorParameter, 'isVariadic') && $constructorParameter->isVariadic()) {
337342
if ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) {
338343
if (!is_array($data[$paramName])) {
@@ -349,7 +354,7 @@ protected function instantiateObject(array &$data, $class, array &$context, \Ref
349354
throw new LogicException(sprintf('Cannot create an instance of %s from serialized data because the serializer inject in "%s" is not a denormalizer', $constructorParameter->getClass(), static::class));
350355
}
351356
$parameterClass = $constructorParameter->getClass()->getName();
352-
$parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $context);
357+
$parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $paramName));
353358
}
354359
} catch (\ReflectionException $e) {
355360
throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $key), 0, $e);
@@ -380,4 +385,21 @@ protected function instantiateObject(array &$data, $class, array &$context, \Ref
380385

381386
return new $class();
382387
}
388+
389+
/**
390+
* @internal
391+
*
392+
* @param array $parentContext
393+
* @param string $attribute
394+
*
395+
* @return array
396+
*/
397+
protected function createChildContext(array $parentContext, $attribute)
398+
{
399+
if (isset($parentContext['attributes'][$attribute])) {
400+
$parentContext['attributes'] = $parentContext['attributes'][$attribute];
401+
}
402+
403+
return $parentContext;
404+
}
383405
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public function normalize($object, $format = null, array $context = array())
9595
throw new LogicException(sprintf('Cannot normalize attribute "%s" because the injected serializer is not a normalizer', $attribute));
9696
}
9797

98-
$data = $this->updateData($data, $attribute, $this->serializer->normalize($attributeValue, $format, $context));
98+
$data = $this->updateData($data, $ 67E6 attribute, $this->serializer->normalize($attributeValue, $format, $this->createChildContext($context, $attribute)));
9999
}
100100

101101
return $data;
@@ -268,7 +268,7 @@ private function validateAndDenormalize($currentClass, $attribute, $data, $forma
268268
}
269269

270270
if ($this->serializer->supportsDenormalization($data, $class, $format)) {
271-
return $this->serializer->denormalize($data, $class, $format, $context);
271+
return $this->serializer->denormalize($data, $class, $format, $this->createChildContext($context, $attribute));
272272
}
273273
}
274274

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

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -647,28 +647,65 @@ public function testExtractAttributesRespectsContext()
647647
public function testAttributesContextNormalize()
648648
{
649649
$normalizer = new ObjectNormalizer();
650+
$serializer = new Serializer(array($normalizer));
651+
652+
$objectInner = new ObjectInner();
653+
$objectInner->foo = 'innerFoo';
654+
$objectInner->bar = 'innerBar';
650655

651656
$objectDummy = new ObjectDummy();
652657
$objectDummy->setFoo('foo');
653-
$objectDummy->setBaz('baz');
658+
$objectDummy->setBaz(true);
659+
$objectDummy->setObject($objectInner);
654660

655-
$context = array('attributes' => array('foo', 'baz'));
656-
$this->assertEquals(array('foo' => 'foo', 'baz' => 'baz'), $normalizer->normalize($objectDummy, null, $context));
661+
$context = array('attributes' => array('foo', 'baz', 'object' => array('foo')));
662+
$this->assertEquals(
663+
array(
664+
'foo' => 'foo',
665+
'baz' => true,
666+
'object' => array('foo' => 'innerFoo'),
667+
),
668+
$serializer->normalize($objectDummy, null, $context)
669+
);
657670
}
658671

659672
public function testAttributesContextDenormalize()
660673
{
661-
$normalizer = new ObjectNormalizer();
674+
$normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor());
675+
$serializer = new Serializer(array($normalizer));
662676

663-
$expected = new ObjectDummy();
664-
$expected->setFoo('foo');
665-
$expected->setBaz('baz');
677+
$objectInner = new ObjectInner();
678+
$objectInner->foo = 'innerFoo';
666679

667-
$context = array('attributes' => array('foo', 'baz'));
668-
$this->assertEquals(
669-
$expected,
670-
$normalizer->denormalize(array('foo' => 'foo', 'baz' => 'baz', 'bar' => 'bar'), ObjectDummy::class, null, $context)
671-
);
680+
$objectOuter = new ObjectOuter();
681+
$objectOuter->bar = 'bar';
682+
$objectOuter->setInner($objectInner);
683+
684+
$context = array('attributes' => array('bar', 'inner' => array('foo')));
685+
$this->assertEquals($objectOuter, $serializer->denormalize(
686+
array(
687+
'foo' => 'foo',
688+
'bar' => 'bar',
689+
'date' => '2017-02-03',
690+
'inner' => array('foo' => 'innerFoo', 'bar' => 'innerBar'),
691+
), ObjectOuter::class, null, $context));
692+
}
693+
694+
public function testAttributesContextDenormalizeConstructor()
695+
{
696+
$normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor());
697+
$serializer = new Serializer(array($normalizer));
698+
699+
$objectInner = new ObjectInner();
700+
$objectInner->bar = 'bar';
701+
702+
$obj = new DummyWithConstructorObjectAndDefaultValue('a', $objectInner);
703+
704+
$context = array('attributes' => array('inner' => array('bar')));
705+
$this->assertEquals($obj, $serializer->denormalize(array(
706+
'foo' => 'b',
707+
'inner' => array('foo' => 'foo', 'bar' => 'bar'),
708+
), DummyWithConstructorObjectAndDefaultValue::class, null, $context));
672709
}
673710
}
674711

@@ -840,6 +877,8 @@ public function setFoo(array $f)
840877

841878
class ObjectOuter
842879
{
880+
public $foo;
881+
public $bar;
843882
private $inner;
844883
private $date;
845884

@@ -937,3 +976,25 @@ class JsonNumber
937976
*/
938977
public $number;
939978
}
979+
980+
class DummyWithConstructorObjectAndDefaultValue
981+
{
982+
private $foo;
983+
private $inner;
984+
985+
public function __construct($foo = 'a', ObjectInner $inner)
986+
{
987+
$this->foo = $foo;
988+
$this->inner = $inner;
989+
}
990+
991+
public function getFoo()
992+
{
993+
return $this->foo;
994+
}
995+
996+
public function getInner()
997+
{
998+
return $this->inner;
999+
}
1000+
}

0 commit comments

Comments
 (0)
0