Skip to content

Commit dc1fab3

Browse files
Merge branch '6.4' into 7.0
* 6.4: [Cache] Fix generating proxies when ext-redis v6 is installed [Serializer] Fix deserializing nested arrays of objects with mixed keys
2 parents 0351be8 + 510e51f commit dc1fab3

File tree

5 files changed

+101
-25
lines changed

5 files changed

+101
-25
lines changed

.appveyor.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ install:
1818
- cd ext
1919
- appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_apcu-5.1.22-8.2-ts-vs16-x86.zip
2020
- 7z x php_apcu-5.1.22-8.2-ts-vs16-x86.zip -y >nul
21-
- appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_redis-5.3.7-8.2-ts-vs16-x86.zip
22-
- 7z x php_redis-5.3.7-8.2-ts-vs16-x86.zip -y >nul
21+
- appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_redis-6.0.0-dev-8.2-ts-vs16-x86.zip
22+
- 7z x php_redis-6.0.0-dev-8.2-ts-vs16-x86.zip -y >nul
2323
- cd ..
2424
- copy /Y php.ini-development php.ini-min
2525
- echo memory_limit=-1 >> php.ini-min

src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
class RedisProxiesTest extends TestCase
2020
{
2121
/**
22-
* @requires extension redis
22+
* @requires extension redis < 6
2323
*
2424
* @testWith ["Redis"]
2525
* ["RedisCluster"]
@@ -85,19 +85,24 @@ public function testRelayProxy()
8585
*/
8686
public function testRedis6Proxy($class, $stub)
8787
{
88-
$this->markTestIncomplete('To be re-enabled when phpredis v6 becomes stable');
89-
90-
$stub = file_get_contents("https://raw.githubusercontent.com/phpredis/phpredis/develop/{$stub}.stub.php");
91-
$stub = preg_replace('/^class /m', 'return; \0', $stub);
92-
$stub = preg_replace('/^return; class ([a-zA-Z]++)/m', 'interface \1StubInterface', $stub, 1);
93-
$stub = preg_replace('/^ public const .*/m', '', $stub);
94-
eval(substr($stub, 5));
88+
if (version_compare(phpversion('redis'), '6.0.0', '<')) {
89+
$this->markTestIncomplete('To be re-enabled when phpredis v6 becomes stable');
90+
91+
$stub = file_get_contents("https://raw.githubusercontent.com/phpredis/phpredis/develop/{$stub}.stub.php");
92+
$stub = preg_replace('/^class /m', 'return; \0', $stub);
93+
$stub = preg_replace('/^return; class ([a-zA-Z]++)/m', 'interface \1StubInterface', $stub, 1);
94+
$stub = preg_replace('/^ public const .*/m', '', $stub);
95+
eval(substr($stub, 5));
96+
$r = new \ReflectionClass($class.'StubInterface');
97+
} else {
98+
$r = new \ReflectionClass($class);
99+
}
95100

96101
$proxy = file_get_contents(\dirname(__DIR__, 2)."/Traits/{$class}6Proxy.php");
97102
$proxy = substr($proxy, 0, 4 + strpos($proxy, '[];'));
98103
$methods = [];
99104

100-
foreach ((new \ReflectionClass($class.'StubInterface'))->getMethods() as $method) {
105+
foreach ($r->getMethods() as $method) {
101106
if ('reset' === $method->name || method_exists(LazyProxyTrait::class, $method->name)) {
102107
continue;
103108
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
477477
$class = $collectionValueType->getClassName().'[]';
478478

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

483483
$context['value_type'] = $collectionValueType;

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,15 @@ public function denormalize(mixed $data, string $type, string $format = null, ar
5454

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

57-
$builtinType = isset($context['key_type']) ? $context['key_type']->getBuiltinType() : null;
57+
$builtinTypes = array_map(static function (Type $keyType) {
58+
return $keyType->getBuiltinType();
59+
}, \is_array($keyType = $context['key_type'] ?? []) ? $keyType : [$keyType]);
60+
5861
foreach ($data as $key => $value) {
5962
$subContext = $context;
6063
$subContext['deserialization_path'] = ($context['deserialization_path'] ?? false) ? sprintf('%s[%s]', $context['deserialization_path'], $key) : "[$key]";
6164

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

6667
$data[$key] = $this->denormalizer->denormalize($value, $type, $format, $subContext);
6768
}
@@ -78,4 +79,19 @@ public function supportsDenormalization(mixed $data, string $type, string $forma
7879
return str_ends_with($type, '[]')
7980
&& $this->denormalizer->supportsDenormalization($data, substr($type, 0, -2), $format, $context);
8081
}
82+
83+
private function validateKeyType(array $builtinTypes, mixed $key, string $path): void
84+
{
85+
if (!$builtinTypes) {
86+
return;
87+
}
88+
89+
foreach ($builtinTypes as $builtinType) {
90+
if (('is_'.$builtinType)($key)) {
91+
return;
92+
}
93+
}
94+
95+
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);
96+
}
8197
}

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

Lines 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;

0 commit comments

Comments
 (0)