Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitdac569d

Browse files
committed
Add COLLECT_EXTRA_ATTRIBUTES_ERRORS and full deserialization path
1 parentc884399 commitdac569d

16 files changed

+444
-22
lines changed

‎UPGRADE-6.2.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@ Security
66

77
* Add maximum username length enforcement of 4096 characters in`UserBadge` to
88
prevent[session storage flooding](https://symfony.com/blog/cve-2016-4423-large-username-storage-in-session)
9+
10+
Serializer
11+
--------
12+
913
* Deprecate the`Symfony\Component\Security\Core\Security` class and service, use`Symfony\Bundle\SecurityBundle\Security\Security` instead
1014

1115
Validator
1216
---------
1317

1418
* Deprecate the`loose` e-mail validation mode, use`html5` instead
19+
* Deprecate`PartialDenormalizationException::getErrors()`, call`getNotNormalizableValueErrors()` instead

‎src/Symfony/Component/PropertyAccess/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
6.2
5+
---
6+
7+
* Add`Symfony\Component\PropertyAccess\PropertyPath::append()`
8+
49
6.0
510
---
611

‎src/Symfony/Component/PropertyAccess/PropertyPath.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,29 @@ public function isIndex(int $index): bool
194194

195195
return$this->isIndex[$index];
196196
}
197+
198+
/**
199+
* Utility method for dealing with property paths.
200+
* For more extensive functionality, use instances of this class.
201+
*
202+
* Appends a path to a given property path.
203+
*
204+
* If the base path is empty, the appended path will be returned unchanged.
205+
* If the base path is not empty, and the appended path starts with a
206+
* squared opening bracket ("["), the concatenation of the two paths is
207+
* returned. Otherwise, the concatenation of the two paths is returned,
208+
* separated by a dot (".").
209+
*/
210+
publicstaticfunctionappend(string$basePath,string$subPath):string
211+
{
212+
if ('' !==$subPath) {
213+
if ('[' ===$subPath[0]) {
214+
return$basePath.$subPath;
215+
}
216+
217+
return'' !==$basePath ?$basePath.'.'.$subPath :$subPath;
218+
}
219+
220+
return$basePath;
221+
}
197222
}

‎src/Symfony/Component/PropertyAccess/Tests/PropertyPathTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,24 @@ public function testIsIndexDoesNotAcceptNegativeIndices()
170170

171171
$propertyPath->isIndex(-1);
172172
}
173+
174+
/**
175+
* @dataProvider provideAppendPaths
176+
*/
177+
publicfunctiontestAppend($basePath,$subPath,$expectedPath,$message)
178+
{
179+
$this->assertSame($expectedPath, PropertyPath::append($basePath,$subPath),$message);
180+
}
181+
182+
publicfunctionprovideAppendPaths()
183+
{
184+
return [
185+
['foo','','foo','It returns the basePath if subPath is empty'],
186+
['','bar','bar','It returns the subPath if basePath is empty'],
187+
['foo','bar','foo.bar','It append the subPath to the basePath'],
188+
['foo','[bar]','foo[bar]','It does not include the dot separator if subPath uses the array notation'],
189+
['0','bar','0.bar','Leading zeros are kept.'],
190+
['0',1,'0.1','Numeric subpaths do not cause PHP 7.4 errors.'],
191+
];
192+
}
173193
}

‎src/Symfony/Component/Serializer/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
6.2
5+
---
6+
* Add`COLLECT_EXTRA_ATTRIBUTES_ERRORS` option to`Serializer` to collect errors from nested denormalizations
7+
* Deprecate`PartialDenormalizationException::getErrors()`, call`getNotNormalizableValueErrors()` instead
8+
49
6.1
510
---
611

‎src/Symfony/Component/Serializer/Context/SerializerContextBuilder.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespaceSymfony\Component\Serializer\Context;
1313

14+
useSymfony\Component\Serializer\Normalizer\AbstractNormalizer;
1415
useSymfony\Component\Serializer\Normalizer\DenormalizerInterface;
1516
useSymfony\Component\Serializer\Serializer;
1617

