Skip to content

Commit

Permalink
Adds metadata field type and enumType validation against Entity prope…
Browse files Browse the repository at this point in the history
…rty type
  • Loading branch information
yceruto committed Nov 6, 2023
1 parent 16028e4 commit 7613f25
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 0 deletions.
20 changes: 20 additions & 0 deletions lib/Doctrine/ORM/Tools/SchemaValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Doctrine\ORM\Tools;

use BackedEnum;
use Doctrine\DBAL\Types\AsciiStringType;
use Doctrine\DBAL\Types\BigIntType;
use Doctrine\DBAL\Types\BooleanType;
Expand All @@ -21,6 +22,7 @@
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use ReflectionEnum;
use ReflectionNamedType;

use function array_diff;
Expand All @@ -37,6 +39,7 @@
use function get_class;
use function implode;
use function in_array;
use function is_a;
use function sprintf;

use const PHP_VERSION_ID;
Expand Down Expand Up @@ -386,6 +389,23 @@ function (array $fieldMapping) use ($class): ?string {
return null;
}

if (
is_a($propertyType, BackedEnum::class, true)
&& $metadataFieldType === (string) (new ReflectionEnum($propertyType))->getBackingType()
) {
if (! isset($fieldMapping['enumType']) || $propertyType === $fieldMapping['enumType']) {
return null;
}

return sprintf(
"The field '%s#%s' has the property type '%s' that differs from the metadata enumType '%s'.",
$class->name,
$fieldName,
$propertyType,
$fieldMapping['enumType']
);
}

return sprintf(
"The field '%s#%s' has the property type '%s' that differs from the metadata field type '%s' returned by the '%s' DBAL type.",
$class->name,
Expand Down
49 changes: 49 additions & 0 deletions tests/Doctrine/Tests/ORM/Functional/Ticket/GH11037/GH11037Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket\GH11037;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Tools\SchemaValidator;
use Doctrine\Tests\OrmTestCase;

/**
* @requires PHP >= 8.1
*/
final class GH11037Test extends OrmTestCase
{
/** @var EntityManagerInterface */
private $em;

/** @var SchemaValidator */
private $validator;

protected function setUp(): void
{
$this->em = $this->getTestEntityManager();
$this->validator = new SchemaValidator($this->em);
}

public function testMetadataFieldTypeCoherentWithEntityPropertyType(): void
{
$class = $this->em->getClassMetadata(ValidEntityWithTypedEnum::class);
$ce = $this->validator->validateClass($class);

self::assertEquals([], $ce);
}

public function testMetadataFieldTypeNotCoherentWithEntityPropertyType(): void
{
$class = $this->em->getClassMetadata(InvalidEntityWithTypedEnum::class);
$ce = $this->validator->validateClass($class);

self::assertEquals(
[
"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.",
"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'.",
],
$ce
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket\GH11037;

enum IntEntityStatus: int
{
case ACTIVE = 0;
case INACTIVE = 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket\GH11037;

use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Id;

/**
* @Entity
*/
class InvalidEntityWithTypedEnum
{
/**
* @Id
* @Column
*/
protected int $id;

/**
* @Column(type="integer", enumType=StringEntityStatus::class)
*/
protected StringEntityStatus $status1;

/**
* @Column(type="integer", enumType=StringEntityStatus::class)
*/
protected IntEntityStatus $status2;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket\GH11037;

enum StringEntityStatus: string
{
case ACTIVE = 'active';
case INACTIVE = 'inactive';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket\GH11037;

use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Id;

/**
* @Entity
*/
class ValidEntityWithTypedEnum
{
/**
* @Id
* @Column
*/
protected int $id;

/**
* @Column(type="string", enumType=StringEntityStatus::class)
*/
protected StringEntityStatus $status1;

/**
* @Column(type="smallint", enumType=IntEntityStatus::class)
*/
protected IntEntityStatus $status2;
}

0 comments on commit 7613f25

Please sign in to comment.