Skip to content

Commit d8e613f

Browse files
committed
[Serializer] add a context to allow invalid values in BackedEnumNormalizer
1 parent f43cd26 commit d8e613f

File tree

3 files changed

+33
-0
lines changed

3 files changed

+33
-0
lines changed

src/Symfony/Component/Serializer/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Add `XmlEncoder::SAVE_OPTIONS` context option
8+
* Add `BackedEnumNormalizer::NULL_IF_NOT_PART_OF_ENUMERATION` context option
89

910
6.2
1011
---

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

+17
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
*/
2323
final class BackedEnumNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface
2424
{
25+
/**
26+
* If provided, will return null for any invalid value.
27+
*/
28+
public const NULL_IF_NOT_PART_OF_ENUMERATION = 'null_if_not_part_of_enumeration';
29+
2530
public function normalize(mixed $object, string $format = null, array $context = []): int|string
2631
{
2732
if (!$object instanceof \BackedEnum) {
@@ -45,6 +50,18 @@ public function denormalize(mixed $data, string $type, string $format = null, ar
4550
throw new InvalidArgumentException('The data must belong to a backed enumeration.');
4651
}
4752

53+
if (isset($context[self::NULL_IF_NOT_PART_OF_ENUMERATION])) {
54+
if (null === $data) { // "tryFrom()" does not accept null
55+
return null;
56+
}
57+
58+
try {
59+
return $type::tryFrom($data);
60+
} catch (\TypeError) {
61+
return null;
62+
}
63+
}
64+
4865
if (!\is_int($data) && !\is_string($data)) {
4966
throw NotNormalizableValueException::createForUnexpectedDataType('The data is neither an integer nor a string, you should pass an integer or a string that can be parsed as an enumeration case of type '.$type.'.', $data, [Type::BUILTIN_TYPE_INT, Type::BUILTIN_TYPE_STRING], $context['deserialization_path'] ?? null, true);
5067
}

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

+15
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,19 @@ public function testSupportsNormalizationShouldFailOnAnyPHPVersionForNonEnumObje
114114
{
115115
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
116116
}
117+
118+
public function testItUsesTryFromIfContextIsPassed()
119+
{
120+
$this->assertNull($this->normalizer->denormalize(1, IntegerBackedEnumDummy::class, null, [BackedEnumNormalizer::NULL_IF_NOT_PART_OF_ENUMERATION => true]));
121+
$this->assertNull($this->normalizer->denormalize('foo', IntegerBackedEnumDummy::class, null, [BackedEnumNormalizer::NULL_IF_NOT_PART_OF_ENUMERATION => true]));
122+
$this->assertNull($this->normalizer->denormalize(null, IntegerBackedEnumDummy::class, null, [BackedEnumNormalizer::NULL_IF_NOT_PART_OF_ENUMERATION => true]));
123+
124+
$this->assertSame(IntegerBackedEnumDummy::SUCCESS, $this->normalizer->denormalize(200, IntegerBackedEnumDummy::class, null, [BackedEnumNormalizer::NULL_IF_NOT_PART_OF_ENUMERATION => true]));
125+
126+
$this->assertNull($this->normalizer->denormalize(1, StringBackedEnumDummy::class, null, [BackedEnumNormalizer::NULL_IF_NOT_PART_OF_ENUMERATION => true]));
127+
$this->assertNull($this->normalizer->denormalize('foo', StringBackedEnumDummy::class, null, [BackedEnumNormalizer::NULL_IF_NOT_PART_OF_ENUMERATION => true]));
128+
$this->assertNull($this->normalizer->denormalize(null, StringBackedEnumDummy::class, null, [BackedEnumNormalizer::NULL_IF_NOT_PART_OF_ENUMERATION => true]));
129+
130+
$this->assertSame(StringBackedEnumDummy::GET, $this->normalizer->denormalize('GET', StringBackedEnumDummy::class, null, [BackedEnumNormalizer::NULL_IF_NOT_PART_OF_ENUMERATION => true]));
131+
}
117132
}

0 commit comments

Comments
 (0)