@@ -36,4 +37,9 @@ public function withCollectDenormalizationErrors(?bool $collectDenormalizationEr
3637
{
3738
return$this->with(DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS,$collectDenormalizationErrors);
3839
}
40+
41+
publicfunctionwithCollectExtraAttributesErrors(?bool$collectExtraAttributesErrors):static
42+
{
43+
return$this->with(DenormalizerInterface::COLLECT_EXTRA_ATTRIBUTES_ERRORS,$collectExtraAttributesErrors);
44+
}
3945
}

‎src/Symfony/Component/Serializer/Exception/PartialDenormalizationException.php

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,45 @@
1717
class PartialDenormalizationExceptionextends UnexpectedValueException
1818
{
1919
private$data;
20-
private$errors;
20+
/**
21+
* @var NotNormalizableValueException[]
22+
*/
23+
privatearray$notNormalizableErrors;
24+
private ?ExtraAttributesException$extraAttributesError =null;
2125

22-
publicfunction__construct($data,array$errors)
26+
publicfunction__construct($data,array$notNormalizableErrors,array$extraAttributesErrors = [])
2327
{
2428
$this->data =$data;
25-
$this->errors =$errors;
29+
$this->notNormalizableErrors =$notNormalizableErrors;
30+
$extraAttributes = [];
31+
foreach ($extraAttributesErrorsas$error) {
32+
\array_push($extraAttributes, ...$error->getExtraAttributes());
33+
}
34+
if (\count($extraAttributes) >0) {
35+
$this->extraAttributesError =newExtraAttributesException($extraAttributes);
36+
}
2637
}
2738

2839
publicfunctiongetData()
2940
{
3041
return$this->data;
3142
}
3243

44+
/**
45+
* @deprecated Use getNotNormalizableValueErrors() instead.
46+
*/
3347
publicfunctiongetErrors():array
3448
{
35-
return$this->errors;
49+
return$this->getNotNormalizableValueErrors();
50+
}
51+
52+
publicfunctiongetNotNormalizableValueErrors():array
53+
{
54+
return$this->notNormalizableErrors;
55+
}
56+
57+
publicfunctiongetExtraAttributesError(): ?ExtraAttributesException
58+
{
59+
return$this->extraAttributesError;
3660
}
3761
}

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
useSymfony\Component\Serializer\Mapping\ClassDiscriminatorResolverInterface;
2828
useSymfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
2929
useSymfony\Component\Serializer\NameConverter\NameConverterInterface;
30+
useSymfony\Component\Serializer\Util\PropertyPath;
3031

