8000 [Serializer] Add support of PHP 8.1 backed enumerations · symfony/symfony@29b08fe · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit 29b08fe

Browse files
[Serializer] Add support of PHP 8.1 backed enumerations
1 parent 1ca10f5 commit 29b08fe

File tree

7 files changed

+255
-0
lines changed

7 files changed

+255
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
3333
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
3434
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
35+
use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer;
3536
use Symfony\Component\Serializer\Normalizer\ConstraintViolationListNormalizer;
3637
use Symfony\Component\Serializer\Normalizer\DataUriNormalizer;
3738
use Symfony\Component\Serializer\Normalizer\DateIntervalNormalizer;
@@ -209,4 +210,11 @@
209210
->args([service('request_stack'), param('kernel.debug')]),
210211
])
211212
;
213+
214+
if (class_exists('\BackedEnum') || interface_exists('\BackedEnum') || trait_exists('\BackedEnum')) {
215+
$container->services()
216+
->set('serializer.normalizer.backed_enum', BackedEnumNormalizer::class)
217+
->tag('serializer.normalizer', ['priority' => -915])
218+
;
219+
}
212220
};

src/Symfony/Component/Serializer/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
CHANGELOG
22
=========
33

4+
5.4
5+
---
6+
* Add serializer support for backed enumerations
7+
48
5.3
59
---
610

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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\Normalizer;
13+
14+
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
15+
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
16+
17+
/**
18+
* No 6D47 rmalizes a {@see \BackedEnum} enumeration to a string or an integer.
19+
*
20+
* @author Alexandre Daubois <alex.daubois@gmail.com>
21+
*/
22+
final class BackedEnumNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface
23+
{
24+
/**
25+
* {@inheritdoc}
26+
*
27+
* @throws InvalidArgumentException
28+
*
29+
* @return int|string
30+
*/
31+
public function normalize($object, string $format = null, array $context = [])
32+
{
33+
if (!$object instanceof \BackedEnum) {
34+
throw new InvalidArgumentException('The data must belong to a backed enumeration.');
35+
}
36+
37+
return $object->value;
38+
}
39+
40+
/**
41+
* {@inheritdoc}
42+
*/
43+
public function supportsNormalization($data, string $format = null)
44+
{
45+
return $data instanceof \BackedEnum;
46+
}
47+
48+
/**
49+
* {@inheritdoc}
50+
*
51+
* @throws NotNormalizableValueException
52+
*/
53+
public function denormalize($data, string $type, string $format = null, array $context = [])
54+
{
55+
if (!is_subclass_of($type, '\BackedEnum')) {
56+
throw new InvalidArgumentException('The data must belong to a backed enumeration.');
57+
}
58+
59+
if ('' === $data || null === $data) {
60+
throw new NotNormalizableValueException('The data is either an empty string or null, you should pass a string that can be parsed as an enumeration case of type '.$type.'.');
61+
}
62+
63+
try {
64+
return $type::from($data);
65+
} catch (\Exception | \ValueError $e) {
66+
throw new NotNormalizableValueException($e->getMessage(), $e->getCode(), $e);
67+
}
68+
}
69+
70+
/**
71+
* {@inheritdoc}
72+
*/
73+
public function supportsDenormalization($data, string $type, string $format = null)
74+
{
75+
return is_subclass_of($type, '\BackedEnum');
76+
}
77+
78+
/**
79+
* {@inheritdoc}
80+
*/
81+
public function hasCacheableSupportsMethod(): bool
82+
{
83+
return __CLASS__ === static::class;
84+
}
85+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Symfony\Component\Serializer\Tests\Fixtures;
4+
5+
enum IntegerBackedEnumDummy: int
6+
{
7+
case SUCCESS = 200;
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Symfony\Component\Serializer\Tests\Fixtures;
4+
5+
enum StringBackedEnumDummy: string
6+
{
7+
case GET = 'GET';
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Symfony\Component\Serializer\Tests\Fixtures;
4+
5+
enum UnitEnumDummy
6+
{
7+
case GET;
8+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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\Normalizer;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
16+
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
17+
use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer;
18+
use Symfony\Component\Serializer\Tests\Fixtures\IntegerBackedEnumDummy;
19+
use Symfony\Component\Serializer\Tests\Fixtures\StringBackedEnumDummy;
20+
use Symfony\Component\Serializer\Tests\Fixtures\UnitEnumDummy;
21+
22+
/**
23+
* @author Alexandre Daubois <alex.daubois@gmail.com>
24+
*/
25+
class BackedEnumNormalizerTest extends TestCase
26+
{
27+
/**
28+
* @var BackedEnumNormalizer
29+
*/
30+
private $normalizer;
31+
32+
protected function setUp(): void
33+
{
34+
$this->normalizer = new BackedEnumNormalizer();
35+
}
36+
37+
/**
38+
* @requires PHP >= 8.1
39+
*/
40+
public function testSupportsNormalization()
41+
{
42+
$this->assertTrue($this->normalizer->supportsNormalization(StringBackedEnumDummy::GET));
43+
$this->assertTrue($this->normalizer->supportsNormalization(IntegerBackedEnumDummy::SUCCESS));
44+
$this->assertFalse($this->normalizer->supportsNormalization(UnitEnumDummy::GET));
45+
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
46+
}
47+
48+
/**
49+
* @requires PHP >= 8.1
50+
*/
51+
public function testNormalize()
52+
{
53+
$this->assertSame('GET', $this->normalizer->normalize(StringBackedEnumDummy::GET));
54+
$this->assertSame(200, $this->normalizer->normalize(IntegerBackedEnumDummy::SUCCESS));
55+
}
56+
57+
/**
58+
* @requires PHP >= 8.1
59+
*/
60+
public function testNormalizeBadObjectTypeThrowsException()
61+
{
62+
$this->expectException(InvalidArgumentException::class);
63+
$this->normalizer->normalize(new \stdClass());
64+
}
65+
66+
/**
67+
* @requires PHP >= 8.1
68+
*/
69+
public function testSupportsDenormalization()
70+
{
71+
$this->assertTrue($this->normalizer->supportsDenormalization(null, StringBackedEnumDummy::class));
72+
$this->assertTrue($this->normalizer->supportsDenormalization(null, IntegerBackedEnumDummy::class));
73+
$this->assertFalse($this->normalizer->supportsDenormalization(null, UnitEnumDummy::class));
74+
$this->assertFalse($this->normalizer->supportsDenormalization(null, \stdClass::class));
75+
}
76+
77+
/**
78+
* @requires PHP >= 8.1
79+
*/
80+
public function testDenormalize()
81+
{
82+
$this->assertSame(StringBackedEnumDummy::GET, $this->normalizer->denormalize('GET', StringBackedEnumDummy::class));
83+
$this->assertSame(IntegerBackedEnumDummy::SUCCESS, $this->normalizer->denormalize(200, IntegerBackedEnumDummy::class));
84+
}
85+
86+
/**
87+
* @requires PHP >= 8.1
88+
*/
89+
public function testDenormalizeNullValueThrowsException()
90+
{
91+
$this->expectException(NotNormalizableValueException::class);
92+
$this->normalizer->denormalize(null, StringBackedEnumDummy::class);
93+
}
94+
95+
/**
96+
* @requires PHP >= 8.1
97+
*/
98+
public function testDenormalizeBadTimeZoneThrowsException()
99+
{
100+
$this->expectException(NotNormalizableValueException::class);
101+
$this->expectExceptionMessage('"POST" is not a valid backing value for enum "'.StringBackedEnumDummy::class.'"');
102+
$this->normalizer->denormalize('POST', StringBackedEnumDummy::class);
103+
}
104+
105+
/**
106+
* @requires PHP < 8.1
107+
*/
108+
public function testSupportsNormalizationShouldFailForLowerThanPHP81()
109+
{
110+
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
111+
}
112+
113+
/**
114+
* @requires PHP < 8.1
115+
*/
116+
public function testNormalizeShouldThrowExceptionForPHPLowerThan81()
117+
{
118+
$this->expectException(\InvalidArgumentException::class);
119+
$this->expectExceptionMessage('The data must belong to a backed enumeration.');
120+
121+
$this->normalizer->normalize(\stdClass::class);
122+
}
123+
124+
/**
125+
* @requires PHP < 8.1
126+
*/
127+
public function testDenormalizeShouldThrowExceptionForPHPLowerThan81()
128+
{
129+
$this->expectException(\InvalidArgumentException::class);
130+
$this->expectExceptionMessage('The data must belong to a backed enumeration.');
131+
132+
$this->normalizer->denormalize('GET', \stdClass::class);
133+
}
134+
}

0 commit comments

Comments
 (0)
0