8000 Merge branch '5.4' into 6.2 · symfony/symfony@70abfa5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 70abfa5

Browse files
Merge branch '5.4' into 6.2
* 5.4: [Serializer] Throw NotNormalizableValueException if it doesn't concern a backedEnum in construct method Do not expose `Sfjs` as it is unused and conflicts with WebProfilerBundle’s [PropertyInfo] Fix phpDocExtractor nullable array value type
2 parents 7aa43b8 + f1122a2 commit 70abfa5

File tree

12 files changed

+334
-281
lines changed

12 files changed

+334
-281
lines changed

src/Symfony/Component/ErrorHandler/Resources/assets/js/exception.js

Lines changed: 241 additions & 253 deletions
Large diffs are not rendered by default.

src/Symfony/Component/HttpKernel/HttpCache/Esi.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public function process(Request $request, Response $response): Response
7272
$content = preg_replace('#<esi\:comment[^>]+>#s', '', $content);
7373

7474
static $cookie;
75-
$cookie = hash('md5', $cookie ?? $cookie = random_bytes(16), true);
75+
$cookie = hash('xxh128', $cookie ??= random_bytes(16), true);
7676
$boundary = base64_encode($cookie);
7777
$chunks = preg_split('#<esi\:include\s+(.*?)\s*(?:/|</esi\:include)>#', $content, -1, \PREG_SPLIT_DELIM_CAPTURE);
7878

src/Symfony/Component/HttpKernel/HttpCache/Ssi.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public function process(Request $request, Response $response): Response
5454
$content = $response->getContent();
5555

5656
static $cookie;
57-
$cookie = hash('md5', $cookie ?? $cookie = random_bytes(16), true);
57+
$cookie = hash('xxh128', $cookie ??= random_bytes(16), true);
5858
$boundary = base64_encode($cookie);
5959
$chunks = preg_split('#<!--\#include\s+(.*?)\s*-->#', $content, -1, \PREG_SPLIT_DELIM_CAPTURE);
6060

src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public function testExtractCollection($property, array $type = null, $shortDescr
142142
public static function provideCollectionTypes()
143143
{
144144
return [
145-
['iteratorCollection', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, null, new Type(Type::BUILTIN_TYPE_STRING))], null, null],
145+
['iteratorCollection', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)], new Type(Type::BUILTIN_TYPE_STRING))], null, null],
146146
['iteratorCollectionWithKey', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Iterator', true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))], null, null],
147147
[
148148
'nestedIterators',
@@ -238,6 +238,8 @@ public static function typesWithCustomPrefixesProvider()
238238
['i', [new Type(Type::BUILTIN_TYPE_STRING, true), new Type(Type::BUILTIN_TYPE_INT, true)], null, null],
239239
['j', [new Type(Type::BUILTIN_TYPE_OBJECT, true, 'DateTimeImmutable')], null, null],
240240
['nullableCollectionOfNonNullableElements', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_INT, false))], null, null],
241+
['nonNullableCollectionOfNullableElements', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_INT, true))], null, null],
242+
['nullableCollectionOfMultipleNonNullableElementTypes', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true, new Type(Type::BUILTIN_TYPE_INT), [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)])], null, null],
241243
['donotexist', null, null, null],
242244
['staticGetter', null, null, null],
243245
['staticSetter', null, null, null],

src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ public function testGetProperties()
5959
'i',
6060
'j',
6161
'nullableCollectionOfNonNullableElements',
62+
'nonNullableCollectionOfNullableElements',
63+
'nullableCollectionOfMultipleNonNullableElementTypes',
6264
'emptyVar',
6365
'iteratorCollection',
6466
'iteratorCollectionWithKey',
@@ -121,6 +123,8 @@ public function testGetPropertiesWithCustomPrefixes()
121123
'i',
122124
'j',
123125
'nullableCollectionOfNonNullableElements',
126+
'nonNullableCollectionOfNullableElements',
127+
'nullableCollectionOfMultipleNonNullableElementTypes',
124128
'emptyVar',
125129
'iteratorCollection',
126130
'iteratorCollectionWithKey',
@@ -172,6 +176,8 @@ public function testGetPropertiesWithNoPrefixes()
172176
'i',
173177
'j',
174178
'nullableCollectionOfNonNullableElements',
179+
'nonNullableCollectionOfNullableElements',
180+
'nullableCollectionOfMultipleNonNullableElementTypes',
175181
'emptyVar',
176182
'iteratorCollection',
177183
'iteratorCollectionWithKey',

