From e3076eb8d836806cb7ab9dc98aeacee01a367ba4 Mon Sep 17 00:00:00 2001 From: Tomas Date: Tue, 6 Dec 2022 23:08:04 +0100 Subject: [PATCH] Fix association mapping with enum fields Enum fields as ID have worked for some time, but referencing these fields from other entities in association mappings such as OneToOne, ManyToOne and ManyToMany resulted in fatal error as there was an attempt to convert enum value to string improperly. --- lib/Doctrine/ORM/UnitOfWork.php | 4 + .../Doctrine/Tests/Models/GH10132/Complex.php | 67 +++++++++++++ .../Tests/Models/GH10132/ComplexChild.php | 95 +++++++++++++++++++ .../Tests/Models/GH10132/SubComplexChild.php | 75 +++++++++++++++ .../ORM/Functional/Ticket/GH10132Test.php | 74 +++++++++++++++ 5 files changed, 315 insertions(+) create mode 100644 tests/Doctrine/Tests/Models/GH10132/Complex.php create mode 100644 tests/Doctrine/Tests/Models/GH10132/ComplexChild.php create mode 100644 tests/Doctrine/Tests/Models/GH10132/SubComplexChild.php create mode 100644 tests/Doctrine/Tests/ORM/Functional/Ticket/GH10132Test.php diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index a3f1794899b..ed6a65e3e4b 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -2812,6 +2812,10 @@ public function createEntity($className, array $data, &$hints = []) $joinColumnValue = $data[$srcColumn] ?? null; if ($joinColumnValue !== null) { + if ($joinColumnValue instanceof BackedEnum) { + $joinColumnValue = $joinColumnValue->value; + } + if ($targetClass->containsForeignIdentifier) { $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue; } else { diff --git a/tests/Doctrine/Tests/Models/GH10132/Complex.php b/tests/Doctrine/Tests/Models/GH10132/Complex.php new file mode 100644 index 00000000000..84ae59ade6c --- /dev/null +++ b/tests/Doctrine/Tests/Models/GH10132/Complex.php @@ -0,0 +1,67 @@ +complexChildren = new ArrayCollection(); + } + + public function getType(): Suit + { + return $this->type; + } + + public function setType(Suit $type): void + { + $this->type = $type; + } + + public function getNumber(): int + { + return $this->number; + } + + public function setNumber(int $number): void + { + $this->number = $number; + } + + public function getComplexChildren(): Collection + { + return $this->complexChildren; + } + + public function addComplexChild(ComplexChild $complexChild): void + { + $this->complexChildren->add($complexChild); + } +} diff --git a/tests/Doctrine/Tests/Models/GH10132/ComplexChild.php b/tests/Doctrine/Tests/Models/GH10132/ComplexChild.php new file mode 100644 index 00000000000..ca99f953102 --- /dev/null +++ b/tests/Doctrine/Tests/Models/GH10132/ComplexChild.php @@ -0,0 +1,95 @@ +subComplexChildren = new ArrayCollection(); + + $complex->addComplexChild($this); + $this->complexType = $complex->getType(); + $this->complexNumber = $complex->getNumber(); + $this->complex = $complex; + } + + public function getSuit(): Suit + { + return $this->complexType; + } + + public function getComplexNumber(): int + { + return $this->complexNumber; + } + + public function getComplex(): Complex + { + return $this->complex; + } + + public function setPoint(int $point): void + { + $this->point = $point; + } + + public function getPoint(): int + { + return $this->point; + } + + public function getSubComplexChildren(): Collection + { + return $this->subComplexChildren; + } + + public function addSubComplexChild(SubComplexChild $subComplexChild): void + { + $this->subComplexChildren[] = $subComplexChild; + } +} diff --git a/tests/Doctrine/Tests/Models/GH10132/SubComplexChild.php b/tests/Doctrine/Tests/Models/GH10132/SubComplexChild.php new file mode 100644 index 00000000000..34166728dfb --- /dev/null +++ b/tests/Doctrine/Tests/Models/GH10132/SubComplexChild.php @@ -0,0 +1,75 @@ +complexChild; + } + + public function setComplexChild(ComplexChild $complexChild): void + { + $complexChild->addSubComplexChild($this); + $this->complexType = $complexChild->getSuit(); + $this->complexNumber = $complexChild->getComplexNumber(); + $this->complexChildPoint = $complexChild->getPoint(); + $this->complexChild = $complexChild; + } + + public function getNumber(): int + { + return $this->number; + } + + public function setNumber(int $number): void + { + $this->number = $number; + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH10132Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH10132Test.php new file mode 100644 index 00000000000..328e12a6ff6 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH10132Test.php @@ -0,0 +1,74 @@ +createSchemaForModels( + Complex::class, + ComplexChild::class, + SubComplexChild::class + ); + } + + public function testQueryBackedEnumInCompositeKeyJoin(): void + { + $complex = new Complex(); + $complex->setType(Suit::Clubs); + $complex->setNumber(1); + + $complexChild = new ComplexChild(); + $complexChild->setComplex($complex); + $complexChild->setPoint(1); + + $subComplexChild1 = new SubComplexChild(); + $subComplexChild1->setComplexChild($complexChild); + $subComplexChild1->setNumber(1); + + $subComplexChild2 = new SubComplexChild(); + $subComplexChild2->setComplexChild($complexChild); + $subComplexChild2->setNumber(2); + + $subComplexChild3 = new SubComplexChild(); + $subComplexChild3->setComplexChild($complexChild); + $subComplexChild3->setNumber(3); + + $this->_em->persist($complex); + $this->_em->persist($complexChild); + $this->_em->persist($subComplexChild1); + $this->_em->persist($subComplexChild2); + $this->_em->persist($subComplexChild3); + $this->_em->flush(); + $this->_em->clear(); + + $qb = $this->_em->createQueryBuilder(); + $qb->select('s') + ->from(SubComplexChild::class, 's') + ->where('s.complexType = :complexType') + ->andWhere('s.complexNumber = :complexNumber') + ->andWhere('s.complexChildPoint = :complexChildPoint') + ->andWhere('s.number = :number'); + + $qb->setParameter('complexType', Suit::Clubs); + $qb->setParameter('complexNumber', 1); + $qb->setParameter('complexChildPoint', 1); + $qb->setParameter('number', 2); + + self::assertNotNull($qb->getQuery()->getOneOrNullResult()); + } +}