Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 205dd70

Browse files
NorthBlue333nicolas-grekas
authored andcommitted
Add COLLECT_EXTRA_ATTRIBUTES_ERRORS and full deserialization path
1 parent 2566d12 commit 205dd70

19 files changed

Lines changed: 363 additions & 46 deletions

UPGRADE-8.1.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ Serializer
127127
----------
128128

129129
* Deprecate datetime constructor as a fallback, in version 9.0 a `Symfony\Component\Serializer\Exception\NotNormalizableValueException` will be thrown when a date could not be parsed using the default format
130+
* Change the signature of `PartialDenormalizationException::__construct($data, array $errors)` to `__construct(mixed $data, array $notNormalizableErrors, array $extraAttributesErrors = [])`
131+
* Deprecate `PartialDenormalizationException::getErrors()`, use `getNotNormalizableValueErrors()` instead
130132

131133
Uid
132134
---

src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ public function onKernelControllerArguments(ControllerArgumentsEvent $event): vo
133133
$payload = $payloadMapper($request, $argument->metadata, $argument);
134134
} catch (PartialDenormalizationException $e) {
135135
$trans = $this->translator ? $this->translator->trans(...) : static fn ($m, $p) => strtr($m, $p);
136-
foreach ($e->getErrors() as $error) {
136+
$errors = method_exists($e, 'getNotNormalizableValueErrors') ? $e->getNotNormalizableValueErrors() : $e->getErrors();
137+
foreach ($errors as $error) {
137138
$parameters = [];
138139
$template = 'This value was of an unexpected type.';
139140
if ($expectedTypes = $error->getExpectedTypes()) {
@@ -173,7 +174,8 @@ public function onKernelControllerArguments(ControllerArgumentsEvent $event): vo
173174
try {
174175
$payload = $payloadMapper($request, $argument->metadata, $argument);
175176
} catch (PartialDenormalizationException $e) {
176-
throw HttpException::fromStatusCode($validationFailedCode, implode("\n", array_map(static fn ($e) => $e->getMessage(), $e->getErrors())), $e);
177+
$errors = method_exists($e, 'getNotNormalizableValueErrors') ? $e->getNotNormalizableValueErrors() : $e->getErrors();
178+
throw HttpException::fromStatusCode($validationFailedCode, implode("\n", array_map(static fn ($e) => $e->getMessage(), $errors)), $e);
177179
} catch (SerializerInvalidArgumentException $e) {
178180
throw HttpException::fromStatusCode($validationFailedCode, $e->getMessage(), $e);
179181
}

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+
8.1
5+
---
6+
7+
* Add `PropertyPath::append()`
8+
49
7.0
510
---
611

src/Symfony/Component/PropertyAccess/PropertyPath.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,4 +202,33 @@ public function isNullSafe(int $index): bool
202202

203203
return $this->isNullSafe[$index];
204204
}
205+
206+
/**
207+
* Utility method for dealing with property paths.
208+
* For more extensive functionality, use instances of this class.
209+
*
210+
* Appends a path to a given property path.
211+
*
212+
* If the base path is empty, the appended path will be returned unchanged.
213+
* If the base path is not empty, and the appended path starts with a
214+
* squared opening bracket ("["), the concatenation of the two paths is
215+
* returned. Otherwise, the concatenation of the two paths is returned,
216+
* separated by a dot (".").
217+
*/
218+
public static function append(string $basePath, string $subPath): string
219+
{
220+
if ('' === $subPath) {
221+
return $basePath;
222+
}
223+
224+
if ('[' === $subPath[0]) {
225+
return $basePath.$subPath;
226+
}
227+
228+
if ('' === $basePath) {
229+
return $subPath;
230+
}
231+
232+
return $basePath.'.'.$subPath;
233+
}
205234
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,22 @@ public function testIsIndexDoesNotAcceptNegativeIndices()
203203

204204
$propertyPath->isIndex(-1);
205205
}
206+
207+
#[DataProvider('provideAppendPaths')]
208+
public function testAppend(string $basePath, string $subPath, string $expectedPath, string $message)
209+
{
210+
$this->assertSame($expectedPath, PropertyPath::append($basePath, $subPath), $message);
211+
}
212+
213+
public static function provideAppendPaths()
214+
{
215+
return [
216+
['foo', '', 'foo', 'It returns the basePath if subPath is empty'],
217+
['', 'bar', 'bar', 'It returns the subPath if basePath is empty'],
218+
['foo', 'bar', 'foo.bar', 'It append the subPath to the basePath'],
219+
['foo', '[bar]', 'foo[bar]', 'It does not include the dot separator if subPath uses the array notation'],
220+
['0', 'bar', '0.bar', 'Leading zeros are kept.'],
221+
['0', '1', '0.1', 'Leading zeros are kept on subPath too.'],
222+
];
223+
}
206224
}

src/Symfony/Component/Serializer/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ CHANGELOG
77
* Improve `NotNormalizableValueException` exception messages in `BackedEnumNormalizer` to contain more useful information
88
* Trigger a deprecation when a date could not be parsed using the default format
99
* Add `AbstractObjectNormalizer::ENABLE_TYPE_CONVERSION` for scalar type transformation
10+
* Add `COLLECT_EXTRA_ATTRIBUTES_ERRORS` option to `Serializer` to collect extra-attributes errors during denormalization
11+
* Deprecate `PartialDenormalizationException::getErrors()`, use `getNotNormalizableValueErrors()` instead
1012

1113
8.0
1214
---

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,9 @@ public function withCollectDenormalizationErrors(?bool $collectDenormalizationEr
3636
{
3737
return $this->with(DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS, $collectDenormalizationErrors);
3838
}
39+
40+
public function withCollectExtraAttributesErrors(?bool $collectExtraAttributesErrors): static
41+
{
42+
return $this->with(DenormalizerInterface::COLLECT_EXTRA_ATTRIBUTES_ERRORS, $collectExtraAttributesErrors);
43+
}
3944
}

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

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,24 @@
1616
*/
1717
class PartialDenormalizationException extends UnexpectedValueException
1818
{
19+
private ?ExtraAttributesException $extraAttributesError = null;
20+
1921
/**
20-
* @param NotNormalizableValueException[] $errors
22+
* @param NotNormalizableValueException[] $notNormalizableErrors
23+
* @param ExtraAttributesException[] $extraAttributesErrors
2124
*/
2225
public function __construct(
2326
private mixed $data,
24-
private array $errors,
27+
private array $notNormalizableErrors,
28+
array $extraAttributesErrors = [],
2529
) {
30+
$extraAttributes = [];
31+
foreach ($extraAttributesErrors as $error) {
32+
$extraAttributes = array_merge($extraAttributes, $error->getExtraAttributes());
33+
}
34+
if ($extraAttributes) {
35+
$this->extraAttributesError = new ExtraAttributesException($extraAttributes);
36+
}
2637
}
2738

2839
public function getData(): mixed
@@ -31,10 +42,25 @@ public function getData(): mixed
3142
}
3243

3344
/**
34-
* @return NotNormalizableValueException[]
45+
* @deprecated since Symfony 8.1, use getNotNormalizableValueErrors() instead
3546
*/
3647
public function getErrors(): array
3748
{
38-
return $this->errors;
49+
trigger_deprecation('symfony/serializer', '8.1', 'The "%s()" method is deprecated, use "%s::getNotNormalizableValueErrors()" instead.', __METHOD__, self::class);
50+
51+
return $this->getNotNormalizableValueErrors();
52+
}
53+
54+
/**
55+
* @return NotNormalizableValueException[]
56+
*/
57+
public function getNotNormalizableValueErrors(): array
58+
{
59+
return $this->notNormalizableErrors;
60+
}
61+
62+
public function getExtraAttributesError(): ?ExtraAttributesException
63+
{
64+
return $this->extraAttributesError;
3965
}
4066
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\Serializer\Normalizer;
1313

14+
use Symfony\Component\PropertyAccess\PropertyPath;
1415
use Symfony\Component\Serializer\Exception\CircularReferenceException;
1516
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
1617
use Symfony\Component\Serializer\Exception\LogicException;
@@ -593,7 +594,7 @@ protected function getAttributeNormalizationContext(object $object, string $attr
593594
*/
594595
protected function getAttributeDenormalizationContext(string $class, string $attribute, array $context): array
595596
{
596-
$context['deserialization_path'] = ($context['deserialization_path'] ?? false) ? $context['deserialization_path'].'.'.$attribute : $attribute;
597+
$context['deserialization_path'] = PropertyPath::append($context['deserialization_path'] ?? '', $attribute);
597598

598599
if (null === $metadata = $this->getAttributeMetadata($class, $attribute)) {
599600
return $context;

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
1616
use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException;
1717
use Symfony\Component\PropertyAccess\PropertyAccess;
18+
use Symfony\Component\PropertyAccess\PropertyPath;
1819
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
1920
use Symfony\Component\Serializer\Encoder\CsvEncoder;
2021
use Symfony\Component\Serializer\Encoder\JsonEncoder;
@@ -421,7 +422,11 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
421422
}
422423

423424
if ($extraAttributes) {
424-
throw new ExtraAttributesException($extraAttributes);
425+
$extraAttributeException = new ExtraAttributesException(array_map(static fn (string $extraAttribute) => PropertyPath::append($context['deserialization_path'] ?? '', $extraAttribute), $extraAttributes));
426+
if (!isset($context['extra_attributes_exceptions'])) {
427+
throw $extraAttributeException;
428+
}
429+
$context['extra_attributes_exceptions'][] = $extraAttributeException;
425430
}
426431

427432
return $object;

0 commit comments

Comments
 (0)