Skip to content

Commit 7151db3

Browse files
committed
Throw exception when trying to use non-backed enum types
1 parent 8503469 commit 7151db3

File tree

5 files changed

+86
-1
lines changed

5 files changed

+86
-1
lines changed

lib/Doctrine/ORM/Mapping/DefaultTypedFieldMapper.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,15 @@ public function validateAndComplete(array $mapping, ReflectionProperty $field):
5757
$mapping['enumType'] = $type->getName();
5858

5959
$reflection = new ReflectionEnum($type->getName());
60-
$type = $reflection->getBackingType();
60+
if (! $reflection->isBacked()) {
61+
throw MappingException::backedEnumTypeRequired(
62+
$field->class,
63+
$mapping['fieldName'],
64+
$mapping['enumType']
65+
);
66+
}
67+
68+
$type = $reflection->getBackingType();
6169

6270
assert($type instanceof ReflectionNamedType);
6371
}

lib/Doctrine/ORM/Mapping/MappingException.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,16 @@ public static function enumsRequirePhp81(string $className, string $fieldName):
954954
return new self(sprintf('Enum types require PHP 8.1 in %s::$%s', $className, $fieldName));
955955
}
956956

957+
public static function backedEnumTypeRequired(string $className, string $fieldName, string $enumType): self
958+
{
959+
return new self(sprintf(
960+
'Attempting to map a non-backed enum type %s in entity %s::$%s. Please use backed enums only',
961+
$enumType,
962+
$className,
963+
$fieldName
964+
));
965+
}
966+
957967
public static function nonEnumTypeMapped(string $className, string $fieldName, string $enumType): self
958968
{
959969
return new self(sprintf(
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\Models\Enums;
6+
7+
use Doctrine\ORM\Mapping\Column;
8+
9+
class FaultySwitch
10+
{
11+
#[Column(type: 'string')]
12+
public string $value;
13+
14+
/**
15+
* The following line is ignored on psalm and phpstan so that we can test
16+
* that the mapping is throwing an exception when a non-backed enum is used.
17+
*
18+
* @psalm-suppress InvalidArgument
19+
*/
20+
#[Column(enumType: SwitchStatus::class)]
21+
public SwitchStatus $status;
22+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\Models\Enums;
6+
7+
enum SwitchStatus
8+
{
9+
case ON;
10+
case OFF;
11+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Mapping;
6+
7+
use Doctrine\ORM\Mapping\DefaultTypedFieldMapper;
8+
use Doctrine\ORM\Mapping\MappingException;
9+
use Doctrine\Tests\Models\Enums\FaultySwitch;
10+
use Doctrine\Tests\OrmTestCase;
11+
use ReflectionClass;
12+
13+
/**
14+
* @requires PHP >= 8.1
15+
*/
16+
class TypedEnumFieldMapperTest extends OrmTestCase
17+
{
18+
private static function defaultTypedFieldMapper(): DefaultTypedFieldMapper
19+
{
20+
return new DefaultTypedFieldMapper();
21+
}
22+
23+
public function testNotBackedEnumThrows(): void
24+
{
25+
$reflectionClass = new ReflectionClass(FaultySwitch::class);
26+
27+
$this->expectException(MappingException::class);
28+
$this->expectExceptionMessage(
29+
'Attempting to map a non-backed enum type Doctrine\Tests\Models\Enums\SwitchStatus in entity Doctrine\Tests\Models\Enums\FaultySwitch::$status. Please use backed enums only'
30+
);
31+
32+
self::defaultTypedFieldMapper()->validateAndComplete(['fieldName' => 'status'], $reflectionClass->getProperty('status'));
33+
}
34+
}

0 commit comments

Comments
 (0)