Skip to content

Navigation Menu

Sign in
Appearance settings
Sign up
Appearance settings

Commit 49ab4ab

Browse filesBrowse the repository at this point in the historyBrowse files
Merge branch '5.4' into 6.2
* 5.4: [Serializer] Fix deserializing nested arrays of objects with mixed keys
2 parents 5dfc9f3 + 8492f10 commit 49ab4ab
Copy full SHA for 49ab4ab

4 files changed

+90-16Lines changed: 90 additions & 16 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
486486
$class = $collectionValueType->getClassName().'[]';
487487

488488
if (\count($collectionKeyType = $type->getCollectionKeyTypes()) > 0) {
489-
[$context['key_type']] = $collectionKeyType;
489+
$context['key_type'] = \count($collectionKeyType) > 1 ? $collectionKeyType : $collectionKeyType[0];
490490
}
491491

492492
$context['value_type'] = $collectionValueType;
Collapse file

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php
+23-4Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,15 @@ public function denormalize(mixed $data, string $type, string $format = null, ar
4444

4545
$type = substr($type, 0, -2);
4646

47-
$builtinType = isset($context['key_type']) ? $context['key_type']->getBuiltinType() : null;
47+
$builtinTypes = array_map(static function (Type $keyType) {
48+
return $keyType->getBuiltinType();
49+
}, \is_array($keyType = $context['key_type'] ?? []) ? $keyType : [$keyType]);
50+
4851
foreach ($data as $key => $value) {
4952
$subContext = $context;
5053
$subContext['deserialization_path'] = ($context['deserialization_path'] ?? false) ? sprintf('%s[%s]', $context['deserialization_path'], $key) : "[$key]";
5154

52-
if (null !== $builtinType && !('is_'.$builtinType)($key)) {
53-
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the key "%s" must be "%s" ("%s" given).', $key, $builtinType, get_debug_type($key)), $key, [$builtinType], $subContext['deserialization_path'] ?? null, true);
54-
}
55+
$this->validateKeyType($builtinTypes, $key, $subContext['deserialization_path']);
5556

5657
$data[$key] = $this->denormalizer->denormalize($value, $type, $format, $subContext);
5758
}
@@ -73,4 +74,22 @@ public function hasCacheableSupportsMethod(): bool
7374
{
7475
return $this->denormalizer instanceof CacheableSupportsMethodInterface && $this->denormalizer->hasCacheableSupportsMethod();
7576
}
77+
78+
/**
79+
* @param mixed $key
80+
*/
81+
private function validateKeyType(array $builtinTypes, $key, string $path): void
82+
{
83+
if (!$builtinTypes) {
84+
return;
85+
}
86+
87+
foreach ($builtinTypes as $builtinType) {
88+
if (('is_'.$builtinType)($key)) {
89+
return;
90+
}
91+
}
92+
93+
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the key "%s" must be "%s" ("%s" given).', $key, implode('", "', $builtinTypes), get_debug_type($key)), $key, $builtinTypes, $path, true);
94+
}
7695
}
Collapse file

