From 3480c5d43d9254db5c31a3bfdf9a2edf968a4910 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Sat, 1 Oct 2022 19:48:04 +0200 Subject: [PATCH] Ensure consistent original data with enums --- .../Internal/Hydration/AbstractHydrator.php | 2 +- .../Hydration/SimpleObjectHydrator.php | 17 +++++++++ .../Entity/BasicEntityPersister.php | 3 ++ .../Hydration/SimpleObjectHydratorTest.php | 27 +++++++++++++ .../BasicEntityPersisterResultMappingTest.php | 38 +++++++++++++++++++ 5 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterResultMappingTest.php 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..f6c66b7f3dc 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php @@ -6,9 +6,11 @@ use Doctrine\ORM\Internal\SQLResultCasing; use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\MappingException; use Doctrine\ORM\Query; use Exception; use RuntimeException; +use ValueError; use function array_keys; use function array_search; @@ -140,6 +142,21 @@ protected function hydrateRowData(array $row, array &$result) $value = $type->convertToPHPValue($value, $this->_platform); } + if ($value !== null && isset($cacheKeyInfo['enumType'])) { + $originalValue = $value; + try { + $value = $this->buildEnum($originalValue, $cacheKeyInfo['enumType']); + } catch (ValueError $e) { + throw MappingException::invalidEnumValue( + $entityName, + $cacheKeyInfo['fieldName'], + (string) $originalValue, + $cacheKeyInfo['enumType'], + $e + ); + } + } + $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/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); + } +}