Skip to content

Commit

Permalink
Merge branch '6.2' into 6.3
Browse files Browse the repository at this point in the history
* 6.2:
  [Cache] Fix generating proxies when ext-redis v6 is installed
  [Serializer] Fix deserializing nested arrays of objects with mixed keys
  • Loading branch information
nicolas-grekas committed Jul 27, 2023
2 parents 8d6a35f + 1908310 commit 189d236
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 16 deletions.
2 changes: 1 addition & 1 deletion Normalizer/AbstractObjectNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
$class = $collectionValueType->getClassName().'[]';

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

$context['value_type'] = $collectionValueType;
Expand Down
27 changes: 23 additions & 4 deletions Normalizer/ArrayDenormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,15 @@ public function denormalize(mixed $data, string $type, string $format = null, ar

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

$builtinType = isset($context['key_type']) ? $context['key_type']->getBuiltinType() : null;
$builtinTypes = array_map(static function (Type $keyType) {
return $keyType->getBuiltinType();
}, \is_array($keyType = $context['key_type'] ?? []) ? $keyType : [$keyType]);

foreach ($data as $key => $value) {
$subContext = $context;
$subContext['deserialization_path'] = ($context['deserialization_path'] ?? false) ? sprintf('%s[%s]', $context['deserialization_path'], $key) : "[$key]";

if (null !== $builtinType && !('is_'.$builtinType)($key)) {
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);
}
$this->validateKeyType($builtinTypes, $key, $subContext['deserialization_path']);

$data[$key] = $this->denormalizer->denormalize($value, $type, $format, $subContext);
}
Expand All @@ -92,4 +93,22 @@ public function hasCacheableSupportsMethod(): bool

return $this->denormalizer instanceof CacheableSupportsMethodInterface && $this->denormalizer->hasCacheableSupportsMethod();
}

/**
* @param mixed $key
*/
private function validateKeyType(array $builtinTypes, $key, string $path): void
{
if (!$builtinTypes) {
return;
}

foreach ($builtinTypes as $builtinType) {
if (('is_'.$builtinType)($key)) {
return;
}
}

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);
}
}
73 changes: 64 additions & 9 deletions Tests/DeserializeNestedArrayOfObjectsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ public static function provider()
*/
public function testPropertyPhpDoc($class)
{
// GIVEN
$json = <<<EOF
{
"animals": [
Expand All @@ -47,13 +46,62 @@ public function testPropertyPhpDoc($class)
new ObjectNormalizer(null, null, null, new PhpDocExtractor()),
new ArrayDenormalizer(),
], ['json' => new JsonEncoder()]);
// WHEN
/** @var Zoo $zoo */

/** @var Zoo|ZooImmutable $zoo */
$zoo = $serializer->deserialize($json, $class, 'json');
// THEN

self::assertCount(1, $zoo->getAnimals());
self::assertInstanceOf(Animal::class, $zoo->getAnimals()[0]);
}

public function testPropertyPhpDocWithKeyTypes()
{
$json = <<<EOF
{
"animalsInt": [
{"name": "Bug"}
],
"animalsString": {
"animal1": {"name": "Bug"}
},
"animalsUnion": {
"animal2": {"name": "Bug"},
"2": {"name": "Dog"}
},
"animalsGenerics": {
"animal3": {"name": "Bug"},
"3": {"name": "Dog"}
}
}
EOF;
$serializer = new Serializer([
new ObjectNormalizer(null, null, null, new PhpDocExtractor()),
new ArrayDenormalizer(),
], ['json' => new JsonEncoder()]);

/** @var ZooWithKeyTypes $zoo */
$zoo = $serializer->deserialize($json, ZooWithKeyTypes::class, 'json');

self::assertCount(1, $zoo->animalsInt);
self::assertArrayHasKey(0, $zoo->animalsInt);
self::assertInstanceOf(Animal::class, $zoo->animalsInt[0]);

self::assertCount(1, $zoo->animalsString);
self::assertArrayHasKey('animal1', $zoo->animalsString);
self::assertInstanceOf(Animal::class, $zoo->animalsString['animal1']);

self::assertCount(2, $zoo->animalsUnion);
self::assertArrayHasKey('animal2', $zoo->animalsUnion);
self::assertInstanceOf(Animal::class, $zoo->animalsUnion['animal2']);
self::assertArrayHasKey(2, $zoo->animalsUnion);
self::assertInstanceOf(Animal::class, $zoo->animalsUnion[2]);

self::assertCount(2, $zoo->animalsGenerics);
self::assertArrayHasKey('animal3', $zoo->animalsGenerics);
self::assertInstanceOf(Animal::class, $zoo->animalsGenerics['animal3']);
self::assertArrayHasKey(3, $zoo->animalsGenerics);
self::assertInstanceOf(Animal::class, $zoo->animalsGenerics[3]);
}
}

class Zoo
Expand Down Expand Up @@ -100,16 +148,23 @@ public function getAnimals(): array
}
}

class ZooWithKeyTypes
{
/** @var array<int, Animal> */
public $animalsInt = [];
/** @var array<string, Animal> */
public $animalsString = [];
/** @var array<int|string, Animal> */
public $animalsUnion = [];
/** @var \stdClass<Animal> */
public $animalsGenerics = [];
}

class Animal
{
/** @var string */
private $name;

public function __construct()
{
echo '';
}

public function getName(): ?string
{
return $this->name;
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"symfony/http-kernel": "^5.4|^6.0",
"symfony/mime": "^5.4|^6.0",
"symfony/property-access": "^5.4|^6.0",
"symfony/property-info": "^5.4|^6.0",
"symfony/property-info": "^5.4.24|^6.2.11",
"symfony/uid": "^5.4|^6.0",
"symfony/validator": "^5.4|^6.0",
"symfony/var-dumper": "^5.4|^6.0",
Expand All @@ -46,7 +46,7 @@
"phpdocumentor/type-resolver": "<1.4.0",
"symfony/dependency-injection": "<5.4",
"symfony/property-access": "<5.4",
"symfony/property-info": "<5.4",
"symfony/property-info": "<5.4.24|>=6,<6.2.11",
"symfony/uid": "<5.4",
"symfony/yaml": "<5.4"
},
Expand Down

0 comments on commit 189d236

Please sign in to comment.