‎src/Symfony/Component/Serializer/Tests/DeserializeNestedArrayOfObjectsTest.php‎

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/Tests/DeserializeNestedArrayOfObjectsTest.php
+64-9Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ public static function provider()
3535
*/
3636
public function testPropertyPhpDoc($class)
3737
{
38-
// GIVEN
3938
$json = <<<EOF
4039
{
4140
"animals": [
@@ -47,13 +46,62 @@ public function testPropertyPhpDoc($class)
4746
new ObjectNormalizer(null, null, null, new PhpDocExtractor()),
4847
new ArrayDenormalizer(),
4948
], ['json' => new JsonEncoder()]);
50-
// WHEN
51-
/** @var Zoo $zoo */
49+
50+
/** @var Zoo|ZooImmutable $zoo */
5251
$zoo = $serializer->deserialize($json, $class, 'json');
53-
// THEN
52+
5453
self::assertCount(1, $zoo->getAnimals());
5554
self::assertInstanceOf(Animal::class, $zoo->getAnimals()[0]);
5655
}
56+
57+
public function testPropertyPhpDocWithKeyTypes()
58+
{
59+
$json = <<<EOF
60+
{
61+
"animalsInt": [
62+
{"name": "Bug"}
63+
],
64+
"animalsString": {
65+
"animal1": {"name": "Bug"}
66+
},
67+
"animalsUnion": {
68+
"animal2": {"name": "Bug"},
69+
"2": {"name": "Dog"}
70+
},
71+
"animalsGenerics": {
72+
"animal3": {"name": "Bug"},
73+
"3": {"name": "Dog"}
74+
}
75+
}
76+
EOF;
77+
$serializer = new Serializer([
78+
new ObjectNormalizer(null, null, null, new PhpDocExtractor()),
79+
new ArrayDenormalizer(),
80+
], ['json' => new JsonEncoder()]);
81+
82+
/** @var ZooWithKeyTypes $zoo */
83+
$zoo = $serializer->deserialize($json, ZooWithKeyTypes::class, 'json');
84+
85+
self::assertCount(1, $zoo->animalsInt);
86+
self::assertArrayHasKey(0, $zoo->animalsInt);
87+
self::assertInstanceOf(Animal::class, $zoo->animalsInt[0]);
88+
89+
self::assertCount(1, $zoo->animalsString);
90+
self::assertArrayHasKey('animal1', $zoo->animalsString);
91+
self::assertInstanceOf(Animal::class, $zoo->animalsString['animal1']);
92+
93+
self::assertCount(2, $zoo->animalsUnion);
94+
self::assertArrayHasKey('animal2', $zoo->animalsUnion);
95+
self::assertInstanceOf(Animal::class, $zoo->animalsUnion['animal2']);
96+
self::assertArrayHasKey(2, $zoo->animalsUnion);
97+
self::assertInstanceOf(Animal::class, $zoo->animalsUnion[2]);
98+
99+
self::assertCount(2, $zoo->animalsGenerics);
100+
self::assertArrayHasKey('animal3', $zoo->animalsGenerics);
101+
self::assertInstanceOf(Animal::class, $zoo->animalsGenerics['animal3']);
102+
self::assertArrayHasKey(3, $zoo->animalsGenerics);
103+
self::assertInstanceOf(Animal::class, $zoo->animalsGenerics[3]);
104+
}
57105
}
58106

59107
class Zoo
@@ -100,16 +148,23 @@ public function getAnimals(): array
100148
}
101149
}
102150

151+
class ZooWithKeyTypes
152+
{
153+
/** @var array<int, Animal> */
154+
public $animalsInt = [];
155+
/** @var array<string, Animal> */
156+
public $animalsString = [];
157+
/** @var array<int|string, Animal> */
158+
public $animalsUnion = [];
159+
/** @var \stdClass<Animal> */
160+
public $animalsGenerics = [];
161+
}
162+
103163
class Animal
104164
{
105165
/** @var string */
106166
private $name;
107167

108-
public function __construct()
109-
{
110-
echo '';
111-
}
112-
113168
public function getName(): ?string
114169
{
115170
return $this->name;
Collapse file

‎src/Symfony/Component/Serializer/composer.json‎

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/composer.json
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"symfony/http-kernel": "^5.4|^6.0",
3333
"symfony/mime": "^5.4|^6.0",
3434
"symfony/property-access": "^5.4|^6.0",
35-
"symfony/property-info": "^5.4|^6.0",
35+
"symfony/property-info": "^5.4.24|^6.2.11",
3636
"symfony/uid": "^5.4|^6.0",
3737
"symfony/validator": "^5.4|^6.0",
3838
"symfony/var-dumper": "^5.4|^6.0",
@@ -45,7 +45,7 @@
4545
"phpdocumentor/type-resolver": "<1.4.0",
4646
"symfony/dependency-injection": "<5.4",
4747
"symfony/property-access": "<5.4",
48-
"symfony/property-info": "<5.4",
48+
"symfony/property-info": "<5.4.24|>=6,<6.2.11",
4949
"symfony/uid": "<5.4",
5050
"symfony/yaml": "<5.4"
5151
},

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.