8000 bug #47128 [Serializer] Throw InvalidArgumentException if the data ne… · symfony/symfony@cb3684e · GitHub
[go: up one dir, main page]

Skip to content

Commit cb3684e

Browse files
committed
bug #47128 [Serializer] Throw InvalidArgumentException if the data needed in the constructor doesn't belong to a backedEnum (allison guilhem)
This PR was merged into the 5.4 branch. Discussion ---------- [Serializer] Throw InvalidArgumentException if the data needed in the constructor doesn't belong to a backedEnum | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | yes | New feature? | no | Deprecations? |no | Tickets | Fix #46977 [Serializer] Collect deserialization errors on enum cause TypeError | License | MIT | Doc PR | Targeted case: Deserialization with "collect_denormalization_errors" set but the data to be serialized does not correspond to the scalar value of the targeted enum instance in the object's constructor. updated in last commit : Keep "from "(in the previous commits I had switched to "tryFrom") to map the data submitted to an enum instance targeted. Imho, even if the "collect_denormalization_errors" is specified, this type of error seems to have to be caught upstream. By just trying to collect the error we do not prevent the object from being instantiated. But this action is bound to fail because we already know that the data is not valid (checked by the BackedEnumNormalizer). This instantiation 'failure' leads to a confusing/misleading error (i.e. _Argument # 1 ($test) must be of type TestEnum, string given_) which is not the original error. Commits ------- c30f057 [Serializer] Throw InvalidArgumentException if the data needed in the constructor doesn't belong to a backedEnum
2 parents b206928 + c30f057 commit cb3684e

File tree

4 files changed

+81
-3
lines changed

4 files changed

+81
-3
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public function denormalize($data, string $type, string $format = null, array $c
6464
try {
6565
return $type::from($data);
6666
} catch (\ValueError $e) {
67-
throw NotNormalizableValueException::createForUnexpectedDataType($e->getMessage(), $data, [Type::BUILTIN_TYPE_INT, Type::BUILTIN_TYPE_STRING], $context['deserialization_path'] ?? null, true, $e->getCode(), $e);
67+
throw new InvalidArgumentException('The data must belong to a backed enumeration of type '.$type);
6868
}
6969
}
7070

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace Symfony\Component\Serializer\Tests\Fixtures;
4+
5+
use Symfony\Component\Serializer\Tests\Fixtures\StringBackedEnumDummy;
6+
7+
class DummyObjectWithEnumConstructor
8+
{
9+
public function __construct(public StringBackedEnumDummy $get)
10+
{
11+
}
12+
}

src/Symfony/Component/Serializer/Tests/Normalizer/BackedEnumNormalizerTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ public function testDenormalizeObjectThrowsException()
115115
*/
116116
public function testDenormalizeBadBackingValueThrowsException()
117117
{
118-
$this->expectException(NotNormalizableValueException::class);
119-
$this->expectExceptionMessage('"POST" is not a valid backing value for enum "'.StringBackedEnumDummy::class.'"');
118+
$this->expectException(InvalidArgumentException::class);
119+
$this->expectExceptionMessage('The data must belong to a backed enumeration of type '.StringBackedEnumDummy::class);
120+
120121
$this->normalizer->denormalize('POST', StringBackedEnumDummy::class);
121122
}
122123

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
3737
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
3838
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
39+
use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer;
3940
use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
4041
use Symfony\Component\Serializer\Normalizer\DataUriNormalizer;
4142
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
@@ -58,6 +59,7 @@
5859
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface;
5960
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne;
6061
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo;
62+
use Symfony\Component\Serializer\Tests\Fixtures\DummyObjectWithEnumConstructor;
6163
use Symfony\Component\Serializer\Tests\Fixtures\FalseBuiltInDummy;
6264
use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy;
6365
use Symfony\Component\Serializer\Tests\Fixtures\Php74Full;
@@ -1173,6 +1175,69 @@ public function testCollectDenormalizationErrorsWithConstructor(?ClassMetadataFa
11731175
$this->assertSame($expected, $exceptionsAsArray);
11741176
}
11751177

1178+
/**
1179+
* @requires PHP 8.1
1180+
*/
1181+
public function testCollectDenormalizationErrorsWithEnumConstructor()
1182+
{
1183+
$serializer = new Serializer(
1184+
[
1185+
new BackedEnumNormalizer(),
1186+
new ObjectNormalizer(),
1187+
],
1188+
['json' => new JsonEncoder()]
1189+
);
1190+
1191+
try {
1192+
$serializer->deserialize('{"invalid": "GET"}', DummyObjectWithEnumConstructor::class, 'json', [
1193+
DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true,
1194+
]);
1195+
} catch (\Throwable $th) {
1196+
$this->assertInstanceOf(PartialDenormalizationException::class, $th);
1197+
}
1198+
1199+
$exceptionsAsArray = array_map(function (NotNormalizableValueException $e): array {
1200+
return [
1201+
'currentType' => $e->getCurrentType(),
1202+
'useMessageForUser' => $e->canUseMessageForUser(),
1203+
'message' => $e->getMessage(),
1204+
];
1205+
}, $th->getErrors());
1206+
1207+
$expected = [
1208+
[
1209+
'currentType' => 'array',
1210+
'useMessageForUser' => true,
1211+
'message' => 'Failed to create object because the class misses the "get" property.',
1212+
],
1213+
];
1214+
1215+
$this->assertSame($expected, $exceptionsAsArray);
1216+
}
1217+
1218+
/**
1219+
* @requires PHP 8.1
1220+
*/
1221+
public function testNoCollectDenormalizationErrorsWithWrongEnum()
1222+
{
1223+
$serializer = new Serializer(
1224+
[
1225+
new BackedEnumNormalizer(),
1226+
new ObjectNormalizer(),
1227+
],
1228+
['json' => new JsonEncoder()]
1229+
);
1230+
1231+
try {
1232+
$serializer->deserialize('{"get": "invalid"}', DummyObjectWithEnumConstructor::class, 'json', [
1233+
DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true,
1234+
]);
1235+
} catch (\Throwable $th) {
1236+
$this->assertNotInstanceOf(PartialDenormalizationException::class, $th);
1237+
$this->assertInstanceOf(InvalidArgumentException::class, $th);
1238+
}
1239+
}
1240+
11761241
public function provideCollectDenormalizationErrors()
11771242
{
11781243
return [

0 commit comments

Comments
 (0)
0