8000 [Serializer] Fix collecting type errors during denormalization with p… · symfony/symfony@9d9570f · GitHub
[go: up one dir, main page]

Skip to content

Commit 9d9570f

Browse files
Th3Moukfabpot
authored andcommitted
[Serializer] Fix collecting type errors during denormalization with promoted properties
1 parent f32af46 commit 9d9570f

File tree

4 files changed

+83
-2
lines changed

4 files changed

+83
-2
lines changed

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,16 @@ protected function instantiateObject(array &$data, string $class, array &$contex
389389
}
390390

391391
// Don't run set for a parameter passed to the constructor
392-
$params[] = $this->denormalizeParameter($reflectionClass, $constructorParameter, $paramName, $parameterData, $context, $format);
392+
try {
393+
$params[] = $this->denormalizeParameter($reflectionClass, $constructorParameter, $paramName, $parameterData, $context, $format);
394+
} catch (NotNormalizableValueException $exception) {
395+
if (!isset($context['not_normalizable_value_exceptions'])) {
396+
throw $exception;
397+
}
398+
399+
$context['not_normalizable_value_exceptions'][] = $exception;
400+
$params[] = $parameterData;
401+
}
393402
unset($data[$key]);
394403
} elseif (\array_key_exists($key, $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? [])) {
395404
$params[] = $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key];

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
571571
return $data;
572572
}
573573

574-
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute for class "%s" must be one of "%s" ("%s" given).', $attribute, $currentClass, implode('", "', array_keys($expectedTypes)), get_debug_type($data)), $data, array_keys($expectedTypes), $context['deserialization_path'] ?? null);
574+
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute for class "%s" must be one of "%s" ("%s" given).', $attribute, $currentClass, implode('", "', array_keys($expectedTypes)), get_debug_type($data)), $data, array_keys($expectedTypes), $context['deserialization_path'] ?? $attribute);
575575
}
576576

577577
/**
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Serializer\Tests\Fixtures;
13+
14+
final class Php80WithPromotedTypedConstructor
15+
{
16+
public function __construct(public bool $bool)
17+
{
18+
}
19+
}

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo;
5959
use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy;
6060
use Symfony\Component\Serializer\Tests\Fixtures\Php74Full;
61+
use Symfony\Component\Serializer\Tests\Fixtures\Php80WithPromotedTypedConstructor;
6162
use Symfony\Component\Serializer\Tests\Fixtures\TraversableDummy;
6263
use Symfony\Component\Serializer\Tests\Normalizer\TestDenormalizer;
6364
use Symfony\Component\Serializer\Tests\Normalizer\TestNormalizer;
@@ -997,6 +998,58 @@ public function testCollectDenormalizationErrors2()
997998

998999
$this->assertSame($expected, $exceptionsAsArray);
9991000
}
1001+
1002+
/** @requires PHP 8.0 */
1003+
public function testCollectDenormalizationErrorsWithConstructor()
1004+
{
1005+
$json = '{"bool": "bool"}';
1006+
1007+
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
1008+
$extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]);
1009+
1010+
$serializer = new Serializer(
1011+
[
1012+
new ObjectNormalizer($classMetadataFactory, null, null, $extractor, new ClassDiscriminatorFromClassMetadata($classMetadataFactory)),
1013+
],
1014+
['json' => new JsonEncoder()]
1015+
);
1016+
1017+
try {
1018+
$serializer->deserialize($json, Php80WithPromotedTypedConstructor::class, 'json', [
1019+
DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true,
1020+
]);
1021+
1022+
$this->fail();
1023+
} catch (\Throwable $th) {
1024+
$this->assertInstanceOf(PartialDenormalizationException::class, $th);
1025+
}
1026+
1027+
$this->assertInstanceOf(Php80WithPromotedTypedConstructor::class, $th->getData());
1028+
1029+
$exceptionsAsArray = array_map(function (NotNormalizableValueException $e): array {
1030+
return [
1031+
'currentType' => $e->getCurrentType(),
1032+
'expectedTypes' => $e->getExpectedTypes(),
1033+
'path' => $e->getPath(),
1034+
'useMessageForUser' => $e->canUseMessageForUser(),
1035+
'message' => $e->getMessage(),
1036+
];
1037+
}, $th->getErrors());
1038+
1039+
$expected = [
1040+
[
1041+
'currentType' => 'string',
1042+
'expectedTypes' => [
1043+
'bool',
1044+
],
1045+
'path' => 'bool',
1046+
'useMessageForUser' => false,
1047+
'message' => 'The type of the "bool" attribute for class "Symfony\\Component\\Serializer\\Tests\\Fixtures\\Php80WithPromotedTypedConstructor" must be one of "bool" ("string" given).',
1048+
],
1049+
];
1050+
1051+
$this->assertSame($expected, $exceptionsAsArray);
1052+
}
10001053
}
10011054

10021055
class Model

0 commit comments

Comments
 (0)
0