src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ class Dummy extends ParentDummy
9898
*/
9999
public $nullableCollectionOfNonNullableElements;
100100

101+
/**
102+
* @var array<null|int>
103+
*/
104+
public $nonNullableCollectionOfNullableElements;
105+
106+
/**
107+
* @var null|array<int|string>
108+
*/
109+
public $nullableCollectionOfMultipleNonNullableElementTypes;
110+
101111
/**
102112
* @var array
103113
*/

src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -118,43 +118,31 @@ private function createType(DocType $type, bool $nullable, string $docType = nul
118118

119119
[$phpType, $class] = $this->getPhpTypeAndClass((string) $fqsen);
120120

121-
$key = $this->getTypes($type->getKeyType());
122-
$value = $this->getTypes($type->getValueType());
121+
$keys = $this->getTypes($type->getKeyType());
122+
$values = $this->getTypes($type->getValueType());
123123

124-
// More than 1 type returned means it is a Compound type, which is
125-
// not handled by Type, so better use a null value.
126-
$key = 1 === \count($key) ? $key[0] : null;
127-
$value = 1 === \count($value) ? $value[0] : null;
128-
129-
return new Type($phpType, $nullable, $class, true, $key, $value);
124+
return new Type($phpType, $nullable, $class, true, $keys, $values);
130125
}
131126

132127
// Cannot guess
133128
if (!$docType || 'mixed' === $docType) {
134129
return null;
135130
}
136131

137-
if (str_ends_with($docType, '[]')) {
138-
$collectionKeyType = new Type(Type::BUILTIN_TYPE_INT);
139-
$collectionValueType = $this->createType($type, false, substr($docType, 0, -2));
132+
if (str_ends_with($docType, '[]') && $type instanceof Array_) {
133+
$collectionKeyTypes = new Type(Type::BUILTIN_TYPE_INT);
134+
$collectionValueTypes = $this->getTypes($type->getValueType());
140135

141-
return new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, $collectionKeyType, $collectionValueType);
136+
return new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, $collectionKeyTypes, $collectionValueTypes);
142137
}
143138

144139
if ((str_starts_with($docType, 'list<') || str_starts_with($docType, 'array<')) && $type instanceof Array_) {
145140
// array<value> is converted to x[] which is handled above
146141
// so it's only necessary to handle array<key, value> here
147-
$collectionKeyType = $this->getTypes($type->getKeyType())[0];
148-
142+
$collectionKeyTypes = $this->getTypes($type->getKeyType());
149143
$collectionValueTypes = $this->getTypes($type->getValueType());
150-
if (1 != \count($collectionValueTypes)) {
151-
// the Type class does not support union types yet, so assume that no type was defined
152-
$collectionValueType = null;
153-
} else {
154-
$collectionValueType = $collectionValueTypes[0];
155-
}
156144

157-
return new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, $collectionKeyType, $collectionValueType);
145+
return new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, $collectionKeyTypes, $collectionValueTypes);
158146
}
159147

