Skip to content

Commit a2cd56c

Browse files
bug #33733 [Serializer] fix denormalization of string-arrays with only one element (mkrauser)
This PR was merged into the 3.4 branch. Discussion ---------- [Serializer] fix denormalization of string-arrays with only one element | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? |no | Deprecations? |no | Tickets | Fix #33731 | License | MIT | Doc PR | This PR does almost the same as ac70edf, just not only for arrays of objects. Commits ------- 8814751 [Serializer] fix denormalization of string-arrays with only one element #33731
2 parents 03f2adc + 8814751 commit a2cd56c

File tree

2 files changed

+63
-17
lines changed

2 files changed

+63
-17
lines changed

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -244,16 +244,18 @@ private function validateAndDenormalize($currentClass, $attribute, $data, $forma
244244
return null;
245245
}
246246

247-
if ($type->isCollection() && null !== ($collectionValueType = $type->getCollectionValueType()) && Type::BUILTIN_TYPE_OBJECT === $collectionValueType->getBuiltinType()) {
247+
$collectionValueType = $type->isCollection() ? $type->getCollectionValueType() : null;
248+
249+
// Fix a collection that contains the only one element
250+
// This is special to xml format only
251+
if ('xml' === $format && null !== $collectionValueType && (!\is_array($data) || !\is_int(key($data)))) {
252+
$data = [$data];
253+
}
254+
255+
if (null !== $collectionValueType && Type::BUILTIN_TYPE_OBJECT === $collectionValueType->getBuiltinType()) {
248256
$builtinType = Type::BUILTIN_TYPE_OBJECT;
249257
$class = $collectionValueType->getClassName().'[]';
250258

251-
// Fix a collection that contains the only one element
252-
// This is special to xml format only
253-
if ('xml' === $format && !\is_int(key($data))) {
254-
$data = [$data];
255-
}
256-
257259
if (null !== $collectionKeyType = $type->getCollectionKeyType()) {
258260
$context['key_type'] = $collectionKeyType;
259261
}

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

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,54 @@ private function getDenormalizerForDummyCollection()
121121
$extractor = $this->getMockBuilder(PhpDocExtractor::class)->getMock();
122122
$extractor->method('getTypes')
123123
->will($this->onConsecutiveCalls(
124-
[
125-
new Type(
126-
'array',
127-
false,
128-
null,
129-
true,
130-
new Type('int'),
131-
new Type('object', false, DummyChild::class)
132-
),
133-
],
124+
[new Type('array', false, null, true, new Type('int'), new Type('object', false, DummyChild::class))],
125+
null
126+
));
127+
128+
$denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor);
129+
$arrayDenormalizer = new ArrayDenormalizerDummy();
130+
$serializer = new SerializerCollectionDummy([$arrayDenormalizer, $denormalizer]);
131+
$arrayDenormalizer->setSerializer($serializer);
132+
$denormalizer->setSerializer($serializer);
133+
134+
return $denormalizer;
135+
}
136+
137+
public function testDenormalizeStringCollectionDecodedFromXmlWithOneChild()
138+
{
139+
$denormalizer = $this->getDenormalizerForStringCollection();
140+
141+
// if an xml-node can have children which should be deserialized as string[]
142+
// and only one child exists
143+
$stringCollection = $denormalizer->denormalize(['children' => 'foo'], StringCollection::class, 'xml');
144+
145+
$this->assertInstanceOf(StringCollection::class, $stringCollection);
146+
$this->assertIsArray($stringCollection->children);
147+
$this->assertCount(1, $stringCollection->children);
148+
$this->assertEquals('foo', $stringCollection->children[0]);
149+
}
150+
151+
public function testDenormalizeStringCollectionDecodedFromXmlWithTwoChildren()
152+
{
153+
$denormalizer = $this->getDenormalizerForStringCollection();
154+
155+
// if an xml-node can have children which should be deserialized as string[]
156+
// and only one child exists
157+
$stringCollection = $denormalizer->denormalize(['children' => ['foo', 'bar']], StringCollection::class, 'xml');
158+
159+
$this->assertInstanceOf(StringCollection::class, $stringCollection);
160+
$this->assertIsArray($stringCollection->children);
161+
$this->assertCount(2, $stringCollection->children);
162+
$this->assertEquals('foo', $stringCollection->children[0]);
163+
$this->assertEquals('bar', $stringCollection->children[1]);
164+
}
165+
166+
private function getDenormalizerForStringCollection()
167+
{
168+
$extractor = $this->getMockBuilder(PhpDocExtractor::class)->getMock();
169+
$extractor->method('getTypes')
170+
->will($this->onConsecutiveCalls(
171+
[new Type('array', false, null, true, new Type('int'), new Type('string'))],
134172
null
135173
));
136174

@@ -212,6 +250,12 @@ protected function setAttributeValue($object, $attribute, $value, $format = null
212250
}
213251
}
214252

253+
class StringCollection
254+
{
255+
/** @var string[] */
256+
public $children;
257+
}
258+
215259
class DummyCollection
216260
{
217261
/** @var DummyChild[] */

0 commit comments

Comments
 (0)