diff --git a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php index 5af8b876691..024639edc18 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php @@ -697,7 +697,7 @@ protected function registerManaged(ClassMetadata $class, $entity, array $data) * * @return BackedEnum|array */ - private function buildEnum($value, string $enumType) + protected function buildEnum($value, string $enumType) { if (is_array($value)) { return array_map(static function ($value) use ($enumType): BackedEnum { diff --git a/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php index 454330290eb..b939f57b637 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php @@ -140,6 +140,10 @@ protected function hydrateRowData(array $row, array &$result) $value = $type->convertToPHPValue($value, $this->_platform); } + if ($value !== null && isset($cacheKeyInfo['enumType'])) { + $value = $this->buildEnum($value, $cacheKeyInfo['enumType']); + } + $fieldName = $cacheKeyInfo['fieldName']; // Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator) diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index bb974993133..6e6877e8952 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -1506,6 +1506,9 @@ protected function getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r' $columnAlias = $this->getSQLColumnAlias($fieldMapping['columnName']); $this->currentPersisterContext->rsm->addFieldResult($alias, $columnAlias, $field); + if (! empty($fieldMapping['enumType'])) { + $this->currentPersisterContext->rsm->addEnumResult($columnAlias, $fieldMapping['enumType']); + } if (isset($fieldMapping['requireSQLConversion'])) { $type = Type::getType($fieldMapping['type']); diff --git a/tests/Doctrine/Tests/ORM/Functional/EnumTest.php b/tests/Doctrine/Tests/ORM/Functional/EnumTest.php index 9e53b856087..36e2c12f509 100644 --- a/tests/Doctrine/Tests/ORM/Functional/EnumTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/EnumTest.php @@ -7,7 +7,6 @@ use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Driver\AttributeDriver; -use Doctrine\ORM\Mapping\MappingException; use Doctrine\ORM\Query\Expr\Func; use Doctrine\ORM\Tools\SchemaTool; use Doctrine\Tests\Models\DataTransferObjects\DtoWithArrayOfEnums; @@ -22,11 +21,14 @@ use Doctrine\Tests\Models\Enums\TypedCard; use Doctrine\Tests\Models\Enums\Unit; use Doctrine\Tests\OrmFunctionalTestCase; +use ValueError; use function dirname; use function sprintf; use function uniqid; +use const PHP_VERSION_ID; + /** * @requires PHP 8.1 */ @@ -307,15 +309,10 @@ public function testEnumWithNonMatchingDatabaseValueThrowsException(string $card [$metadata->fieldMappings['id']['columnName'] => $card->id] ); - $this->expectException(MappingException::class); + $this->expectException(ValueError::class); $this->expectExceptionMessage(sprintf( - <<<'EXCEPTION' -Context: Trying to hydrate enum property "%s::$suit" -Problem: Case "invalid" is not listed in enum "Doctrine\Tests\Models\Enums\Suit" -Solution: Either add the case to the enum type or migrate the database column to use another case of the enum -EXCEPTION - , - $cardClass + '"invalid" is not a valid backing value for enum ' . (PHP_VERSION_ID < 80200 ? '"%s"' : '%s'), + Suit::class )); $this->_em->find($cardClass, $card->id); diff --git a/tests/Doctrine/Tests/ORM/Hydration/SimpleObjectHydratorTest.php b/tests/Doctrine/Tests/ORM/Hydration/SimpleObjectHydratorTest.php index 01504102ad2..1b84f25bad8 100644 --- a/tests/Doctrine/Tests/ORM/Hydration/SimpleObjectHydratorTest.php +++ b/tests/Doctrine/Tests/ORM/Hydration/SimpleObjectHydratorTest.php @@ -13,6 +13,8 @@ use Doctrine\Tests\Mocks\ArrayResultFactory; use Doctrine\Tests\Models\CMS\CmsAddress; use Doctrine\Tests\Models\Company\CompanyPerson; +use Doctrine\Tests\Models\Enums\Card; +use Doctrine\Tests\Models\Enums\Suit; use Doctrine\Tests\Models\GH8565\GH8565Employee; use Doctrine\Tests\Models\GH8565\GH8565Manager; use Doctrine\Tests\Models\GH8565\GH8565Person; @@ -155,4 +157,29 @@ public function testWrongValuesShouldNotBeConvertedToPhpValue(): void $result = $hydrator->hydrateAll($stmt, $rsm); self::assertEquals($result[0], $expectedEntity); } + + /** + * @requires PHP 8.1 + */ + public function testEnumsAreBuilt(): void + { + $rsm = new ResultSetMapping(); + $rsm->addEntityResult(Card::class, 'r'); + $rsm->addFieldResult('r', 'id_1', 'id'); + $rsm->addFieldResult('r', 'suit_2', 'suit'); + $rsm->addEnumResult('suit_2', Suit::class); + $resultSet = [ + [ + 'id_1' => 1, + 'suit_2' => 'C', + ], + ]; + + $stmt = ArrayResultFactory::createFromArray($resultSet); + $hydrator = new SimpleObjectHydrator($this->entityManager); + $result = $hydrator->hydrateAll($stmt, $rsm)[0]; + + self::assertEquals(Suit::Clubs, $result->suit); + self::assertEquals(Suit::Clubs, $this->entityManager->getUnitOfWork()->getOriginalEntityData($result)['suit']); + } } diff --git a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterResultMappingTest.php b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterResultMappingTest.php new file mode 100644 index 00000000000..7f218e4c353 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterResultMappingTest.php @@ -0,0 +1,38 @@ +entityManager = $this->getTestEntityManager(); + $this->persister = new BasicEntityPersister($this->entityManager, $this->entityManager->getClassMetadata(Card::class)); + } + + /** + * @requires PHP 8.1 + */ + public function testEnumTypeIsAddedToResultMapping(): void + { + $statement = $this->persister->getSelectSQL([]); + self::assertEquals('SELECT t0.id AS id_1, t0.suit AS suit_2 FROM Card t0', $statement); + self::assertEquals(['suit_2' => Suit::class], $this->persister->getResultSetMapping()->enumMappings); + } +}