[2.0] Enhanced one-to-one self-referential association handling.
This commit is contained in:
parent
3135799f9e
commit
d2405ded5d
@ -288,11 +288,14 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
if ($relation->isOwningSide) {
|
if ($relation->isOwningSide) {
|
||||||
// If there is an inverse mapping on the target class its bidirectional
|
// If there is an inverse mapping on the target class its bidirectional
|
||||||
if (isset($targetClass->inverseMappings[$property])) {
|
if (isset($targetClass->inverseMappings[$property])) {
|
||||||
$sourceProp = $targetClass->inverseMappings[$fieldName]->sourceFieldName;
|
$sourceProp = $targetClass->inverseMappings[$property]->sourceFieldName;
|
||||||
$targetClass->reflFields[$sourceProp]->setValue($entity2, $entity1);
|
$targetClass->reflFields[$sourceProp]->setValue($entity2, $entity1);
|
||||||
|
} else if ($classMetadata1 === $targetClass) {
|
||||||
|
// Special case: self-referencing one-one on the same class
|
||||||
|
$targetClass->reflFields[$property]->setValue($entity2, $entity1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// For sure bidirectional, as there is no inverse side in unidirectional
|
// For sure bidirectional, as there is no inverse side in unidirectional mappings
|
||||||
$targetClass->reflFields[$relation->mappedByFieldName]->setValue($entity2, $entity1);
|
$targetClass->reflFields[$relation->mappedByFieldName]->setValue($entity2, $entity1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ namespace Doctrine\ORM\Persisters;
|
|||||||
|
|
||||||
use Doctrine\DBAL\Types\Type;
|
use Doctrine\DBAL\Types\Type;
|
||||||
use Doctrine\ORM\EntityManager;
|
use Doctrine\ORM\EntityManager;
|
||||||
|
use Doctrine\ORM\UnitOfWork;
|
||||||
use Doctrine\ORM\PersistentCollection;
|
use Doctrine\ORM\PersistentCollection;
|
||||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||||
|
|
||||||
@ -92,7 +93,7 @@ class StandardEntityPersister
|
|||||||
*/
|
*/
|
||||||
public function addInsert($entity)
|
public function addInsert($entity)
|
||||||
{
|
{
|
||||||
$this->_queuedInserts[] = $entity;
|
$this->_queuedInserts[spl_object_hash($entity)] = $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -237,16 +238,22 @@ class StandardEntityPersister
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: If the one-one is self-referencing, check whether the referenced entity ($newVal)
|
// Special case: One-one self-referencing of the same class.
|
||||||
// is still scheduled for insertion. If so:
|
if ($newVal !== null && $assocMapping->sourceEntityName == $assocMapping->targetEntityName) {
|
||||||
// 1) set $newVal = null, so that we insert a null value
|
$oid = spl_object_hash($newVal);
|
||||||
// 2) schedule $entity for an update, so that the FK gets set through an update
|
$isScheduledForInsert = $uow->isRegisteredNew($newVal);
|
||||||
// later, after the referenced entity has been inserted.
|
if (isset($this->_queuedInserts[$oid]) || $isScheduledForInsert) {
|
||||||
//$needsPostponedUpdate = ...
|
// The associated entity $newVal is not yet persisted, so we must
|
||||||
/*if ($assocMapping->sourceEntityName == $assocMapping->targetEntityName &&
|
// set $newVal = null, in order to insert a null value and update later.
|
||||||
isset($this->_queuedInserts[spl_object_hash($entity)])) {
|
$newVal = null;
|
||||||
echo "SELF-REFERENCING!";
|
} else if ($isInsert && ! $isScheduledForInsert && $uow->getEntityState($newVal) == UnitOfWork::STATE_MANAGED) {
|
||||||
}*/
|
// $newVal is already fully persisted
|
||||||
|
// Clear changeset of $newVal, so that only the identifier is updated.
|
||||||
|
// Not sure this is really rock-solid here but it seems to work.
|
||||||
|
$uow->clearEntityChangeSet($oid);
|
||||||
|
$uow->propertyChanged($newVal, $field, $entity, $entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($assocMapping->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
|
foreach ($assocMapping->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
|
||||||
$otherClass = $this->_em->getClassMetadata($assocMapping->targetEntityName);
|
$otherClass = $this->_em->getClassMetadata($assocMapping->targetEntityName);
|
||||||
|
@ -269,8 +269,6 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: commit transaction here?
|
|
||||||
|
|
||||||
// Take new snapshots from visited collections
|
// Take new snapshots from visited collections
|
||||||
foreach ($this->_visitedCollections as $coll) {
|
foreach ($this->_visitedCollections as $coll) {
|
||||||
$coll->takeSnapshot();
|
$coll->takeSnapshot();
|
||||||
@ -548,9 +546,10 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
{
|
{
|
||||||
$className = $class->name;
|
$className = $class->name;
|
||||||
$persister = $this->getEntityPersister($className);
|
$persister = $this->getEntityPersister($className);
|
||||||
foreach ($this->_entityInsertions as $entity) {
|
foreach ($this->_entityInsertions as $oid => $entity) {
|
||||||
if (get_class($entity) == $className) {
|
if (get_class($entity) == $className) {
|
||||||
$persister->addInsert($entity);
|
$persister->addInsert($entity);
|
||||||
|
unset($this->_entityInsertions[$oid]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$postInsertIds = $persister->executeInserts();
|
$postInsertIds = $persister->executeInserts();
|
||||||
@ -577,9 +576,10 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
{
|
{
|
||||||
$className = $class->name;
|
$className = $class->name;
|
||||||
$persister = $this->getEntityPersister($className);
|
$persister = $this->getEntityPersister($className);
|
||||||
foreach ($this->_entityUpdates as $entity) {
|
foreach ($this->_entityUpdates as $oid => $entity) {
|
||||||
if (get_class($entity) == $className) {
|
if (get_class($entity) == $className) {
|
||||||
$persister->update($entity);
|
$persister->update($entity);
|
||||||
|
unset($this->_entityUpdates[$oid]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -593,9 +593,10 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
{
|
{
|
||||||
$className = $class->name;
|
$className = $class->name;
|
||||||
$persister = $this->getEntityPersister($className);
|
$persister = $this->getEntityPersister($className);
|
||||||
foreach ($this->_entityDeletions as $entity) {
|
foreach ($this->_entityDeletions as $oid => $entity) {
|
||||||
if (get_class($entity) == $className) {
|
if (get_class($entity) == $className) {
|
||||||
$persister->delete($entity);
|
$persister->delete($entity);
|
||||||
|
unset($this->_entityDeletions[$oid]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1533,6 +1534,17 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
$this->addToIdentityMap($entity);
|
$this->addToIdentityMap($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* INTERNAL:
|
||||||
|
* Clears the property changeset of the entity with the given OID.
|
||||||
|
*
|
||||||
|
* @param string $oid The entity's OID.
|
||||||
|
*/
|
||||||
|
public function clearEntityChangeSet($oid)
|
||||||
|
{
|
||||||
|
unset($this->_entityChangeSets[$oid]);
|
||||||
|
}
|
||||||
|
|
||||||
/* PropertyChangedListener implementation */
|
/* PropertyChangedListener implementation */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1552,7 +1564,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
$this->_entityChangeSets[$oid][$propertyName] = array($oldValue, $newValue);
|
$this->_entityChangeSets[$oid][$propertyName] = array($oldValue, $newValue);
|
||||||
|
|
||||||
if (isset($class->associationMappings[$propertyName])) {
|
if (isset($class->associationMappings[$propertyName])) {
|
||||||
$assoc = $class->associationMappings[$name];
|
$assoc = $class->associationMappings[$propertyName];
|
||||||
if ($assoc->isOneToOne() && $assoc->isOwningSide) {
|
if ($assoc->isOneToOne() && $assoc->isOwningSide) {
|
||||||
$this->_entityUpdates[$oid] = $entity;
|
$this->_entityUpdates[$oid] = $entity;
|
||||||
} else if ($oldValue instanceof PersistentCollection) {
|
} else if ($oldValue instanceof PersistentCollection) {
|
||||||
|
@ -146,8 +146,7 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->assertTrue($result[0] instanceof CompanyPerson);
|
$this->assertTrue($result[0] instanceof CompanyPerson);
|
||||||
$this->assertEquals('Mary Smith', $result[0]->getName());
|
$this->assertEquals('Mary Smith', $result[0]->getName());
|
||||||
$this->assertTrue($result[0]->getSpouse() instanceof CompanyEmployee);
|
$this->assertTrue($result[0]->getSpouse() instanceof CompanyEmployee);
|
||||||
|
$this->assertEquals('John Smith', $result[0]->getSpouse()->getName());
|
||||||
//var_dump($result);
|
$this->assertSame($result[0], $result[0]->getSpouse()->getSpouse());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user