3132
/**
3233
* Base class for a normalizer dealing with objects.
@@ -242,7 +243,7 @@ private function getAttributeNormalizationContext(object $object, string $attrib
242243
*/
243244
privatefunctiongetAttributeDenormalizationContext(string$class,string$attribute,array$context):array
244245
{
245-
$context['deserialization_path'] = ($context['deserialization_path'] ??false) ?$context['deserialization_path'].'.'.$attribute :$attribute;
246+
$context['deserialization_path'] =PropertyPath::append($context['deserialization_path'] ??'',$attribute);
246247

247248
if (null ===$metadata =$this->getAttributeMetadata($class,$attribute)) {
248249
return$context;
@@ -267,12 +268,12 @@ protected function instantiateObject(array &$data, string $class, array &$contex
267268
{
268269
if ($this->classDiscriminatorResolver &&$mapping =$this->classDiscriminatorResolver->getMappingForClass($class)) {
269270
if (!isset($data[$mapping->getTypeProperty()])) {
270-
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('Type property "%s" not found for the abstract object "%s".',$mapping->getTypeProperty(),$class),null, ['string'],isset($context['deserialization_path']) ?$context['deserialization_path'].'.'.$mapping->getTypeProperty() :$mapping->getTypeProperty(),false);
271+
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('Type property "%s" not found for the abstract object "%s".',$mapping->getTypeProperty(),$class),null, ['string'],PropertyPath::append($context['deserialization_path'] ??'',$mapping->getTypeProperty()),false);
271272
}
272273

273274
$type =$data[$mapping->getTypeProperty()];
274275
if (null === ($mappedClass =$mapping->getClassForType($type))) {
275-
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type "%s" is not a valid value.',$type),$type, ['string'],isset($context['deserialization_path']) ?$context['deserialization_path'].'.'.$mapping->getTypeProperty() :$mapping->getTypeProperty(),true);
276+
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type "%s" is not a valid value.',$type),$type, ['string'],PropertyPath::append($context['deserialization_path'] ??'',$mapping->getTypeProperty()),true);
276277
}
277278

278279
if ($mappedClass !==$class) {
@@ -422,7 +423,11 @@ public function denormalize(mixed $data, string $type, string $format = null, ar
422423
}
423424

424425
if (!empty($extraAttributes)) {
425-
thrownewExtraAttributesException($extraAttributes);
426+
$extraAttributeException =newExtraAttributesException(array_map(fn (string$extraAttribute) => PropertyPath::append($context['deserialization_path'] ??'',$extraAttribute),$extraAttributes));
427+
if (!isset($context['extra_attributes_exceptions'])) {
428+
throw$extraAttributeException;
429+
}
430+
$context['extra_attributes_exceptions'][] =$extraAttributeException;
426431
}
427432

428433
return$object;
@@ -486,14 +491,14 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
486491
}elseif ('true' ===$data ||'1' ===$data) {
487492
$data =true;
488493
}else {
489-
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute for class "%s" must be bool ("%s" given).',$attribute,$currentClass,$data),$data, [Type::BUILTIN_TYPE_BOOL],$context['deserialization_path'] ??null);
494+
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute for class "%s" must be bool ("%s" given).',$attribute,$currentClass,$data),$data, [Type::BUILTIN_TYPE_BOOL],$context['deserialization_path'] ??$attribute);
490495
}
491496
break;
492497
case Type::BUILTIN_TYPE_INT:
493498
if (ctype_digit($data) ||'-' ===$data[0] &&ctype_digit(substr($data,1))) {
494499
$data = (int)$data;
495500
}else {
496-
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute for class "%s" must be int ("%s" given).',$attribute,$currentClass,$data),$data, [Type::BUILTIN_TYPE_INT],$context['deserialization_path'] ??null);
501+
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute for class "%s" must be int ("%s" given).',$attribute,$currentClass,$data),$data, [Type::BUILTIN_TYPE_INT],$context['deserialization_path'] ??$attribute);
497502
}
498503
break;
499504
case Type::BUILTIN_TYPE_FLOAT:
@@ -504,7 +509,7 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
504509
'NaN' => \NAN,
505510
'INF' => \INF,
506511
'-INF' => -\INF,
507-
default =>throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute for class "%s" must be float ("%s" given).',$attribute,$currentClass,$data),$data, [Type::BUILTIN_TYPE_FLOAT],$context['deserialization_path'] ??null),
512+
default =>throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute for class "%s" must be float ("%s" given).',$attribute,$currentClass,$data),$data, [Type::BUILTIN_TYPE_FLOAT],$context['deserialization_path'] ??$attribute),
508513
};
509514
}
510515
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
useSymfony\Component\Serializer\Exception\BadMethodCallException;
1515
useSymfony\Component\Serializer\Exception\InvalidArgumentException;
1616
useSymfony\Component\Serializer\Exception\NotNormalizableValueException;
17+
useSymfony\Component\Serializer\Util\PropertyPath;
1718

1819
/**
1920
* Denormalizes arrays of objects.
@@ -48,7 +49,7 @@ public function denormalize(mixed $data, string $type, string $format = null, ar
4849
$builtinType =isset($context['key_type']) ?$context['key_type']->getBuiltinType() :null;
4950
foreach ($dataas$key =>$value) {
5051
$subContext =$context;
51-
$subContext['deserialization_path'] = ($context['deserialization_path'] ??false) ?sprintf('%s[%s]',$context['deserialization_path'],$key) :"[$key]";
52+
$subContext['deserialization_path'] =PropertyPath::append($context['deserialization_path'] ??'',"[$key]");
5253

5354
if (null !==$builtinType && !('is_'.$builtinType)($key)) {
5455
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);

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,16 @@
2424
*/
2525
interface DenormalizerInterface
2626
{
27+
/**
28+
* Whether to collect all denormalization errors or to stop at first error.
29+
*/
2730
publicconstCOLLECT_DENORMALIZATION_ERRORS ='collect_denormalization_errors';
2831

32+
/**
33+
* Whether to collect all extra attributes errors or to stop at first nested error.
34+
*/
35+
publicconstCOLLECT_EXTRA_ATTRIBUTES_ERRORS ='collect_extra_attributes_errors';
36+
2937
/**
3038
* Denormalizes data back into an object of the given class.
3139
*

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

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -223,19 +223,31 @@ public function denormalize(mixed $data, string $type, string $format = null, ar
223223
thrownewNotNormalizableValueException(sprintf('Could not denormalize object of type "%s", no supporting normalizer found.',$type));
224224
}
225225

226+
$notNormalizableExceptions = [];
226227
if (isset($context[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS])) {
228+
if ($context[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS]) {
229+
$context['not_normalizable_value_exceptions'] = [];
230+
$notNormalizableExceptions = &$context['not_normalizable_value_exceptions'];
231+
}
227232
unset($context[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS]);
228-
$context['not_normalizable_value_exceptions'] = [];
229-
$errors = &$context['not_normalizable_value_exceptions'];
230-
$denormalized =$normalizer->denormalize($data,$type,$format,$context);
231-
if ($errors) {
232-
thrownewPartialDenormalizationException($denormalized,$errors);
233+
}
234+
235+
$extraAttributesExceptions = [];
236+
if (isset($context[DenormalizerInterface::COLLECT_EXTRA_ATTRIBUTES_ERRORS])) {
237+
if ($context[DenormalizerInterface::COLLECT_EXTRA_ATTRIBUTES_ERRORS]) {
238+
$context['extra_attributes_exceptions'] = [];
239+
$extraAttributesExceptions = &$context['extra_attributes_exceptions'];
233240
}
241+
unset($context[DenormalizerInterface::COLLECT_EXTRA_ATTRIBUTES_ERRORS]);
242+
}
243+
244+
$denormalized =$normalizer->denormalize($data,$type,$format,$context);
234245

235-
return$denormalized;
246+
if (\count($notNormalizableExceptions) >0 ||\count($extraAttributesExceptions) >0) {
247+
thrownewPartialDenormalizationException($denormalized,$notNormalizableExceptions ?? [],$extraAttributesExceptions ?? []);
236248
}
237249

238-
return$normalizer->denormalize($data,$type,$format,$context);
250+
return$denormalized;
239251
}
240252

241253
/**

‎src/Symfony/Component/Serializer/Tests/Context/SerializerContextBuilderTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
usePHPUnit\Framework\TestCase;
1515
useSymfony\Component\Serializer\Context\SerializerContextBuilder;
16+
useSymfony\Component\Serializer\Normalizer\AbstractNormalizer;
1617
useSymfony\Component\Serializer\Normalizer\DenormalizerInterface;
1718
useSymfony\Component\Serializer\Serializer;
1819

@@ -38,6 +39,7 @@ public function testWithers(array $values)
3839
$context =$this->contextBuilder
3940
->withEmptyArrayAsObject($values[Serializer::EMPTY_ARRAY_AS_OBJECT])
4041
->withCollectDenormalizationErrors($values[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS])
42+
->withCollectExtraAttributesErrors($values[DenormalizerInterface::COLLECT_EXTRA_ATTRIBUTES_ERRORS])
4143
->toArray();
4244

4345
$this->assertSame($values,$context);
@@ -51,11 +53,13 @@ public function withersDataProvider(): iterable
5153
yield'With values' => [[
5254
Serializer::EMPTY_ARRAY_AS_OBJECT =>true,
5355
DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS =>false,
56+
DenormalizerInterface::COLLECT_EXTRA_ATTRIBUTES_ERRORS =>false,
5457
]];
5558

5659
yield'With null values' => [[
5760
Serializer::EMPTY_ARRAY_AS_OBJECT =>null,
5861
DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS =>null,
62+
DenormalizerInterface::COLLECT_EXTRA_ATTRIBUTES_ERRORS =>null,
5963
]];
6064
}
6165
}

‎src/Symfony/Component/Serializer/Tests/Fixtures/Php74Full.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ final class Php74Full
3131
publicDummyMessageInterface$dummyMessage;
3232
/** @var TestFoo[] $nestedArray */
3333
publicTestFoo$nestedObject;
34+
publicTestFoo$nestedObject2;
3435
}
3536

3637

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp