From 2946d58efc51d92ef8b786d2603577dd82e7dea2 Mon Sep 17 00:00:00 2001 From: Julien Falque Date: Sat, 12 Sep 2020 16:30:30 +0200 Subject: [PATCH 1/4] [Serializer] Add ability to collect denormalization errors --- src/Symfony/Component/Serializer/CHANGELOG.md | 1 + .../Exception/InvariantViolationException.php | 76 +++++++++++++ .../Serializer/InvariantViolation.php | 52 +++++++++ .../Normalizer/AbstractObjectNormalizer.php | 19 +++- .../Normalizer/ArrayDenormalizer.php | 17 ++- .../Normalizer/DataUriNormalizer.php | 17 +++ .../Normalizer/DateIntervalNormalizer.php | 17 +++ .../Normalizer/DateTimeNormalizer.php | 17 +++ .../Normalizer/DenormalizerInterface.php | 2 + .../Normalizer/MimeMessageNormalizer.php | 14 ++- .../Serializer/Normalizer/UidNormalizer.php | 8 ++ .../Normalizer/UnwrappingDenormalizer.php | 9 +- .../Serializer/Tests/SerializerTest.php | 106 ++++++++++++++++++ 13 files changed, 346 insertions(+), 9 deletions(-) create mode 100644 src/Symfony/Component/Serializer/Exception/InvariantViolationException.php create mode 100644 src/Symfony/Component/Serializer/InvariantViolation.php diff --git a/src/Symfony/Component/Serializer/CHANGELOG.md b/src/Symfony/Component/Serializer/CHANGELOG.md index 0fc8fd2c6898c..68bc4d3b71857 100644 --- a/src/Symfony/Component/Serializer/CHANGELOG.md +++ b/src/Symfony/Component/Serializer/CHANGELOG.md @@ -8,6 +8,7 @@ CHANGELOG * added `UidNormalizer` * added `FormErrorNormalizer` * added `MimeMessageNormalizer` + * added `DenormalizerInterface::COLLECT_INVARIANT_VIOLATIONS` context option to collect denormalization errors instead of throwing immediately 5.1.0 ----- diff --git a/src/Symfony/Component/Serializer/Exception/InvariantViolationException.php b/src/Symfony/Component/Serializer/Exception/InvariantViolationException.php new file mode 100644 index 0000000000000..a08a96a623be2 --- /dev/null +++ b/src/Symfony/Component/Serializer/Exception/InvariantViolationException.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Exception; + +use Symfony\Component\Serializer\InvariantViolation; + +final class InvariantViolationException extends \RuntimeException implements ExceptionInterface +{ + /** + * @var array> + */ + private $violations; + + /** + * @param array> $violations + */ + public function __construct(array $violations) + { + parent::__construct('Denormalization failed because some values were invalid.'); + + $this->violations = $violations; + } + + /** + * @return array> + */ + public function getViolations(): array + { + return $this->violations; + } + + /** + * @return array> + */ + public function getViolationsNestedIn(string $parentPath): array + { + if ('' === $parentPath) { + throw new \InvalidArgumentException('Parent path cannot be empty.'); + } + + $nestedViolations = []; + + foreach ($this->violations as $path => $violations) { + $path = '' !== $path ? "{$parentPath}.{$path}" : $parentPath; + + $nestedViolations[$path] = $violations; + } + + return $nestedViolations; + } + + /** + * @return array> + */ + public function getViolationMessages(): array + { + $messages = []; + + foreach ($this->violations as $path => $violations) { + foreach ($violations as $violation) { + $messages[$path][] = $violation->getMessage(); + } + } + + return $messages; + } +} diff --git a/src/Symfony/Component/Serializer/InvariantViolation.php b/src/Symfony/Component/Serializer/InvariantViolation.php new file mode 100644 index 0000000000000..d6d6d9e6cf39d --- /dev/null +++ b/src/Symfony/Component/Serializer/InvariantViolation.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer; + +class InvariantViolation +{ + /** + * @var mixed + */ + private $normalizedValue; + + /** + * @var string + */ + private $message; + + /** + * @var \Throwable|null + */ + private $exception; + + public function __construct($normalizedValue, string $message, ?\Throwable $exception = null) + { + $this->normalizedValue = $normalizedValue; + $this->message = $message; + $this->exception = $exception; + } + + public function getNormalizedValue() + { + return $this->normalizedValue; + } + + public function getMessage(): string + { + return $this->message; + } + + public function getException(): ?\Throwable + { + return $this->exception; + } +} diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index aa1be48cfbaf5..0a51637b7e528 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -19,6 +19,7 @@ use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Encoder\XmlEncoder; use Symfony\Component\Serializer\Exception\ExtraAttributesException; +use Symfony\Component\Serializer\Exception\InvariantViolationException; use Symfony\Component\Serializer\Exception\LogicException; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; use Symfony\Component\Serializer\Exception\RuntimeException; @@ -311,6 +312,8 @@ public function denormalize($data, string $type, string $format = null, array $c $object = $this->instantiateObject($normalizedData, $type, $context, $reflectionClass, $allowedAttributes, $format); $resolvedClass = $this->objectClassResolver ? ($this->objectClassResolver)($object) : \get_class($object); + $invariantViolations = []; + foreach ($normalizedData as $attribute => $value) { if ($this->nameConverter) { $attribute = $this->nameConverter->denormalize($attribute, $resolvedClass, $format, $context); @@ -331,14 +334,22 @@ public function denormalize($data, string $type, string $format = null, array $c } } - $value = $this->validateAndDenormalize($resolvedClass, $attribute, $value, $format, $context); try { - $this->setAttributeValue($object, $attribute, $value, $format, $context); - } catch (InvalidArgumentException $e) { - throw new NotNormalizableValueException(sprintf('Failed to denormalize attribute "%s" value for class "%s": '.$e->getMessage(), $attribute, $type), $e->getCode(), $e); + $denormalizedValue = $this->validateAndDenormalize($resolvedClass, $attribute, $value, $format, $context); + try { + $this->setAttributeValue($object, $attribute, $denormalizedValue, $format, $context); + } catch (InvalidArgumentException $e) { + throw new NotNormalizableValueException(sprintf('Failed to denormalize attribute "%s" value for class "%s": '.$e->getMessage(), $attribute, $type), $e->getCode(), $e); + } + } catch (InvariantViolationException $exception) { + $invariantViolations += $exception->getViolationsNestedIn($attribute); } } + if ([] !== $invariantViolations) { + throw new InvariantViolationException($invariantViolations); + } + if (!empty($extraAttributes)) { throw new ExtraAttributesException($extraAttributes); } diff --git a/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php index 33892277389e5..0ef844f13b648 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ArrayDenormalizer.php @@ -13,6 +13,7 @@ use Symfony\Component\Serializer\Exception\BadMethodCallException; use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Symfony\Component\Serializer\Exception\InvariantViolationException; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; use Symfony\Component\Serializer\SerializerAwareInterface; use Symfony\Component\Serializer\SerializerInterface; @@ -51,13 +52,23 @@ public function denormalize($data, string $type, string $format = null, array $c $serializer = $this->serializer; $type = substr($type, 0, -2); + $invariantViolations = []; + $builtinType = isset($context['key_type']) ? $context['key_type']->getBuiltinType() : null; foreach ($data as $key => $value) { - if (null !== $builtinType && !('is_'.$builtinType)($key)) { - throw new NotNormalizableValueException(sprintf('The type of the key "%s" must be "%s" ("%s" given).', $key, $builtinType, get_debug_type($key))); + try { + if (null !== $builtinType && !('is_'.$builtinType)($key)) { + throw new NotNormalizableValueException($key, $value, sprintf('The type of the key "%s" must be "%s" ("%s" given).', $key, $builtinType, get_debug_type($key))); + } + + $data[$key] = $serializer->denormalize($value, $type, $format, $context); + } catch (InvariantViolationException $exception) { + $invariantViolations += $exception->getViolationsNestedIn($key); } + } - $data[$key] = $serializer->denormalize($value, $type, $format, $context); + if ([] !== $invariantViolations) { + throw new InvariantViolationException($invariantViolations); } return $data; diff --git a/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php index 979288cf6ace3..aa3ade182d4ac 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php @@ -15,7 +15,9 @@ use Symfony\Component\Mime\MimeTypeGuesserInterface; use Symfony\Component\Mime\MimeTypes; use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Symfony\Component\Serializer\Exception\InvariantViolationException; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; +use Symfony\Component\Serializer\InvariantViolation; /** * Normalizes an {@see \SplFileInfo} object to a data URI. @@ -90,6 +92,21 @@ public function supportsNormalization($data, string $format = null) * @throws NotNormalizableValueException */ public function denormalize($data, string $type, string $format = null, array $context = []) + { + try { + return $this->doDenormalize($data, $type); + } catch (NotNormalizableValueException $exception) { + if ($context[self::COLLECT_INVARIANT_VIOLATIONS] ?? false) { + $violation = new InvariantViolation($data, 'This value is not a valid data URI.', $exception); + + throw new InvariantViolationException(['' => [$violation]]); + } + + throw $exception; + } + } + + private function doDenormalize($data, string $type) { if (!preg_match('/^data:([a-z0-9][a-z0-9\!\#\$\&\-\^\_\+\.]{0,126}\/[a-z0-9][a-z0-9\!\#\$\&\-\^\_\+\.]{0,126}(;[a-z0-9\-]+\=[a-z0-9\-]+)?)?(;base64)?,[a-z0-9\!\$\&\\\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i', $data)) { throw new NotNormalizableValueException('The provided "data:" URI is not valid.'); diff --git a/src/Symfony/Component/Serializer/Normalizer/DateIntervalNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DateIntervalNormalizer.php index de028b34341f9..e38596fcf52b0 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DateIntervalNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DateIntervalNormalizer.php @@ -12,7 +12,9 @@ namespace Symfony\Component\Serializer\Normalizer; use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Symfony\Component\Serializer\Exception\InvariantViolationException; use Symfony\Component\Serializer\Exception\UnexpectedValueException; +use Symfony\Component\Serializer\InvariantViolation; /** * Normalizes an instance of {@see \DateInterval} to an interval string. @@ -70,6 +72,21 @@ public function hasCacheableSupportsMethod(): bool * @throws UnexpectedValueException */ public function denormalize($data, string $type, string $format = null, array $context = []) + { + try { + return $this->doDenormalize($data, $context); + } catch (\Throwable $exception) { + if ($context[self::COLLECT_INVARIANT_VIOLATIONS] ?? false) { + $violation = new InvariantViolation($data, 'This value is not a valid date interval.', $exception); + + throw new InvariantViolationException(['' => [$violation]]); + } + + throw $exception; + } + } + + private function doDenormalize($data, array $context = []) { if (!\is_string($data)) { throw new InvalidArgumentException(sprintf('Data expected to be a string, "%s" given.', get_debug_type($data))); diff --git a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php index c12e23470a445..342658c5fb971 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php @@ -12,7 +12,9 @@ namespace Symfony\Component\Serializer\Normalizer; use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Symfony\Component\Serializer\Exception\InvariantViolationException; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; +use Symfony\Component\Serializer\InvariantViolation; /** * Normalizes an object implementing the {@see \DateTimeInterface} to a date string. @@ -77,6 +79,21 @@ public function supportsNormalization($data, string $format = null) * @throws NotNormalizableValueException */ public function denormalize($data, string $type, string $format = null, array $context = []) + { + try { + return $this->doDenormalize($data, $type, $context); + } catch (NotNormalizableValueException $exception) { + if ($context[self::COLLECT_INVARIANT_VIOLATIONS] ?? false) { + $violation = new InvariantViolation($data, 'This value is not a valid date.', $exception); + + throw new InvariantViolationException(['' => [$violation]]); + } + + throw $exception; + } + } + + private function doDenormalize($data, string $type, array $context = []) { $dateTimeFormat = $context[self::FORMAT_KEY] ?? null; $timezone = $this->getTimezone($context); diff --git a/src/Symfony/Component/Serializer/Normalizer/DenormalizerInterface.php b/src/Symfony/Component/Serializer/Normalizer/DenormalizerInterface.php index 73ca7ce3865d4..d71e9a6213c29 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DenormalizerInterface.php +++ b/src/Symfony/Component/Serializer/Normalizer/DenormalizerInterface.php @@ -26,6 +26,8 @@ */ interface DenormalizerInterface { + const COLLECT_INVARIANT_VIOLATIONS = 'collect_invariant_violations'; + /** * Denormalizes data back into an object of the given class. * diff --git a/src/Symfony/Component/Serializer/Normalizer/MimeMessageNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/MimeMessageNormalizer.php index a1c4f169bbf5e..97a6652af424c 100644 --- a/src/Symfony/Component/Serializer/Normalizer/MimeMessageNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/MimeMessageNormalizer.php @@ -17,6 +17,8 @@ use Symfony\Component\Mime\Header\UnstructuredHeader; use Symfony\Component\Mime\Message; use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Serializer\Exception\InvariantViolationException; +use Symfony\Component\Serializer\InvariantViolation; use Symfony\Component\Serializer\SerializerAwareInterface; use Symfony\Component\Serializer\SerializerInterface; @@ -55,9 +57,19 @@ public function setSerializer(SerializerInterface $serializer) public function normalize($object, ?string $format = null, array $context = []) { if ($object instanceof Headers) { + $invariantViolations = []; + $ret = []; foreach ($this->headersProperty->getValue($object) as $name => $header) { - $ret[$name] = $this->serializer->normalize($header, $format, $context); + try { + $ret[$name] = $this->serializer->normalize($header, $format, $context); + } catch (InvariantViolationException $exception) { + $invariantViolations[''][] = new InvariantViolation($header, "Header {$name} is invalid.", $exception); + } + } + + if ([] !== $invariantViolations) { + throw new InvariantViolationException($invariantViolations); } return $ret; diff --git a/src/Symfony/Component/Serializer/Normalizer/UidNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/UidNormalizer.php index 22b563adc5804..80c5b005744cc 100644 --- a/src/Symfony/Component/Serializer/Normalizer/UidNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/UidNormalizer.php @@ -11,7 +11,9 @@ namespace Symfony\Component\Serializer\Normalizer; +use Symfony\Component\Serializer\Exception\InvariantViolationException; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; +use Symfony\Component\Serializer\InvariantViolation; use Symfony\Component\Uid\AbstractUid; use Symfony\Component\Uid\Ulid; use Symfony\Component\Uid\Uuid; @@ -42,6 +44,12 @@ public function denormalize($data, string $type, string $format = null, array $c try { return Ulid::class === $type ? Ulid::fromString($data) : Uuid::fromString($data); } catch (\InvalidArgumentException $exception) { + if ($context[self::COLLECT_INVARIANT_VIOLATIONS] ?? false) { + $violation = new InvariantViolation($data, sprintf('This value is not a valid %s URI.', substr(strrchr($type, '\\'), 1)), $exception); + + throw new InvariantViolationException(['' => [$violation]]); + } + throw new NotNormalizableValueException(sprintf('The data is not a valid "%s" string representation.', $type)); } } diff --git a/src/Symfony/Component/Serializer/Normalizer/UnwrappingDenormalizer.php b/src/Symfony/Component/Serializer/Normalizer/UnwrappingDenormalizer.php index a56546c6775b7..02cc954f42d32 100644 --- a/src/Symfony/Component/Serializer/Normalizer/UnwrappingDenormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/UnwrappingDenormalizer.php @@ -13,6 +13,7 @@ use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; +use Symfony\Component\Serializer\Exception\InvariantViolationException; use Symfony\Component\Serializer\SerializerAwareInterface; use Symfony\Component\Serializer\SerializerAwareTrait; @@ -48,7 +49,13 @@ public function denormalize($data, $class, string $format = null, array $context $data = $this->propertyAccessor->getValue($data, $propertyPath); } - return $this->serializer->denormalize($data, $class, $format, $context); + try { + return $this->serializer->denormalize($data, $class, $format, $context); + } catch (InvariantViolationException $exception) { + $propertyPath = str_replace('][', '.', substr($propertyPath, 1, -1)); + + throw new InvariantViolationException($exception->getViolationsNestedIn($propertyPath)); + } } /** diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index 80c430a7d4323..538e604f4b64f 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -18,6 +18,7 @@ use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Symfony\Component\Serializer\Exception\InvariantViolationException; use Symfony\Component\Serializer\Exception\LogicException; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata; @@ -30,6 +31,7 @@ use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\CustomNormalizer; +use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer; @@ -633,6 +635,92 @@ public function testDeserializeAndUnwrap() $serializer->deserialize($jsonData, __NAMESPACE__.'\Model', 'json', [UnwrappingDenormalizer::UNWRAP_PATH => '[baz][inner]']) ); } + + public function testCollectDenormalizationErrors() + { + $serializer = new Serializer( + [ + new DateTimeNormalizer(), + new ObjectNormalizer(null, null, null, new PhpDocExtractor()), + new ArrayDenormalizer(), + ], + [ + 'json' => new JsonEncoder(), + ] + ); + + $json = json_encode([ + 'foo' => 'foo', + 'bar' => 'bar', + 'baz' => [ + 'foo' => 'foo', + 'bar' => 'bar', + ], + ]); + + $exception = null; + + try { + $serializer->deserialize($json, Dto::class, 'json', [ + Serializer::COLLECT_INVARIANT_VIOLATIONS => true, + ]); + } catch (InvariantViolationException $exception) { + } + + self::assertNotNull($exception); + self::assertSame([ + 'foo' => ['This value is not a valid date.'], + 'bar' => ['This value is not a valid date.'], + 'baz.foo' => ['This value is not a valid date.'], + 'baz.bar' => ['This value is not a valid date.'], + ], $exception->getViolationMessages()); + } + + public function testCollectDenormalizationErrorsWithUnwrapping() + { + $serializer = new Serializer( + [ + new UnwrappingDenormalizer(new PropertyAccessor()), + new DateTimeNormalizer(), + new ObjectNormalizer(null, null, null, new PhpDocExtractor()), + new ArrayDenormalizer(), + ], + [ + 'json' => new JsonEncoder(), + ] + ); + + $json = json_encode([ + 'wrapped' => [ + 'data' => [ + 'foo' => 'foo', + 'bar' => 'bar', + 'baz' => [ + 'foo' => 'foo', + 'bar' => 'bar', + ], + ], + ], + ]); + + $exception = null; + + try { + $serializer->deserialize($json, Dto::class, 'json', [ + Serializer::COLLECT_INVARIANT_VIOLATIONS => true, + UnwrappingDenormalizer::UNWRAP_PATH => '[wrapped][data]', + ]); + } catch (InvariantViolationException $exception) { + } + + self::assertNotNull($exception); + self::assertSame([ + 'wrapped.data.foo' => ['This value is not a valid date.'], + 'wrapped.data.bar' => ['This value is not a valid date.'], + 'wrapped.data.baz.foo' => ['This value is not a valid date.'], + 'wrapped.data.baz.bar' => ['This value is not a valid date.'], + ], $exception->getViolationMessages()); + } } class Model @@ -706,3 +794,21 @@ interface NormalizerAwareNormalizer extends NormalizerInterface, NormalizerAware interface DenormalizerAwareDenormalizer extends DenormalizerInterface, DenormalizerAwareInterface { } + +class Dto +{ + /** + * @var \DateTimeImmutable + */ + public $foo; + + /** + * @var \DateTimeImmutable + */ + public $bar; + + /** + * @var Dto + */ + public $baz; +} From efb8dff2978bf8eeadd9ff2a85b746a48d5d1691 Mon Sep 17 00:00:00 2001 From: Julien Falque Date: Wed, 30 Sep 2020 16:19:26 +0200 Subject: [PATCH 2/4] Remove redundant PHPDocs --- .../Exception/InvariantViolationException.php | 3 --- .../Component/Serializer/InvariantViolation.php | 11 ----------- 2 files changed, 14 deletions(-) diff --git a/src/Symfony/Component/Serializer/Exception/InvariantViolationException.php b/src/Symfony/Component/Serializer/Exception/InvariantViolationException.php index a08a96a623be2..c08d4a2043475 100644 --- a/src/Symfony/Component/Serializer/Exception/InvariantViolationException.php +++ b/src/Symfony/Component/Serializer/Exception/InvariantViolationException.php @@ -15,9 +15,6 @@ final class InvariantViolationException extends \RuntimeException implements ExceptionInterface { - /** - * @var array> - */ private $violations; /** diff --git a/src/Symfony/Component/Serializer/InvariantViolation.php b/src/Symfony/Component/Serializer/InvariantViolation.php index d6d6d9e6cf39d..cdd2e556503c7 100644 --- a/src/Symfony/Component/Serializer/InvariantViolation.php +++ b/src/Symfony/Component/Serializer/InvariantViolation.php @@ -13,19 +13,8 @@ class InvariantViolation { - /** - * @var mixed - */ private $normalizedValue; - - /** - * @var string - */ private $message; - - /** - * @var \Throwable|null - */ private $exception; public function __construct($normalizedValue, string $message, ?\Throwable $exception = null) From 6488a62dfb78fbab1b81ed0aa830d94cd6371c37 Mon Sep 17 00:00:00 2001 From: Julien Falque Date: Wed, 30 Sep 2020 16:21:45 +0200 Subject: [PATCH 3/4] Make invariant violation exception mandatory --- src/Symfony/Component/Serializer/InvariantViolation.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Serializer/InvariantViolation.php b/src/Symfony/Component/Serializer/InvariantViolation.php index cdd2e556503c7..a7e8ccdd6de49 100644 --- a/src/Symfony/Component/Serializer/InvariantViolation.php +++ b/src/Symfony/Component/Serializer/InvariantViolation.php @@ -17,7 +17,7 @@ class InvariantViolation private $message; private $exception; - public function __construct($normalizedValue, string $message, ?\Throwable $exception = null) + public function __construct($normalizedValue, string $message, \Throwable $exception) { $this->normalizedValue = $normalizedValue; $this->message = $message; @@ -34,7 +34,7 @@ public function getMessage(): string return $this->message; } - public function getException(): ?\Throwable + public function getException(): \Throwable { return $this->exception; } From a974fc6fe56bd55c30de3c574fe83cf5c78771fa Mon Sep 17 00:00:00 2001 From: Julien Falque Date: Wed, 30 Sep 2020 16:34:00 +0200 Subject: [PATCH 4/4] Failing to write property is not an invariant violation --- .../Normalizer/AbstractObjectNormalizer.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 0a51637b7e528..518c69e4ff953 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -335,15 +335,16 @@ public function denormalize($data, string $type, string $format = null, array $c } try { - $denormalizedValue = $this->validateAndDenormalize($resolvedClass, $attribute, $value, $format, $context); - try { - $this->setAttributeValue($object, $attribute, $denormalizedValue, $format, $context); - } catch (InvalidArgumentException $e) { - throw new NotNormalizableValueException(sprintf('Failed to denormalize attribute "%s" value for class "%s": '.$e->getMessage(), $attribute, $type), $e->getCode(), $e); - } + $value = $this->validateAndDenormalize($resolvedClass, $attribute, $value, $format, $context); } catch (InvariantViolationException $exception) { $invariantViolations += $exception->getViolationsNestedIn($attribute); } + + try { + $this->setAttributeValue($object, $attribute, $value, $format, $context); + } catch (InvalidArgumentException $e) { + throw new NotNormalizableValueException(sprintf('Failed to denormalize attribute "%s" value for class "%s": '.$e->getMessage(), $attribute, $type), $e->getCode(), $e); + } } if ([] !== $invariantViolations) { 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