From 52badf1cdd3b00fd193ce977363b2ee14394fc2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Renan=20Gon=C3=A7alves?= Date: Sun, 11 Sep 2016 12:24:19 +0200 Subject: [PATCH 1/5] Convert generated id value to its PHP representation. According to the conversion rules of a specific DBAL mapping type. --- lib/Doctrine/ORM/UnitOfWork.php | 62 +++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index 1336a57f3..9e759c0ad 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -19,36 +19,33 @@ namespace Doctrine\ORM; -use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService; -use Doctrine\DBAL\LockMode; -use Doctrine\ORM\Internal\HydrationCompleteHandler; -use Doctrine\ORM\Mapping\Reflection\ReflectionPropertiesGetter; -use Exception; -use InvalidArgumentException; -use UnexpectedValueException; - use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\Common\NotifyPropertyChanged; -use Doctrine\Common\PropertyChangedListener; +use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService; use Doctrine\Common\Persistence\ObjectManagerAware; -use Doctrine\ORM\Mapping\ClassMetadata; -use Doctrine\ORM\Proxy\Proxy; - +use Doctrine\Common\PropertyChangedListener; +use Doctrine\DBAL\LockMode; +use Doctrine\ORM\Cache\Persister\CachedPersister; use Doctrine\ORM\Event\LifecycleEventArgs; -use Doctrine\ORM\Event\PreUpdateEventArgs; -use Doctrine\ORM\Event\PreFlushEventArgs; +use Doctrine\ORM\Event\ListenersInvoker; use Doctrine\ORM\Event\OnFlushEventArgs; use Doctrine\ORM\Event\PostFlushEventArgs; -use Doctrine\ORM\Event\ListenersInvoker; - -use Doctrine\ORM\Cache\Persister\CachedPersister; -use Doctrine\ORM\Persisters\Entity\BasicEntityPersister; -use Doctrine\ORM\Persisters\Entity\SingleTablePersister; -use Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister; -use Doctrine\ORM\Persisters\Collection\OneToManyPersister; +use Doctrine\ORM\Event\PreFlushEventArgs; +use Doctrine\ORM\Event\PreUpdateEventArgs; +use Doctrine\ORM\Internal\HydrationCompleteHandler; +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\Reflection\ReflectionPropertiesGetter; use Doctrine\ORM\Persisters\Collection\ManyToManyPersister; +use Doctrine\ORM\Persisters\Collection\OneToManyPersister; +use Doctrine\ORM\Persisters\Entity\BasicEntityPersister; +use Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister; +use Doctrine\ORM\Persisters\Entity\SingleTablePersister; +use Doctrine\ORM\Proxy\Proxy; use Doctrine\ORM\Utility\IdentifierFlattener; +use Exception; +use InvalidArgumentException; +use UnexpectedValueException; /** * The UnitOfWork is responsible for tracking changes to objects during an @@ -890,7 +887,14 @@ class UnitOfWork implements PropertyChangedListener $idValue = $idGen->generate($this->em, $entity); if ( ! $idGen instanceof \Doctrine\ORM\Id\AssignedGenerator) { - $idValue = array($class->identifier[0] => $idValue); + $idField = $class->identifier[0]; + + $idValue = [ + $idField => $this->em->getConnection()->convertToPHPValue( + $idValue, + $class->getTypeOfField($idField) + ) + ]; $class->setIdentifierValues($entity, $idValue); } @@ -1008,16 +1012,20 @@ class UnitOfWork implements PropertyChangedListener if ($postInsertIds) { // Persister returned post-insert IDs foreach ($postInsertIds as $postInsertId) { - $id = $postInsertId['generatedId']; + $idField = $class->identifier[0]; + $idValue = $this->em->getConnection()->convertToPHPValue( + $postInsertId['generatedId'], + $class->getTypeOfField($idField) + ); + $entity = $postInsertId['entity']; $oid = spl_object_hash($entity); - $idField = $class->identifier[0]; - $class->reflFields[$idField]->setValue($entity, $id); + $class->reflFields[$idField]->setValue($entity, $idValue); - $this->entityIdentifiers[$oid] = array($idField => $id); + $this->entityIdentifiers[$oid] = array($idField => $idValue); $this->entityStates[$oid] = self::STATE_MANAGED; - $this->originalEntityData[$oid][$idField] = $id; + $this->originalEntityData[$oid][$idField] = $idValue; $this->addToIdentityMap($entity); } From 0a86c324ad368ca5aaa68ab9714f338921a9583a Mon Sep 17 00:00:00 2001 From: Christian Hammerl Date: Sun, 27 Nov 2016 01:45:56 +0100 Subject: [PATCH 2/5] Add test case for autoincremented id of custom type --- .../ORM/Functional/Ticket/DDC5684Test.php | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php new file mode 100644 index 000000000..22c3b0695 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php @@ -0,0 +1,111 @@ +_schemaTool->createSchema([$this->_em->getClassMetadata(DDC5684Object::CLASSNAME)]); + } + + protected function tearDown() + { + $this->_schemaTool->dropSchema([$this->_em->getClassMetadata(DDC5684Object::CLASSNAME)]); + + parent::tearDown(); + } + + public function testAutoIncrementIdWithCustomType() + { + $object = new DDC5684Object(); + $this->_em->persist($object); + $this->_em->flush(); + + $this->assertInstanceOf(DDC5684ObjectId::CLASSNAME, $object->id); + } + + public function testFetchObjectWithAutoIncrementedCustomType() + { + $object = new DDC5684Object(); + $this->_em->persist($object); + $this->_em->flush(); + $this->_em->clear(); + + $rawId = $object->id->value; + $object = $this->_em->find(DDC5684Object::CLASSNAME, new DDC5684ObjectId($rawId)); + + $this->assertInstanceOf(DDC5684ObjectId::CLASSNAME, $object->id); + $this->assertEquals($rawId, $object->id->value); + } +} + +class DDC5684ObjectIdType extends DBALTypes\IntegerType +{ + const NAME = 'ticket_5684_object_id'; + const CLASSNAME = __CLASS__; + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return new DDC5684ObjectId($value); + } + + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + return $value->value; + } + + public function getName() + { + return self::NAME; + } + + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} + +class DDC5684ObjectId +{ + const CLASSNAME = __CLASS__; + + public $value; + + public function __construct($value) + { + $this->value = $value; + } + + public function __toString() + { + return (string) $this->value; + } +} + +/** + * @Entity + * @Table(name="ticket_5684_objects") + */ +class DDC5684Object +{ + const CLASSNAME = __CLASS__; + + /** + * @Id + * @Column(type="ticket_5684_object_id") + * @GeneratedValue(strategy="AUTO") + */ + public $id; +} From e736d196770d5919ea26e35f7592f70a2e16920a Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sun, 27 Nov 2016 17:42:12 +0100 Subject: [PATCH 3/5] #5935 #5684 #6020 #6152 extracted identifier conversion to a private method --- lib/Doctrine/ORM/UnitOfWork.php | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index 9e759c0ad..fbbab7b6a 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -887,14 +887,7 @@ class UnitOfWork implements PropertyChangedListener $idValue = $idGen->generate($this->em, $entity); if ( ! $idGen instanceof \Doctrine\ORM\Id\AssignedGenerator) { - $idField = $class->identifier[0]; - - $idValue = [ - $idField => $this->em->getConnection()->convertToPHPValue( - $idValue, - $class->getTypeOfField($idField) - ) - ]; + $idValue = [$class->getSingleIdentifierFieldName() => $this->convertSingleFieldIdentifierToPHPValue($class, $idValue)]; $class->setIdentifierValues($entity, $idValue); } @@ -1012,11 +1005,8 @@ class UnitOfWork implements PropertyChangedListener if ($postInsertIds) { // Persister returned post-insert IDs foreach ($postInsertIds as $postInsertId) { - $idField = $class->identifier[0]; - $idValue = $this->em->getConnection()->convertToPHPValue( - $postInsertId['generatedId'], - $class->getTypeOfField($idField) - ); + $idField = $class->getSingleIdentifierFieldName(); + $idValue = $this->convertSingleFieldIdentifierToPHPValue($class, $postInsertId['generatedId']); $entity = $postInsertId['entity']; $oid = spl_object_hash($entity); @@ -3475,4 +3465,20 @@ class UnitOfWork implements PropertyChangedListener } } } + + /** + * @param ClassMetadata $class + * @param mixed $identifierValue + * + * @return mixed the identifier after type conversion + * + * @throws \Doctrine\ORM\Mapping\MappingException if the entity has more than a single identifier + */ + private function convertSingleFieldIdentifierToPHPValue(ClassMetadata $class, $identifierValue) + { + return $this->em->getConnection()->convertToPHPValue( + $identifierValue, + $class->getTypeOfField($class->getSingleIdentifierFieldName()) + ); + } } From 73ea0ba8f38b6881ea360aa993260c15e7ecfd4b Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sun, 27 Nov 2016 17:45:50 +0100 Subject: [PATCH 4/5] #5935 #5684 #6020 #6152 adding description to the test scenario --- tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php index 22c3b0695..78e9330a0 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php @@ -5,6 +5,13 @@ namespace Doctrine\Tests\ORM\Functional\Ticket; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types as DBALTypes; +/** + * This test verifies that custom post-insert identifiers respect type conversion semantics. + * The generated identifier must be converted via DBAL types before populating the entity + * identifier field. + * + * @group 5935 5684 6020 6152 + */ class DDC5684Test extends \Doctrine\Tests\OrmFunctionalTestCase { protected function setUp() From cff5c07014aa4c35a8f085018bf4883ebd5da828 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sun, 27 Nov 2016 17:49:09 +0100 Subject: [PATCH 5/5] #5935 #5684 #6020 #6152 removed useless `NAME` constant from the test --- .../Tests/ORM/Functional/Ticket/DDC5684Test.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php index 78e9330a0..a25178de2 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php @@ -18,10 +18,10 @@ class DDC5684Test extends \Doctrine\Tests\OrmFunctionalTestCase { parent::setUp(); - if (DBALTypes\Type::hasType(DDC5684ObjectIdType::NAME)) { - DBALTypes\Type::overrideType(DDC5684ObjectIdType::NAME, DDC5684ObjectIdType::CLASSNAME); + if (DBALTypes\Type::hasType(DDC5684ObjectIdType::CLASSNAME)) { + DBALTypes\Type::overrideType(DDC5684ObjectIdType::CLASSNAME, DDC5684ObjectIdType::CLASSNAME); } else { - DBALTypes\Type::addType(DDC5684ObjectIdType::NAME, DDC5684ObjectIdType::CLASSNAME); + DBALTypes\Type::addType(DDC5684ObjectIdType::CLASSNAME, DDC5684ObjectIdType::CLASSNAME); } $this->_schemaTool->createSchema([$this->_em->getClassMetadata(DDC5684Object::CLASSNAME)]); @@ -60,7 +60,6 @@ class DDC5684Test extends \Doctrine\Tests\OrmFunctionalTestCase class DDC5684ObjectIdType extends DBALTypes\IntegerType { - const NAME = 'ticket_5684_object_id'; const CLASSNAME = __CLASS__; public function convertToPHPValue($value, AbstractPlatform $platform) @@ -75,7 +74,7 @@ class DDC5684ObjectIdType extends DBALTypes\IntegerType public function getName() { - return self::NAME; + return self::CLASSNAME; } public function requiresSQLCommentHint(AbstractPlatform $platform) @@ -111,7 +110,7 @@ class DDC5684Object /** * @Id - * @Column(type="ticket_5684_object_id") + * @Column(type=Doctrine\Tests\ORM\Functional\Ticket\DDC5684ObjectIdType::class) * @GeneratedValue(strategy="AUTO") */ public $id;