8000 [Serializer] deserialize from xml: Fix a collection that contains the… · symfony/symfony@1f346f4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1f346f4

Browse files
webnet-frfabpot
authored andcommitted
[Serializer] deserialize from xml: Fix a collection that contains the only one element
1 parent 28c8c85 commit 1f346f4

File tree

2 files changed

+202
-0
lines changed

2 files changed

+202
-0
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,12 @@ private function validateAndDenormalize($currentClass, $attribute, $data, $forma
255255
$builtinType = Type::BUILTIN_TYPE_OBJECT;
256256
$class = $collectionValueType->getClassName().'[]';
257257

258+
// Fix a collection that contains the only one element
259+
// This is special to xml format only
260+
if ('xml' === $format && !is_int(key($data))) {
261+
$data = array($data);
262+
}
263+
258264
if (null !== $collectionKeyType = $type->getCollectionKeyType()) {
259265
$context['key_type'] = $collectionKeyType;
260266
}

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

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@
1313

1414
use Doctrine\Common\Annotations\AnnotationReader;
1515
use PHPUnit\Framework\TestCase;
16+
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
1617
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
1718
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
1819
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
20+
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
21+
use Symfony\Component\Serializer\SerializerAwareInterface;
22+
use Symfony\Component\Serializer\SerializerInterface;
1923

2024
class AbstractObjectNormalizerTest extends TestCase
2125
{
@@ -69,6 +73,75 @@ public function testDenormalizeWithExtraAttributesAndNoGroupsWithMetadataFactory
6973
array('allow_extra_attributes' => false)
7074
);
7175
}
76+
77+
public function testDenormalizeCollectionDecodedFromXmlWithOneChild()
78+
{
79+
$denormalizer = $this->getDenormalizerForDummyCollection();
80+
81+
$dummyCollection = $denormalizer->denormalize(
82+
array(
83+
'children' => array(
84+
'bar' => 'first',
85+
),
86+
),
87+
DummyCollection::class,
88+
'xml'
89+
);
90+
91+
$this->assertInstanceOf(DummyCollection::class, $dummyCollection);
92+
$this->assertInternalType('array', $dummyCollection->children);
93+
$this->assertCount(1, $dummyCollection->children);
94+
$this->assertInstanceOf(DummyChild::class, $dummyCollection->children[0]);
95+
}
96+
97+
public function testDenormalizeCollectionDecodedFromXmlWithTwoChildren()
98+
{
99+
$denormalizer = $this->getDenormalizerForDummyCollection();
100+
101+
$dummyCollection = $denormalizer->denormalize(
102+
array(
103+
'children' => array(
104+
array('bar' => 'first'),
105+
array('bar' => 'second'),
106+
),
107+
),
108+
DummyCollection::class,
109+
'xml'
110+
);
111+
112+
$this->assertInstanceOf(DummyCollection::class, $dummyCollection);
113+
$this->assertInternalType('array', $dummyCollection->children);
114+
$this->assertCount(2, $dummyCollection->children);
115+
$this->assertInstanceOf(DummyChild::class, $dummyCollection->children[0]);
116+
$this->assertInstanceOf(DummyChild::class, $dummyCollection->children[1]);
117+
}
118+
119+
private function getDenormalizerForDummyCollection()
120+
{
121+
$extractor = $this->getMockBuilder('Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor')->getMock();
122+
$extractor->method('getTypes')
123+
->will($this->onConsecutiveCalls(
124+
array(
125+
new \Symfony\Component\PropertyInfo\Type(
126+
'array',
127+
false,
128+
null,
129+
true,
130+
new \Symfony\Component\PropertyInfo\Type('int'),
131+
new \Symfony\Component\PropertyInfo\Type('object', false, DummyChild::class)
132+
),
133+
),
134+
null
135+
));
136+
137+
$denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor);
138+
$arrayDenormalizer = new ArrayDenormalizerDummy();
139+
$serializer = new SerializerCollectionDummy(array($arrayDenormalizer, $denormalizer));
140+
$arrayDenormalizer->setSerializer($serializer);
141+
$denormalizer->setSerializer($serializer);
142+
143+
return $denormalizer;
144+
}
72145
}
73146

