8000 [Serializer] add a context to allow invalid values in BackedEnumNorma… · symfony/symfony@89b9d3c · GitHub
[go: up one dir, main page]

Skip to content

Commit 89b9d3c

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

File tree

5 files changed

+105
-0
lines changed

5 files changed

+105
-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::ALLOW_INVALID_VALUES` context option
89

910
6.2
1011
---
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 withAllowInvalidValue(bool $allowInvalidValues): static
32+
{
33+
return $this->with(BackedEnumNormalizer::ALLOW_INVALID_VALUES, $allowInvalidValues);
34+
}
35+
}

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 true, will return null for any invalid value.
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 (true === ($context[self::ALLOW_INVALID_VALUES] ?? false)) {
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
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Symfony package.
7+
*
8+
* (c) Fabien Potencier <fabien@symfony.com>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Symfony\Component\Serializer\Tests\Context\Normalizer;
15+
16+
use PHPUnit\Framework\TestCase;
17+
use Symfony\Component\Serializer\Context\Normalizer\BackedEnumNormalizerContextBuilder;
18+
use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer;
19+
20+
class BackedEnumNormalizerContextBuilderTest extends TestCase
21+
{
22+
private BackedEnumNormalizerContextBuilder $contextBuilder;
23+
24+
protected function setUp(): void
25+
{
26+
$this->contextBuilder = new BackedEnumNormalizerContextBuilder();
27+
}
28+
29+
public function testWithers()
30+
{
31+
$context = $this->contextBuilder->withAllowInvalidValue(true)->toArray();
32+
self::assertSame([BackedEnumNormalizer::ALLOW_INVALID_VALUES => true], $context);
33+
34+
$context = $this->contextBuilder->withAllowInvalidValue(false)->toArray();
35+
self::assertSame([BackedEnumNormalizer::ALLOW_INVALID_VALUES => false], $context);
36+
}
37+
}

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::ALLOW_INVALID_VALUES => true]));
121+
$this->assertNull($this->normalizer->denormalize('foo', 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