diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 16cf59e8bb2f..e15c89e827a2 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -640,8 +640,11 @@ private function validateAndDenormalizeLegacy(array $types, string $currentClass private function validateAndDenormalize(Type $type, string $currentClass, string $attribute, mixed $data, ?string $format, array $context): mixed { $expectedTypes = []; + $isUnionType = $type->asNonNullable() instanceof UnionType; + $e = null; $extraAttributesException = null; $missingConstructorArgumentsException = null; + $isNullable = false; $types = match (true) { $type instanceof IntersectionType => throw new LogicException('Unable to handle intersection type.'), @@ -679,12 +682,19 @@ private function validateAndDenormalize(Type $type, string $currentClass, string // That's why we have to transform the values, if one of these non-string basic datatypes is expected. $typeIdentifier = $t->getTypeIdentifier(); if (\is_string($data) && (XmlEncoder::FORMAT === $format || CsvEncoder::FORMAT === $format)) { + if ('' === $data) { + if (TypeIdentifier::ARRAY === $typeIdentifier) { + return []; + } + + if (TypeIdentifier::STRING === $typeIdentifier) { + return ''; + } + + $isNullable = $isNullable ?: $type->isNullable(); + } + switch ($typeIdentifier) { - case TypeIdentifier::ARRAY: - if ('' === $data) { - return []; - } - break; case TypeIdentifier::BOOL: // according to https://www.w3.org/TR/xmlschema-2/#boolean, valid representations are "false", "true", "0" and "1" if ('false' === $data || '0' === $data) { @@ -808,17 +818,17 @@ private function validateAndDenormalize(Type $type, string $currentClass, string return $data; } } catch (NotNormalizableValueException|InvalidArgumentException $e) { - if (!$type instanceof UnionType) { + if (!$isUnionType && !$isNullable) { throw $e; } } catch (ExtraAttributesException $e) { - if (!$type instanceof UnionType) { + if (!$isUnionType && !$isNullable) { throw $e; } $extraAttributesException ??= $e; } catch (MissingConstructorArgumentsException $e) { - if (!$type instanceof UnionType) { + if (!$isUnionType && !$isNullable) { throw $e; } @@ -838,6 +848,10 @@ private function validateAndDenormalize(Type $type, string $currentClass, string throw $missingConstructorArgumentsException; } + if (!$isUnionType && $e) { + throw $e; + } + if ($context[self::DISABLE_TYPE_ENFORCEMENT] ?? $this->defaultContext[self::DISABLE_TYPE_ENFORCEMENT] ?? false) { return $data; } diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/NotNormalizableDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/NotNormalizableDummy.php index 41da0eac8a99..ef7a8c906dc5 100644 --- a/src/Symfony/Component/Serializer/Tests/Fixtures/NotNormalizableDummy.php +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/NotNormalizableDummy.php @@ -26,6 +26,6 @@ public function __construct() public function denormalize(DenormalizerInterface $denormalizer, $data, ?string $format = null, array $context = []): void { - throw new NotNormalizableValueException(); + throw new NotNormalizableValueException('Custom exception message'); } } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php index c5c1f6f0ba01..6f6256506d47 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -946,6 +946,7 @@ public function testDenormalizeUntypedFormat() public function testDenormalizeUntypedFormatNotNormalizable() { $this->expectException(NotNormalizableValueException::class); + $this->expectExceptionMessage('Custom exception message'); $serializer = new Serializer([new CustomNormalizer(), new ObjectNormalizer(null, null, null, new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]))]); $serializer->denormalize(['value' => 'test'], DummyWithNotNormalizable::class, 'xml'); }
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: