From cce00322580f00efecac61b1318d8115bd454ced Mon Sep 17 00:00:00 2001 From: Reio Remma Date: Thu, 23 Jan 2025 10:43:41 +0200 Subject: [PATCH 1/8] Fix https://github.com/doctrine/orm/issues/11794 --- src/Mapping/ClassMetadata.php | 24 ++++++++++++++++++++++++ src/Mapping/MappingException.php | 18 ++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/Mapping/ClassMetadata.php b/src/Mapping/ClassMetadata.php index 7351d09bce0..f6d3028323b 100644 --- a/src/Mapping/ClassMetadata.php +++ b/src/Mapping/ClassMetadata.php @@ -2165,6 +2165,20 @@ public function setDiscriminatorColumn(DiscriminatorColumnMapping|array|null $co throw MappingException::invalidDiscriminatorColumnType($this->name, $columnDef['type']); } + if (isset($columnDef['enumType'])) { + if (! enum_exists($columnDef['enumType'])) { + throw MappingException::nonEnumTypeMapped($this->name, $columnDef['fieldName'], $columnDef['enumType']); + } + + if ( + defined('Doctrine\DBAL\Types\Types::ENUM') + && $columnDef['type'] === Types::ENUM + && ! isset($columnDef['options']['values']) + ) { + $columnDef['options']['values'] = array_column($columnDef['enumType']::cases(), 'value'); + } + } + $this->discriminatorColumn = DiscriminatorColumnMapping::fromMappingArray($columnDef); } } @@ -2202,6 +2216,16 @@ public function setDiscriminatorMap(array $map): void ); } + $values = $this->discriminatorColumn->options['values'] ?? null; + + if ($values !== null) { + $diff = array_diff(array_keys($map), $values); + + if ($diff !== []) { + throw MappingException::invalidEntriesInDiscriminatorMap(array_values($diff), $this->name, $this->discriminatorColumn->enumType); + } + } + foreach ($map as $value => $className) { $this->addDiscriminatorMapClass($value, $className); } diff --git a/src/Mapping/MappingException.php b/src/Mapping/MappingException.php index 9b732427642..fc81eca6bbb 100644 --- a/src/Mapping/MappingException.php +++ b/src/Mapping/MappingException.php @@ -329,6 +329,24 @@ public static function fileMappingDriversRequireConfiguredDirectoryPath(string|n ); } + /** + * Returns an exception that indicates that discriminator entries used in a discriminator map + * does not exist in the backed enum provided by enumType option. + * + * @param string[] $entries The discriminator entries that could not be found. + * @param string $owningClass The class that declares the discriminator map. + * @param string $enumType The enum that entries were checked against. + */ + public static function invalidEntriesInDiscriminatorMap(array $entries, string $owningClass, string $enumType): self + { + return new self(\sprintf( + "The entries %s in the discriminator map of class '%s' do not correspond to enum cases of '%s'.", + \implode(', ', \array_map(static fn ($entry): string => "'$entry'", $entries)), + $owningClass, + $enumType + )); + } + /** * Returns an exception that indicates that a class used in a discriminator map does not exist. * An example would be an outdated (maybe renamed) classname. From 0e23915e5bfa7f4435f6cafe09943059495e811f Mon Sep 17 00:00:00 2001 From: Reio Remma Date: Thu, 23 Jan 2025 14:11:27 +0200 Subject: [PATCH 2/8] Fix static analysis and style issues. --- src/Mapping/ClassMetadata.php | 2 ++ src/Mapping/MappingException.php | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Mapping/ClassMetadata.php b/src/Mapping/ClassMetadata.php index f6d3028323b..2a5c426fcc9 100644 --- a/src/Mapping/ClassMetadata.php +++ b/src/Mapping/ClassMetadata.php @@ -2197,6 +2197,8 @@ final public function getDiscriminatorColumn(): DiscriminatorColumnMapping * Used for JOINED and SINGLE_TABLE inheritance mapping strategies. * * @param array $map + * + * @throws MappingException */ public function setDiscriminatorMap(array $map): void { diff --git a/src/Mapping/MappingException.php b/src/Mapping/MappingException.php index fc81eca6bbb..4611a9d967f 100644 --- a/src/Mapping/MappingException.php +++ b/src/Mapping/MappingException.php @@ -333,17 +333,17 @@ public static function fileMappingDriversRequireConfiguredDirectoryPath(string|n * Returns an exception that indicates that discriminator entries used in a discriminator map * does not exist in the backed enum provided by enumType option. * - * @param string[] $entries The discriminator entries that could not be found. - * @param string $owningClass The class that declares the discriminator map. - * @param string $enumType The enum that entries were checked against. + * @param array $entries The discriminator entries that could not be found. + * @param string $owningClass The class that declares the discriminator map. + * @param string $enumType The enum that entries were checked against. */ public static function invalidEntriesInDiscriminatorMap(array $entries, string $owningClass, string $enumType): self { - return new self(\sprintf( + return new self(sprintf( "The entries %s in the discriminator map of class '%s' do not correspond to enum cases of '%s'.", - \implode(', ', \array_map(static fn ($entry): string => "'$entry'", $entries)), + implode(', ', array_map(static fn ($entry): string => sprintf("'%s'", $entry), $entries)), $owningClass, - $enumType + $enumType, )); } From 5f9cdb7514da1a13893c69049010a94c9abaa468 Mon Sep 17 00:00:00 2001 From: Reio Remma Date: Fri, 24 Jan 2025 18:02:13 +0200 Subject: [PATCH 3/8] Add testSetDiscriminatorColumnWithEnumType() test. --- tests/Tests/ORM/Tools/SchemaToolTest.php | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/Tests/ORM/Tools/SchemaToolTest.php b/tests/Tests/ORM/Tools/SchemaToolTest.php index 36037fcf569..3dea2bc7a4b 100644 --- a/tests/Tests/ORM/Tools/SchemaToolTest.php +++ b/tests/Tests/ORM/Tools/SchemaToolTest.php @@ -38,6 +38,7 @@ use Doctrine\Tests\Models\Enums\Suit; use Doctrine\Tests\Models\Forum\ForumAvatar; use Doctrine\Tests\Models\Forum\ForumUser; +use Doctrine\Tests\Models\GH10288\GH10288People; use Doctrine\Tests\Models\NullDefault\NullDefaultColumn; use Doctrine\Tests\OrmTestCase; use PHPUnit\Framework\Attributes\Group; @@ -255,6 +256,30 @@ public function testSetDiscriminatorColumnWithoutLength(): void self::assertEquals(255, $column->getLength()); } + public function testSetDiscriminatorColumnWithEnumType(): void + { + $em = $this->getTestEntityManager(); + $schemaTool = new SchemaTool($em); + $metadata = $em->getClassMetadata(FirstEntity::class); + + $metadata->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE); + $metadata->setDiscriminatorColumn(['name' => 'discriminator', 'type' => 'enum', 'enumType' => GH10288People::class]); + + $schema = $schemaTool->getSchemaFromMetadata([$metadata]); + + self::assertTrue($schema->hasTable('first_entity')); + $table = $schema->getTable('first_entity'); + + self::assertTrue($table->hasColumn('discriminator')); + $column = $table->getColumn('discriminator'); + self::assertEquals(GH10288People::class, $column->getPlatformOption('enumType')); + self::assertEquals([0 => 'boss', 1 => 'employee'], $column->getValues()); + + $this->expectException(MappingException::class); + $this->expectExceptionMessage("The entries 'user' in the discriminator map of class '" . FirstEntity::class . "' do not correspond to enum cases of '" . GH10288People::class . "'."); + $metadata->setDiscriminatorMap(['user' => CmsUser::class, 'employee' => CmsEmployee::class]); + } + public function testDerivedCompositeKey(): void { $em = $this->getTestEntityManager(); From 7517fa5097267a9c159fb454197c70f81b68e2cb Mon Sep 17 00:00:00 2001 From: Reio Remma Date: Fri, 25 Apr 2025 16:05:11 +0300 Subject: [PATCH 4/8] Use Types::ENUM in column definition only when it exists. --- tests/Tests/ORM/Tools/SchemaToolTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/Tests/ORM/Tools/SchemaToolTest.php b/tests/Tests/ORM/Tools/SchemaToolTest.php index 3dea2bc7a4b..ba423e01b3a 100644 --- a/tests/Tests/ORM/Tools/SchemaToolTest.php +++ b/tests/Tests/ORM/Tools/SchemaToolTest.php @@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Tools; use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Entity; @@ -263,7 +264,11 @@ public function testSetDiscriminatorColumnWithEnumType(): void $metadata = $em->getClassMetadata(FirstEntity::class); $metadata->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE); - $metadata->setDiscriminatorColumn(['name' => 'discriminator', 'type' => 'enum', 'enumType' => GH10288People::class]); + $metadata->setDiscriminatorColumn([ + 'name' => 'discriminator', + 'type' => defined('Doctrine\DBAL\Types\Types::ENUM') ? Types::ENUM : Types::STRING, + 'enumType' => GH10288People::class, + ]); $schema = $schemaTool->getSchemaFromMetadata([$metadata]); From c508ddb13acf553e22d93ce92b4547ce61de13c6 Mon Sep 17 00:00:00 2001 From: Reio Remma Date: Fri, 25 Apr 2025 16:06:51 +0300 Subject: [PATCH 5/8] Remove dependency on DBAL. --- tests/Tests/ORM/Tools/SchemaToolTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Tests/ORM/Tools/SchemaToolTest.php b/tests/Tests/ORM/Tools/SchemaToolTest.php index ba423e01b3a..a69eb236dad 100644 --- a/tests/Tests/ORM/Tools/SchemaToolTest.php +++ b/tests/Tests/ORM/Tools/SchemaToolTest.php @@ -5,7 +5,6 @@ namespace Doctrine\Tests\ORM\Tools; use Doctrine\Common\Collections\Collection; -use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Entity; @@ -266,7 +265,7 @@ public function testSetDiscriminatorColumnWithEnumType(): void $metadata->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE); $metadata->setDiscriminatorColumn([ 'name' => 'discriminator', - 'type' => defined('Doctrine\DBAL\Types\Types::ENUM') ? Types::ENUM : Types::STRING, + 'type' => defined('Doctrine\DBAL\Types\Types::ENUM') ? 'enum' : 'string', 'enumType' => GH10288People::class, ]); From 626dd0131078bf9525302b428dca6d567d6da7e4 Mon Sep 17 00:00:00 2001 From: Reio Remma Date: Fri, 25 Apr 2025 16:05:11 +0300 Subject: [PATCH 6/8] Use Types::ENUM in column definition only when it exists. --- tests/Tests/ORM/Tools/SchemaToolTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/Tests/ORM/Tools/SchemaToolTest.php b/tests/Tests/ORM/Tools/SchemaToolTest.php index 3dea2bc7a4b..ba423e01b3a 100644 --- a/tests/Tests/ORM/Tools/SchemaToolTest.php +++ b/tests/Tests/ORM/Tools/SchemaToolTest.php @@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Tools; use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Entity; @@ -263,7 +264,11 @@ public function testSetDiscriminatorColumnWithEnumType(): void $metadata = $em->getClassMetadata(FirstEntity::class); $metadata->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE); - $metadata->setDiscriminatorColumn(['name' => 'discriminator', 'type' => 'enum', 'enumType' => GH10288People::class]); + $metadata->setDiscriminatorColumn([ + 'name' => 'discriminator', + 'type' => defined('Doctrine\DBAL\Types\Types::ENUM') ? Types::ENUM : Types::STRING, + 'enumType' => GH10288People::class, + ]); $schema = $schemaTool->getSchemaFromMetadata([$metadata]); From 6e92d4fcdd7c7147167deda72fcd25f97e77cb88 Mon Sep 17 00:00:00 2001 From: Reio Remma Date: Fri, 25 Apr 2025 16:06:51 +0300 Subject: [PATCH 7/8] Remove dependency on DBAL. --- tests/Tests/ORM/Tools/SchemaToolTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Tests/ORM/Tools/SchemaToolTest.php b/tests/Tests/ORM/Tools/SchemaToolTest.php index ba423e01b3a..a69eb236dad 100644 --- a/tests/Tests/ORM/Tools/SchemaToolTest.php +++ b/tests/Tests/ORM/Tools/SchemaToolTest.php @@ -5,7 +5,6 @@ namespace Doctrine\Tests\ORM\Tools; use Doctrine\Common\Collections\Collection; -use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Entity; @@ -266,7 +265,7 @@ public function testSetDiscriminatorColumnWithEnumType(): void $metadata->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE); $metadata->setDiscriminatorColumn([ 'name' => 'discriminator', - 'type' => defined('Doctrine\DBAL\Types\Types::ENUM') ? Types::ENUM : Types::STRING, + 'type' => defined('Doctrine\DBAL\Types\Types::ENUM') ? 'enum' : 'string', 'enumType' => GH10288People::class, ]); From 0b6b750339be806333acd1a2c777e10f56a8955e Mon Sep 17 00:00:00 2001 From: Reio Remma Date: Wed, 11 Jun 2025 10:43:28 +0300 Subject: [PATCH 8/8] Add use statement for defined function. --- tests/Tests/ORM/Tools/SchemaToolTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Tests/ORM/Tools/SchemaToolTest.php b/tests/Tests/ORM/Tools/SchemaToolTest.php index 0e7c961debd..9cce6bf4670 100644 --- a/tests/Tests/ORM/Tools/SchemaToolTest.php +++ b/tests/Tests/ORM/Tools/SchemaToolTest.php @@ -54,6 +54,7 @@ use function class_exists; use function count; use function current; +use function defined; use function enum_exists; use function method_exists;