160148
if ($type instanceof PseudoType) {

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ protected function instantiateObject(array &$data, string $class, array &$contex
322322

323323
$constructor = $this->getConstructor($data, $class, $context, $reflectionClass, $allowedAttributes);
324324
if ($constructor) {
325+
$context['has_constructor'] = true;
325326
if (true !== $constructor->isPublic()) {
326327
return $reflectionClass->newInstanceWithoutConstructor();
327328
}
@@ -412,6 +413,8 @@ protected function instantiateObject(array &$data, string $class, array &$contex
412413
}
413414
}
414415

416+
unset($context['has_constructor']);
417+
415418
return new $class();
416419
}
417420

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ public function denormalize(mixed $data, string $type, string $format = null, ar
5252
try {
5353
return $type::from($data);
5454
} catch (\ValueError $e) {
55-
throw new InvalidArgumentException('The data must belong to a backed enumeration of type '.$type);
55+
if (isset($context['has_constructor'])) {
56+
throw new InvalidArgumentException('The data must belong to a backed enumeration of type '.$type);
57+
}
58+
59+
throw NotNormalizableValueException::createForUnexpectedDataType('The data must belong to a backed enumeration of type '.$type, $data, [$type], $context['deserialization_path'] ?? null, true, 0, $e);
5660
}
5761
}
5862

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Symfony\Component\Serializer\Tests\Fixtures;
4+
5+
use Symfony\Component\Serializer\Tests\Fixtures\StringBackedEnumDummy;
6+
7+
class DummyObjectWithEnumProperty
8+
{
9+
public StringBackedEnumDummy $get;
10+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public function testDenormalizeObjectThrowsException()
8888

8989
public function testDenormalizeBadBackingValueThrowsException()
9090
{
91-
$this->expectException(InvalidArgumentException::class);
91+
$this->expectException(NotNormalizableValueException::class);
9292
$this->expectExceptionMessage('The data must belong to a backed enumeration of type '.StringBackedEnumDummy::class);
9393

9494
$this->normalizer->denormalize('POST', StringBackedEnumDummy::class);

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

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne;
6161
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo;
6262
use Symfony\Component\Serializer\Tests\Fixtures\DummyObjectWithEnumConstructor;
63+
use Symfony\Component\Serializer\Tests\Fixtures\DummyObjectWithEnumProperty;
6364
use Symfony\Component\Serializer\Tests\Fixtures\FalseBuiltInDummy;
6465
use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy;
6566
use Symfony\Component\Serializer\Tests\Fixtures\Php74Full;
@@ -1232,7 +1233,48 @@ public function testCollectDenormalizationErrorsWithEnumConstructor()
12321233
$this->assertSame($expected, $exceptionsAsArray);
12331234
}
12341235

1235-
public function testNoCollectDenormalizationErrorsWithWrongEnum()
1236+
public function testCollectDenormalizationErrorsWithWrongPropertyWithoutConstruct()
1237+
{
1238+
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader());
1239+
$reflectionExtractor = new ReflectionExtractor();
1240+
$propertyInfoExtractor = new PropertyInfoExtractor([], [$reflectionExtractor], [], [], []);
1241+
1242+
$serializer = new Serializer(
1243+
[
1244+
new BackedEnumNormalizer(),
1245+
new ObjectNormalizer($classMetadataFactory, null, null, $propertyInfoExtractor),
1246+
],
1247+
['json' => new JsonEncoder()]
1248+
);
1249+
1250+
try {
1251+
$serializer->deserialize('{"get": "POST"}', DummyObjectWithEnumProperty::class, 'json', [
1252+
DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true,
1253+
]);
1254+
} catch (\Throwable $e) {
1255+
$this->assertInstanceOf(PartialDenormalizationException::class, $e);
1256+
}
1257+
1258+
$exceptionsAsArray = array_map(function (NotNormalizableValueException $e): array {
1259+
return [
1260+
'currentType' => $e->getCurrentType(),
1261+
'useMessageForUser' => $e->canUseMessageForUser(),
1262+
'message' => $e->getMessage(),
1263+
];
1264+
}, $e->getErrors());
1265+
1266+
$expected = [
1267+
[
1268+
'currentType' => 'string',
1269+
'useMessageForUser' => true,
1270+
'message' => 'The data must belong to a backed enumeration of type Symfony\Component\Serializer\Tests\Fixtures\StringBackedEnumDummy',
1271+
],
1272+
];
1273+
1274+
$this->assertSame($expected, $exceptionsAsArray);
1275+
}
1276+
1277+
public function testNoCollectDenormalizationErrorsWithWrongEnumOnConstructor()
12361278
{
12371279
$serializer = new Serializer(
12381280
[
@@ -1243,7 +1285,7 @@ public function testNoCollectDenormalizationErrorsWithWrongEnum()
12431285
);
12441286

12451287
try {
1246-
$serializer->deserialize('{"get": "invalid"}', DummyObjectWithEnumConstructor::class, 'json', [
1288+
$serializer->deserialize('{"get": "POST"}', DummyObjectWithEnumConstructor::class, 'json', [
12471289
DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true,
12481290
]);
12491291
} catch (\Throwable $th) {

0 commit comments

Comments
 (0)
0