74147
class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer
@@ -124,3 +197,126 @@ protected function setAttributeValue($object, $attribute, $value, $format = null
124197
$object->$attribute = $value;
125198
}
126199
}
200+
201+
class DummyCollection
202+
{
203+
/** @var DummyChild[] */
204+
public $children;
205+
}
206+
207+
class DummyChild
208+
{
209+
public $bar;
210+
}
211+
212+
class SerializerCollectionDummy implements \Symfony\Component\Serializer\SerializerInterface, \Symfony\Component\Serializer\Normalizer\DenormalizerInterface
213+
{
214+
/** @var \Symfony\Component\Serializer\Normalizer\DenormalizerInterface */
215+
private $normalizers;
216+
217+
/**
218+
* @param $normalizers
219+
*/
220+
public function __construct($normalizers)
221+
{
222+
$this->normalizers = $normalizers;
223+
}
224+
225+
public function serialize($data, $format, array $context = array())
226+
{
227+
}
228+
229+
public function deserialize($data, $type, $format, array $context = array())
230+
{
231+
}
232+
233+
public function denormalize($data, $type, $format = null, array $context = array())
234+
{
235+
foreach ($this->normalizers as $normalizer) {
236+
if ($normalizer instanceof \Symfony\Component\Serializer\Normalizer\DenormalizerInterface && $normalizer->supportsDenormalization($data, $type, $format, $context)) {
237+
return $normalizer->denormalize($data, $type, $format, $context);
238+
}
239+
}
240+
}
241+
242+
public function supportsDenormalization($data, $type, $format = null)
243+
{
244+
return true;
245+
}
246+
}
247+
248+
class AbstractObjectNormalizerCollectionDummy extends \Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer
249+
{
250+
protected function extractAttributes($object, $format = null, array $context = array())
251+
{
252+
}
253+
254+
protected function getAttributeValue($object, $attribute, $format = null, array $context = array())
255+
{
256+
}
257+
258+
protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array())
259+
{
260+
$object->$attribute = $value;
261+
}
262+
263+
protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = array())
264+
{
265+
return true;
266+
}
267+
268+
public function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes, $format = null)
269+
{
270+
return parent::instantiateObject($data, $class, $context, $reflectionClass, $allowedAttributes, $format);
271+
}
272+
273+
public function serialize($data, $format, array $context = array())
274+
{
275+
}
276+
277+
public function deserialize($data, $type, $format, array $context = array())
278+
{
279+
}
280+
}
281+
282+
class ArrayDenormalizerDummy implements DenormalizerInterface, SerializerAwareInterface
283+
{
284+
/**
285+
* @var SerializerInterface|DenormalizerInterface
286+
*/
287+
private $serializer;
288+
289+
/**
290+
* {@inheritdoc}
291+
*
292+
* @throws NotNormalizableValueException
293+
*/
294+
public function denormalize($data, $class, $format = null, array $context = array())
295+
{
296+
$serializer = $this->serializer;
297+
$class = substr($class, 0, -2);
298+
299+
foreach ($data as $key => $value) {
300+
$data[$key] = $serializer->denormalize($value, $class, $format, $context);
301+
}
302+
303+
return $data;
304+
}
305+
306+
/**
307+
* {@inheritdoc}
308+
*/
309+
public function supportsDenormalization($data, $type, $format = null, array $context = array())
310+
{
311+
return '[]' === substr($type, -2)
312+
&& $this->serializer->supportsDenormalization($data, substr($type, 0, -2), $format, $context);
313+
}
314+
315+
/**
316+
* {@inheritdoc}
317+
*/
318+
public function setSerializer(SerializerInterface $serializer)
319+
{
320+
$this->serializer = $serializer;
321+
}
322+
}

0 commit comments

Comments
 (0)
0