Skip to content

Commit 4dd0cdf

Browse files
authored
fix(doctrine): support integer-backed enums in BackedEnumFilter (#7127)
1 parent 4ddce1f commit 4dd0cdf

File tree

5 files changed

+201
-1
lines changed

5 files changed

+201
-1
lines changed

src/Doctrine/Common/Filter/BackedEnumFilterTrait.php

+9-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ trait BackedEnumFilterTrait
3232
use PropertyHelperTrait;
3333

3434
/**
35-
* @var array<string, string>
35+
* @var array<string, class-string>
3636
*/
3737
private array $enumTypes;
3838

@@ -80,6 +80,14 @@ abstract protected function isBackedEnumField(string $property, string $resource
8080

8181
private function normalizeValue($value, string $property): mixed
8282
{
83+
$firstCase = $this->enumTypes[$property]::cases()[0] ?? null;
84+
if (
85+
\is_int($firstCase?->value)
86+
&& false !== filter_var($value, \FILTER_VALIDATE_INT)
87+
) {
88+
$value = (int) $value;
89+
}
90+
8391
$values = array_map(fn (\BackedEnum $case) => $case->value, $this->enumTypes[$property]::cases());
8492

8593
if (\in_array($value, $values, true)) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue7126;
15+
16+
use ApiPlatform\Doctrine\Orm\Filter\BackedEnumFilter;
17+
use ApiPlatform\Metadata\ApiFilter;
18+
use ApiPlatform\Metadata\GetCollection;
19+
use Doctrine\ORM\Mapping as ORM;
20+
21+
#[GetCollection(
22+
uriTemplate: 'backed_enum_filter{._format}',
23+
)]
24+
#[ApiFilter(BackedEnumFilter::class, properties: ['stringBackedEnum', 'integerBackedEnum'])]
25+
#[ORM\Entity]
26+
class DummyForBackedEnumFilter
27+
{
28+
/**
29+
* @var int The id
30+
*/
31+
#[ORM\Column(type: 'integer')]
32+
#[ORM\Id]
33+
#[ORM\GeneratedValue(strategy: 'AUTO')]
34+
private ?int $id = null;
35+
36+
#[ORM\Column(nullable: true, enumType: StringBackedEnum::class)]
37+
private ?StringBackedEnum $stringBackedEnum = null;
38+
39+
#[ORM\Column(nullable: true, enumType: IntegerBackedEnum::class)]
40+
private ?IntegerBackedEnum $integerBackedEnum = null;
41+
42+
public function getId(): ?int
43+
{
44+
return $this->id;
45+
}
46+
47+
public function getStringBackedEnum(): ?StringBackedEnum
48+
{
49+
return $this->stringBackedEnum;
50+
}
51+
52+
public function setStringBackedEnum(StringBackedEnum $stringBackedEnum): void
53+
{
54+
$this->stringBackedEnum = $stringBackedEnum;
55+
}
56+
57+
public function getIntegerBackedEnum(): ?IntegerBackedEnum
58+
{
59+
return $this->integerBackedEnum;
60+
}
61+
62+
public function setIntegerBackedEnum(IntegerBackedEnum $IntegerBackedEnum): void
63+
{
64+
$this->integerBackedEnum = $IntegerBackedEnum;
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue7126;
15+
16+
enum IntegerBackedEnum: int
17+
{
18+
case One = 1;
19+
case Two = 2;
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue7126;
15+
16+
enum StringBackedEnum: string
17+
{
18+
case One = 'one';
19+
case Two = 'two';
20+
}
+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Functional;
15+
16+
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
17+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue7126\DummyForBackedEnumFilter;
18+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue7126\IntegerBackedEnum;
19+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue7126\StringBackedEnum;
20+
use ApiPlatform\Tests\RecreateSchemaTrait;
21+
use ApiPlatform\Tests\SetupClassResourcesTrait;
22+
23+
final class BackedEnumFilterTest extends ApiTestCase
24+
{
25+
use RecreateSchemaTrait;
26+
use SetupClassResourcesTrait;
27+
28+
protected static ?bool $alwaysBootKernel = false;
29+
30+
/**
31+
* @return class-string[]
32+
*/
33+
public static function getResources(): array
34+
{
35+
return [DummyForBackedEnumFilter::class];
36+
}
37+
38+
public function testFilterStringBackedEnum(): void
39+
{
40+
if ($this->isMongoDB()) {
41+
$this->markTestSkipped();
42+
}
43+
44+
$this->recreateSchema($this->getResources());
45+
$this->loadFixtures();
46+
$route = 'backed_enum_filter';
47+
$response = self::createClient()->request('GET', $route.'?stringBackedEnum='.StringBackedEnum::One->value);
48+
$a = $response->toArray();
49+
$this->assertCount(1, $a['hydra:member']);
50+
$this->assertEquals(StringBackedEnum::One->value, $a['hydra:member'][0]['stringBackedEnum']);
51+
}
52+
53+
public function testFilterIntegerBackedEnum(): void
54+
{
55+
if ($this->isMongoDB()) {
56+
$this->markTestSkipped();
57+
}
58+
59+
$this->recreateSchema($this->getResources());
60+
$this->loadFixtures();
61+
$route = 'backed_enum_filter';
62+
$response = self::createClient()->request('GET', $route.'?integerBackedEnum='.IntegerBackedEnum::Two->value);
63+
$a = $response->toArray();
64+
$this->assertCount(1, $a['hydra:member']);
65+
$this->assertEquals(IntegerBackedEnum::Two->value, $a['hydra:member'][0]['integerBackedEnum']);
66+
}
67+
68+
public function loadFixtures(): void
69+
{
70+
$container = static::$kernel->getContainer();
71+
$registry = $container->get('doctrine');
72+
$manager = $registry->getManager();
73+
74+
$dummyOne = new DummyForBackedEnumFilter();
75+
$dummyOne->setStringBackedEnum(StringBackedEnum::One);
76+
$dummyOne->setIntegerBackedEnum(IntegerBackedEnum::One);
77+
$manager->persist($dummyOne);
78+
79+
$dummyTwo = new DummyForBackedEnumFilter();
80+
$dummyTwo->setStringBackedEnum(StringBackedEnum::Two);
81+
$dummyTwo->setIntegerBackedEnum(IntegerBackedEnum::Two);
82+
$manager->persist($dummyTwo);
83+
84+
$manager->flush();
85+
}
86+
}

0 commit comments

Comments
 (0)