Skip to content

Commit 510e51f

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

File tree

5 files changed

+104
-25
lines changed

5 files changed

+104
-25
lines changed

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"]
@@ -86,19 +86,24 @@ public function testRelayProxy()
8686
*/
8787
public function testRedis6Proxy($class, $stub)
8888
{
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));
89+
if (version_compare(phpversion('redis'), '6.0.0', '<')) {
90+
$this->markTestIncomplete('To be re-enabled when phpredis v6 becomes stable');
91+
92+
$stub = file_get_contents("https://raw.githubusercontent.com/phpredis/phpredis/develop/{$stub}.stub.php");
93+
$stub = preg_replace('/^class /m', 'return; \0', $stub);
94+
$stub = preg_replace('/^return; class ([a-zA-Z]++)/m', 'interface \1StubInterface', $stub, 1);
95+
$stub = preg_replace('/^ public const .*/m', '', $stub);
96+
eval(substr($stub, 5));
97+
$r = new \ReflectionClass($class.'StubInterface');
98+
} else {
99+
$r = new \ReflectionClass($class);
100+
}
96101

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

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

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

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

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

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

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

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

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

61-
$builtinType = isset($context['key_type']) ? $context['key_type']->getBuiltinType() : null;
61+
$builtinTypes = array_map(static function (Type $keyType) {
62+
return $keyType->getBuiltinType();
63+
}, \is_array($keyType = $context['key_type'] ?? []) ? $keyType : [$keyType]);
64+
6265
foreach ($data as $key => $value) {
6366
$subContext = $context;
6467
$subContext['deserialization_path'] = ($context['deserialization_path'] ?? false) ? sprintf('%s[%s]', $context['deserialization_path'], $key) : "[$key]";
6568

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

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

9394
return $this->denormalizer instanceof CacheableSupportsMethodInterface && $this->denormalizer->hasCacheableSupportsMethod();
9495
}
96+
97+
/**
98+
* @param mixed $key
99+
*/
100+
private function validateKeyType(array $builtinTypes, $key, string $path): void
101+
{
102+
if (!$builtinTypes) {
103+
return;
104+
}
105+
106+
foreach ($builtinTypes as $builtinType) {
107+
if (('is_'.$builtinType)($key)) {
108+
return;
109+
}
110+
}
111+
112+
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);
113+
}
95114
}

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;

src/Symfony/Component/Serializer/composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"symfony/http-kernel": "^5.4|^6.0|^7.0",
3434
"symfony/mime": "^5.4|^6.0|^7.0",
3535
"symfony/property-access": "^5.4|^6.0|^7.0",
36-
"symfony/property-info": "^5.4|^6.0|^7.0",
36+
"symfony/property-info": "^5.4.24|^6.2.11|^7.0",
3737
"symfony/uid": "^5.4|^6.0|^7.0",
3838
"symfony/validator": "^5.4|^6.0|^7.0",
3939
"symfony/var-dumper": "^5.4|^6.0|^7.0",
@@ -46,7 +46,7 @@
4646
"phpdocumentor/type-resolver": "<1.4.0",
4747
"symfony/dependency-injection": "<5.4",
4848
"symfony/property-access": "<5.4",
49-
"symfony/property-info": "<5.4",
49+
"symfony/property-info": "<5.4.24|>=6,<6.2.11",
5050
"symfony/uid": "<5.4",
5151
"symfony/yaml": "<5.4"
5252
},

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy