Skip to content

Commit 7613f25

Browse files
committed
Adds metadata field type and enumType validation against Entity property type
1 parent 16028e4 commit 7613f25

File tree

6 files changed

+153
-0
lines changed

6 files changed

+153
-0
lines changed

Diff for: lib/Doctrine/ORM/Tools/SchemaValidator.php

+20
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Doctrine\ORM\Tools;
66

7+
use BackedEnum;
78
use Doctrine\DBAL\Types\AsciiStringType;
89
use Doctrine\DBAL\Types\BigIntType;
910
use Doctrine\DBAL\Types\BooleanType;
@@ -21,6 +22,7 @@
2122
use Doctrine\ORM\EntityManagerInterface;
2223
use Doctrine\ORM\Mapping\ClassMetadata;
2324
use Doctrine\ORM\Mapping\ClassMetadataInfo;
25+
use ReflectionEnum;
2426
use ReflectionNamedType;
2527

2628
use function array_diff;
@@ -37,6 +39,7 @@
3739
use function get_class;
3840
use function implode;
3941
use function in_array;
42+
use function is_a;
4043
use function sprintf;
4144

4245
use const PHP_VERSION_ID;
@@ -386,6 +389,23 @@ function (array $fieldMapping) use ($class): ?string {
386389
return null;
387390
}
388391

392+
if (
393+
is_a($propertyType, BackedEnum::class, true)
394+
&& $metadataFieldType === (string) (new ReflectionEnum($propertyType))->getBackingType()
395+
) {
396+
if (! isset($fieldMapping['enumType']) || $propertyType === $fieldMapping['enumType']) {
397+
return null;
398+
}
399+
400+
return sprintf(
401+
"The field '%s#%s' has the property type '%s' that differs from the metadata enumType '%s'.",
402+
$class->name,
403+
$fieldName,
404+
$propertyType,
405+
$fieldMapping['enumType']
406+
);
407+
}
408+
389409
return sprintf(
390410
"The field '%s#%s' has the property type '%s' that differs from the metadata field type '%s' returned by the '%s' DBAL type.",
391411
$class->name,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket\GH11037;
6+
7+
use Doctrine\ORM\EntityManagerInterface;
8+
use Doctrine\ORM\Tools\SchemaValidator;
9+
use Doctrine\Tests\OrmTestCase;
10+
11+
/**
12+
* @requires PHP >= 8.1
13+
*/
14+
final class GH11037Test extends OrmTestCase
15+
{
16+
/** @var EntityManagerInterface */
17+
private $em;
18+
19+
/** @var SchemaValidator */
20+
private $validator;
21+
22+
protected function setUp(): void
23+
{
24+
$this->em = $this->getTestEntityManager();
25+
$this->validator = new SchemaValidator($this->em);
26+
}
27+
28+
public function testMetadataFieldTypeCoherentWithEntityPropertyType(): void
29+
{
30+
$class = $this->em->getClassMetadata(ValidEntityWithTypedEnum::class);
31+
$ce = $this->validator->validateClass($class);
32+
33+
self::assertEquals([], $ce);
34+
}
35+
36+
public function testMetadataFieldTypeNotCoherentWithEntityPropertyType(): void
37+
{
38+
$class = $this->em->getClassMetadata(InvalidEntityWithTypedEnum::class);
39+
$ce = $this->validator->validateClass($class);
40+
41+
self::assertEquals(
42+
[
43+
"The field 'Doctrine\Tests\ORM\Functional\Ticket\GH11037\InvalidEntityWithTypedEnum#status1' has the property type 'Doctrine\Tests\ORM\Functional\Ticket\GH11037\StringEntityStatus' that differs from the metadata field type 'int' returned by the 'integer' DBAL type.",
44+
"The field 'Doctrine\Tests\ORM\Functional\Ticket\GH11037\InvalidEntityWithTypedEnum#status2' has the property type 'Doctrine\Tests\ORM\Functional\Ticket\GH11037\IntEntityStatus' that differs from the metadata enumType 'Doctrine\Tests\ORM\Functional\Ticket\GH11037\StringEntityStatus'.",
45+
],
46+
$ce
47+
);
48+
}
49+
}
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\ORM\Functional\Ticket\GH11037;
6+
7+
enum IntEntityStatus: int
8+
{
9+
case ACTIVE = 0;
10+
case INACTIVE = 1;
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket\GH11037;
6+
7+
use Doctrine\ORM\Mapping\Column;
8+
use Doctrine\ORM\Mapping\Entity;
9+
use Doctrine\ORM\Mapping\Id;
10+
11+
/**
12+
* @Entity
13+
*/
14+
class InvalidEntityWithTypedEnum
15+
{
16+
/**
17+
* @Id
18+
* @Column
19+
*/
20+
protected int $id;
21+
22+
/**
23+
* @Column(type="integer", enumType=StringEntityStatus::class)
24+
*/
25+
protected StringEntityStatus $status1;
26+
27+
/**
28+
* @Column(type="integer", enumType=StringEntityStatus::class)
29+
*/
30+
protected IntEntityStatus $status2;
31+
}
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\ORM\Functional\Ticket\GH11037;
6+
7+
enum StringEntityStatus: string
8+
{
9+
case ACTIVE = 'active';
10+
case INACTIVE = 'inactive';
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket\GH11037;
6+
7+
use Doctrine\ORM\Mapping\Column;
8+
use Doctrine\ORM\Mapping\Entity;
9+
use Doctrine\ORM\Mapping\Id;
10+
11+
/**
12+
* @Entity
13+
*/
14+
class ValidEntityWithTypedEnum
15+
{
16+
/**
17+
* @Id
18+
* @Column
19+
*/
20+
protected int $id;
21+
22+
/**
23+
* @Column(type="string", enumType=StringEntityStatus::class)
24+
*/
25+
protected StringEntityStatus $status1;
26+
27+
/**
28+
* @Column(type="smallint", enumType=IntEntityStatus::class)
29+
*/
30+
protected IntEntityStatus $status2;
31+
}

0 commit comments

Comments
 (0)