Merge branch 'DDC-1238'
This commit is contained in:
commit
5c2a4c0339
@ -287,4 +287,25 @@ abstract class AbstractHydrator
|
|||||||
|
|
||||||
return $rowData;
|
return $rowData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function registerManaged($class, $entity, $data)
|
||||||
|
{
|
||||||
|
if ($class->isIdentifierComposite) {
|
||||||
|
$id = array();
|
||||||
|
foreach ($class->identifier as $fieldName) {
|
||||||
|
if (isset($class->associationMappings[$fieldName])) {
|
||||||
|
$id[$fieldName] = $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']];
|
||||||
|
} else {
|
||||||
|
$id[$fieldName] = $data[$fieldName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isset($class->associationMappings[$class->identifier[0]])) {
|
||||||
|
$id = array($class->identifier[0] => $data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']]);
|
||||||
|
} else {
|
||||||
|
$id = array($class->identifier[0] => $data[$class->identifier[0]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->_em->getUnitOfWork()->registerManaged($entity, $id, $data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,6 +205,12 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
$className = $this->_ce[$className]->discriminatorMap[$data[$discrColumn]];
|
$className = $this->_ce[$className]->discriminatorMap[$data[$discrColumn]];
|
||||||
unset($data[$discrColumn]);
|
unset($data[$discrColumn]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($this->_hints[Query::HINT_REFRESH_ENTITY]) && isset($this->_rootAliases[$dqlAlias])) {
|
||||||
|
$class = $this->_ce[$className];
|
||||||
|
$this->registerManaged($class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->_uow->createEntity($className, $data, $this->_hints);
|
return $this->_uow->createEntity($className, $data, $this->_hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,11 +23,10 @@ namespace Doctrine\ORM\Internal\Hydration;
|
|||||||
use \PDO;
|
use \PDO;
|
||||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||||
use Doctrine\DBAL\Types\Type;
|
use Doctrine\DBAL\Types\Type;
|
||||||
|
use Doctrine\ORM\Query;
|
||||||
|
|
||||||
class SimpleObjectHydrator extends AbstractHydrator
|
class SimpleObjectHydrator extends AbstractHydrator
|
||||||
{
|
{
|
||||||
const REFRESH_ENTITY = 'doctrine_refresh_entity';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ClassMetadata
|
* @var ClassMetadata
|
||||||
*/
|
*/
|
||||||
@ -123,17 +122,8 @@ class SimpleObjectHydrator extends AbstractHydrator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($this->_hints[self::REFRESH_ENTITY])) {
|
if (isset($this->_hints[Query::HINT_REFRESH_ENTITY])) {
|
||||||
$this->_hints[Query::HINT_REFRESH] = true;
|
$this->registerManaged($this->class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
|
||||||
$id = array();
|
|
||||||
if ($this->_class->isIdentifierComposite) {
|
|
||||||
foreach ($this->_class->identifier as $fieldName) {
|
|
||||||
$id[$fieldName] = $data[$fieldName];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$id = array($this->_class->identifier[0] => $data[$this->_class->identifier[0]]);
|
|
||||||
}
|
|
||||||
$this->_em->getUnitOfWork()->registerManaged($this->_hints[self::REFRESH_ENTITY], $id, $data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$result[] = $this->_em->getUnitOfWork()->createEntity($entityName, $data, $this->_hints);
|
$result[] = $this->_em->getUnitOfWork()->createEntity($entityName, $data, $this->_hints);
|
||||||
|
@ -570,6 +570,7 @@ class BasicEntityPersister
|
|||||||
|
|
||||||
if ($entity !== null) {
|
if ($entity !== null) {
|
||||||
$hints[Query::HINT_REFRESH] = true;
|
$hints[Query::HINT_REFRESH] = true;
|
||||||
|
$hints[Query::HINT_REFRESH_ENTITY] = $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->_selectJoinSql) {
|
if ($this->_selectJoinSql) {
|
||||||
@ -587,13 +588,12 @@ class BasicEntityPersister
|
|||||||
*
|
*
|
||||||
* @param array $assoc The association to load.
|
* @param array $assoc The association to load.
|
||||||
* @param object $sourceEntity The entity that owns the association (not necessarily the "owning side").
|
* @param object $sourceEntity The entity that owns the association (not necessarily the "owning side").
|
||||||
* @param object $targetEntity The existing ghost entity (proxy) to load, if any.
|
|
||||||
* @param array $identifier The identifier of the entity to load. Must be provided if
|
* @param array $identifier The identifier of the entity to load. Must be provided if
|
||||||
* the association to load represents the owning side, otherwise
|
* the association to load represents the owning side, otherwise
|
||||||
* the identifier is derived from the $sourceEntity.
|
* the identifier is derived from the $sourceEntity.
|
||||||
* @return object The loaded and managed entity instance or NULL if the entity can not be found.
|
* @return object The loaded and managed entity instance or NULL if the entity can not be found.
|
||||||
*/
|
*/
|
||||||
public function loadOneToOneEntity(array $assoc, $sourceEntity, $targetEntity, array $identifier = array())
|
public function loadOneToOneEntity(array $assoc, $sourceEntity, array $identifier = array())
|
||||||
{
|
{
|
||||||
if ($foundEntity = $this->_em->getUnitOfWork()->tryGetById($identifier, $assoc['targetEntity'])) {
|
if ($foundEntity = $this->_em->getUnitOfWork()->tryGetById($identifier, $assoc['targetEntity'])) {
|
||||||
return $foundEntity;
|
return $foundEntity;
|
||||||
@ -621,7 +621,7 @@ class BasicEntityPersister
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$targetEntity = $this->load($identifier, $targetEntity, $assoc, $hints);
|
$targetEntity = $this->load($identifier, null, $assoc, $hints);
|
||||||
|
|
||||||
// Complete bidirectional association, if necessary
|
// Complete bidirectional association, if necessary
|
||||||
if ($targetEntity !== null && $isInverseSingleValued) {
|
if ($targetEntity !== null && $isInverseSingleValued) {
|
||||||
@ -641,7 +641,7 @@ class BasicEntityPersister
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$targetEntity = $this->load($identifier, $targetEntity, $assoc);
|
$targetEntity = $this->load($identifier, null, $assoc);
|
||||||
|
|
||||||
if ($targetEntity !== null) {
|
if ($targetEntity !== null) {
|
||||||
$targetClass->setFieldValue($targetEntity, $assoc['mappedBy'], $sourceEntity);
|
$targetClass->setFieldValue($targetEntity, $assoc['mappedBy'], $sourceEntity);
|
||||||
|
@ -53,6 +53,15 @@ final class Query extends AbstractQuery
|
|||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
const HINT_REFRESH = 'doctrine.refresh';
|
const HINT_REFRESH = 'doctrine.refresh';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal hint: is set to the proxy entity that is currently triggered for loading
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const HINT_REFRESH_ENTITY = 'doctrine.refresh.entity';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The forcePartialLoad query hint forces a particular query to return
|
* The forcePartialLoad query hint forces a particular query to return
|
||||||
* partial objects.
|
* partial objects.
|
||||||
|
@ -1976,7 +1976,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
// a way to solve this with deferred eager loading, which means putting
|
// a way to solve this with deferred eager loading, which means putting
|
||||||
// an entity with subclasses at a *-to-one location is really bad! (performance-wise)
|
// an entity with subclasses at a *-to-one location is really bad! (performance-wise)
|
||||||
$newValue = $this->getEntityPersister($assoc['targetEntity'])
|
$newValue = $this->getEntityPersister($assoc['targetEntity'])
|
||||||
->loadOneToOneEntity($assoc, $entity, null, $associatedId);
|
->loadOneToOneEntity($assoc, $entity, $associatedId);
|
||||||
} else {
|
} else {
|
||||||
// Deferred eager load only works for single identifier classes
|
// Deferred eager load only works for single identifier classes
|
||||||
|
|
||||||
@ -2012,7 +2012,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
} else {
|
} else {
|
||||||
// Inverse side of x-to-one can never be lazy
|
// Inverse side of x-to-one can never be lazy
|
||||||
$class->reflFields[$field]->setValue($entity, $this->getEntityPersister($assoc['targetEntity'])
|
$class->reflFields[$field]->setValue($entity, $this->getEntityPersister($assoc['targetEntity'])
|
||||||
->loadOneToOneEntity($assoc, $entity, null));
|
->loadOneToOneEntity($assoc, $entity));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Inject collection
|
// Inject collection
|
||||||
|
96
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1238Test.php
Normal file
96
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1238Test.php
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||||
|
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use Doctrine\Tests\Models\CMS\CmsEmployee;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../../TestInit.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-1238
|
||||||
|
*/
|
||||||
|
class DDC1238Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||||
|
{
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
try {
|
||||||
|
$this->_schemaTool->createSchema(array(
|
||||||
|
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1238User'),
|
||||||
|
));
|
||||||
|
} catch(\PDOException $e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIssue()
|
||||||
|
{
|
||||||
|
$user = new DDC1238User;
|
||||||
|
$user->setName("test");
|
||||||
|
|
||||||
|
$this->_em->persist($user);
|
||||||
|
$this->_em->flush();
|
||||||
|
$this->_em->clear();
|
||||||
|
|
||||||
|
$userId = $user->getId();
|
||||||
|
$this->_em->clear();
|
||||||
|
|
||||||
|
$user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId);
|
||||||
|
$this->_em->clear();
|
||||||
|
|
||||||
|
$userId2 = $user->getId();
|
||||||
|
$this->assertEquals($userId, $userId2, "This proxy can still be initialized.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIssueProxyClear()
|
||||||
|
{
|
||||||
|
$user = new DDC1238User;
|
||||||
|
$user->setName("test");
|
||||||
|
|
||||||
|
$this->_em->persist($user);
|
||||||
|
$this->_em->flush();
|
||||||
|
$this->_em->clear();
|
||||||
|
|
||||||
|
$userId = $user->getId();
|
||||||
|
$this->_em->clear();
|
||||||
|
|
||||||
|
$user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId);
|
||||||
|
$this->_em->clear();
|
||||||
|
|
||||||
|
$user2 = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId);
|
||||||
|
|
||||||
|
$this->assertNull($user->getId(), "Now this is null, we already have a user instance of that type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Entity
|
||||||
|
*/
|
||||||
|
class DDC1238User
|
||||||
|
{
|
||||||
|
/** @Id @GeneratedValue @Column(type="integer") */
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Column
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName($name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user