Skip to content

Commit e89fcd7

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

File tree

6 files changed

+154
-0
lines changed

6 files changed

+154
-0
lines changed

lib/Doctrine/ORM/Tools/SchemaValidator.php

Lines changed: 21 additions & 0 deletions
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;
@@ -35,8 +36,10 @@
3536
use function class_parents;
3637
use function count;
3738
use function get_class;
39+
use function get_debug_type;
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,24 @@ function (array $fieldMapping) use ($class): ?string {
386389
return null;
387390
}
388391

392+
if (
393+
is_a($propertyType, BackedEnum::class, true)
394+
&& $metadataFieldType === get_debug_type($propertyType::cases()[0]->value)
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' returned by the '%s' DBAL type.",
402+
$class->name,
403+
$fieldName,
404+
$propertyType,
405+
$fieldMapping['enumType'],
406+
$fieldMapping['type']
407+
);
408+
}
409+
389410
return sprintf(
390411
"The field '%s#%s' has the property type '%s' that differs from the metadata field type '%s' returned by the '%s' DBAL type.",
391412
$class->name,
Lines changed: 49 additions & 0 deletions
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 >= 7.4
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' returned by the 'integer' DBAL type.",
45+
],
46+
$ce
47+
);
48+
}
49+
}
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\ORM\Functional\Ticket\GH11037;
6+
7+
enum IntEntityStatus: int
8+
{
9+
case ACTIVE = 0;
10+
case INACTIVE = 1;
11+
}
Lines changed: 31 additions & 0 deletions
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+
}
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\ORM\Functional\Ticket\GH11037;
6+
7+
enum StringEntityStatus: string
8+
{
9+
case ACTIVE = 'active';
10+
case INACTIVE = 'inactive';
11+
}
Lines changed: 31 additions & 0 deletions
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)