8000 feature #48821 [Serializer] add a context to allow invalid values in … · symfony/symfony@21c8789 · GitHub
[go: up one dir, main page]

Skip to content

Commit 21c8789

Browse files
feature #48821 [Serializer] add a context to allow invalid values in BackedEnumNormalizer (nikophil)
This PR was merged into the 6.3 branch. Discussion ---------- [Serializer] add a context to allow invalid values in BackedEnumNormalizer | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | License | MIT | Doc PR | todo if PR gets merged sometimes it is needed to allow deserialization of an enum to end up in a `null` value, this PR allows this behavior by passing a context Commits ------- 526e0b2 [Serializer] add a context to allow invalid values in BackedEnumNormalizer
2 parents ad86f72 + 526e0b2 commit 21c8789

File tree

5 files changed

+103
-0
lines changed

5 files changed

+103
-0
lines changed

src/Symfony/Component/Serializer/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
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::ALLOW_INVALID_VALUES` context option
89
* Deprecate `MissingConstructorArgumentsException` in favor of `MissingConstructorArgumentException`
910

1011
6.2
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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\Context\Normalizer;
13+
14+
use Symfony\Component\Serializer\Context\ContextBuilderInterface;
15+
use Symfony\Component\Serializer\Context\ContextBuilderTrait;
16+
use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer;
17+
18+
/**
19+
* A helper providing autocompletion for available BackedEnumNormalizer options.
20+
*
21+
* @author Nicolas PHILIPPE <nikophil@gmail.com>
22+
*/
23+
final class BackedEnumNormalizerContextBuilder implements ContextBuilderInterface
24+
{
25+
use ContextBuilderTrait;
26+
27+
/**
28+
* Configures if invalid values are allowed in denormalization.
29+
* They will be denormalized into `null` values.
30+
*/
31+
public function withAllowInvalidValues(bool $allowInvalidValues): static
32+
{
33+
return $this->with(BackedEnumNormalizer::ALLOW_INVALID_VALUES, $allowInvalidValues);
34+
}
35+
}

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

Lines changed: 17 additions & 0 deletions
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 true, will denormalize any invalid value into null.
27+
*/
28+
public const ALLOW_INVALID_VALUES = 'allow_invalid_values';
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 ($context[self::ALLOW_INVALID_VALUES] ?? false) {
54+
if (null === $data || (!\is_int($data) && !\is_string($data))) {
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
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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\Context\Normalizer;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Serializer\Context\Normalizer\BackedEnumNormalizerContextBuilder;
16+
use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer;
17+
18+
class BackedEnumNormalizerContextBuilderTest extends TestCase
19+
{
20+
private BackedEnumNormalizerContextBuilder $contextBuilder;
21+
22+
protected function setUp(): void
23+
{
24+
$this->contextBuilder = new BackedEnumNormalizerContextBuilder();
25+
}
26+
27+
public function testWithers()
28+
{
29+
$context = $this->contextBuilder->withAllowInvalidValues(true)->toArray();
30+
self::assertSame([BackedEnumNormalizer::ALLOW_INVALID_VALUES => true], $context);
31+
32+
$context = $this->contextBuilder->withAllowInvalidValues(false)->toArray();
33+
self::assertSame([BackedEnumNormalizer::ALLOW_INVALID_VALUES => false], $context);
34+
}
35+
}

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

Lines changed: 15 additions & 0 deletions
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::ALLOW_INVALID_VALUES => true]));
121+
$this->assertNull($this->normalizer->denormalize('', IntegerBackedEnumDummy::class, null, [BackedEnumNormalizer::ALLOW_INVALID_VALUES => true]));
122+
$this->assertNull($this->normalizer->denormalize(null, IntegerBackedEnumDummy::class, null, [BackedEnumNormalizer::ALLOW_INVALID_VALUES => true]));
123+
124+
$this->assertSame(IntegerBackedEnumDummy::SUCCESS, $this->normalizer->denormalize(200, IntegerBackedEnumDummy::class, null, [BackedEnumNormalizer::ALLOW_INVALID_VALUES => true]));
125+
126+
$this->assertNull($this->normalizer->denormalize(1, StringBackedEnumDummy::class, null, [BackedEnumNormalizer::ALLOW_INVALID_VALUES => true]));
127+
$this->assertNull($this->normalizer->denormalize('foo', StringBackedEnumDummy::class, null, [BackedEnumNormalizer::ALLOW_INVALID_VALUES => true]));
128+
$this->assertNull($this->normalizer->denormalize(null, StringBackedEnumDummy::class, null, [BackedEnumNormalizer::ALLOW_INVALID_VALUES => true]));
129+
130+
$this->assertSame(StringBackedEnumDummy::GET, $this->normalizer->denormalize('GET', StringBackedEnumDummy::class, null, [BackedEnumNormalizer::ALLOW_INVALID_VALUES => true]));
131+
}
117132
}

0 commit comments

Comments
 (0)
0