Skip to content

Commit

Permalink
Merge branch 'fix/#5935-#5684-#6020-#6152-id-generator-convert-to-cus…
Browse files Browse the repository at this point in the history
…tom-dbal-id-type'

Close #5935
Close #5684
Close #6020
Close #6152
  • Loading branch information
Ocramius committed Nov 27, 2016
2 parents 4c59ec9 + cff5c07 commit 77a338e
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 26 deletions.
66 changes: 40 additions & 26 deletions lib/Doctrine/ORM/UnitOfWork.php
Expand Up @@ -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\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\SingleTablePersister;
use Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister;
use Doctrine\ORM\Persisters\Collection\OneToManyPersister;
use Doctrine\ORM\Persisters\Collection\ManyToManyPersister;
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
Expand Down Expand Up @@ -890,7 +887,7 @@ private function persistNew($class, $entity)
$idValue = $idGen->generate($this->em, $entity);

if ( ! $idGen instanceof \Doctrine\ORM\Id\AssignedGenerator) {
$idValue = array($class->identifier[0] => $idValue);
$idValue = [$class->getSingleIdentifierFieldName() => $this->convertSingleFieldIdentifierToPHPValue($class, $idValue)];

$class->setIdentifierValues($entity, $idValue);
}
Expand Down Expand Up @@ -1008,16 +1005,17 @@ private function executeInserts($class)
if ($postInsertIds) {
// Persister returned post-insert IDs
foreach ($postInsertIds as $postInsertId) {
$id = $postInsertId['generatedId'];
$idField = $class->getSingleIdentifierFieldName();
$idValue = $this->convertSingleFieldIdentifierToPHPValue($class, $postInsertId['generatedId']);

$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);
}
Expand Down Expand Up @@ -3467,4 +3465,20 @@ private function clearEntityInsertionsForEntityName($entityName)
}
}
}

/**
* @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())
);
}
}
117 changes: 117 additions & 0 deletions tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php
@@ -0,0 +1,117 @@
<?php

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()
{
parent::setUp();

if (DBALTypes\Type::hasType(DDC5684ObjectIdType::CLASSNAME)) {
DBALTypes\Type::overrideType(DDC5684ObjectIdType::CLASSNAME, DDC5684ObjectIdType::CLASSNAME);
} else {
DBALTypes\Type::addType(DDC5684ObjectIdType::CLASSNAME, DDC5684ObjectIdType::CLASSNAME);
}

$this->_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 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::CLASSNAME;
}

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=Doctrine\Tests\ORM\Functional\Ticket\DDC5684ObjectIdType::class)
* @GeneratedValue(strategy="AUTO")
*/
public $id;
}

0 comments on commit 77a338e

Please sign in to comment.