1
0
mirror of synced 2025-01-29 19:41:45 +03:00

[2.0][DDC-32] Fixed.

This commit is contained in:
romanb 2009-10-07 12:39:46 +00:00
parent e1645efa76
commit b8bcd51ff2
4 changed files with 115 additions and 6 deletions

View File

@ -312,12 +312,19 @@ class EntityManager
*/
public function getReference($entityName, $identifier)
{
// Check identity map first, if its already in there just return it.
if ($entity = $this->_unitOfWork->tryGetById($identifier,
$this->_metadataFactory->getMetadataFor($entityName)->rootEntityName)) {
return $entity;
}
if ($this->_config->getAllowPartialObjects()) {
$entity = new $entityName;
$this->getClassMetadata($entityName)->setEntityIdentifier($entity, $identifier);
$this->getClassMetadata($entityName)->setIdentifierValues($entity, $identifier);
} else {
$entity = $this->_proxyFactory->getReferenceProxy($entityName, $identifier);
}
$this->_unitOfWork->registerManaged($entity, (array) $identifier, array());
return $entity;
}

View File

@ -24,6 +24,7 @@ namespace Doctrine\ORM;
use Doctrine\Common\Collections\ArrayCollection,
Doctrine\Common\Collections\Collection,
Doctrine\Common\DoctrineException,
Doctrine\Common\NotifyPropertyChanged,
Doctrine\Common\PropertyChangedListener,
Doctrine\ORM\Event\LifecycleEventArgs;
@ -239,11 +240,19 @@ class UnitOfWork implements PropertyChangedListener
* Commits the UnitOfWork, executing all operations that have been postponed
* up to this point. The state of all managed entities will be synchronized with
* the database.
*
* The operations are executed in the following order:
*
* 1) All entity insertions
* 2) All entity updates
* 3) All collection deletions
* 4) All collection updates
* 5) All entity deletions
*
*/
public function commit()
{
// Compute changes done since last commit.
// This populates _entityUpdates and _collectionUpdates.
$this->computeChangeSets();
if ( ! ($this->_entityInsertions ||
@ -879,6 +888,7 @@ class UnitOfWork implements PropertyChangedListener
* Schedules an extra update that will be executed immediately after the
* regular entity updates within the currently running commit cycle.
*
* @ignore
* @param $entity
* @param $changeset
*/
@ -959,6 +969,7 @@ class UnitOfWork implements PropertyChangedListener
* Note that entities in a hierarchy are registered with the class name of
* the root entity.
*
* @ignore
* @param object $entity The entity to register.
* @return boolean TRUE if the registration was successful, FALSE if the identity of
* the entity in question is already managed.
@ -968,14 +979,14 @@ class UnitOfWork implements PropertyChangedListener
$classMetadata = $this->_em->getClassMetadata(get_class($entity));
$idHash = implode(' ', $this->_entityIdentifiers[spl_object_hash($entity)]);
if ($idHash === '') {
throw DoctrineException::entityMustHaveIdentifyToBeAddedToIdentityMap($entity);
throw DoctrineException::entityMustHaveIdentityToBeAddedToIdentityMap($entity);
}
$className = $classMetadata->rootEntityName;
if (isset($this->_identityMap[$className][$idHash])) {
return false;
}
$this->_identityMap[$className][$idHash] = $entity;
if ($entity instanceof \Doctrine\Common\NotifyPropertyChanged) {
if ($entity instanceof NotifyPropertyChanged) {
$entity->addPropertyChangedListener($this);
}
return true;
@ -1021,6 +1032,7 @@ class UnitOfWork implements PropertyChangedListener
* Removes an entity from the identity map. This effectively detaches the
* entity from the persistence management of Doctrine.
*
* @ignore
* @param object $entity
* @return boolean
*/
@ -1046,6 +1058,7 @@ class UnitOfWork implements PropertyChangedListener
* INTERNAL:
* Gets an entity in the identity map by its identifier hash.
*
* @ignore
* @param string $idHash
* @param string $rootClassName
* @return object
@ -1060,6 +1073,7 @@ class UnitOfWork implements PropertyChangedListener
* Tries to get an entity by its identifier hash. If no entity is found for
* the given hash, FALSE is returned.
*
* @ignore
* @param string $idHash
* @param string $rootClassName
* @return mixed The found entity or FALSE.
@ -1097,6 +1111,7 @@ class UnitOfWork implements PropertyChangedListener
* INTERNAL:
* Checks whether an identifier hash exists in the identity map.
*
* @ignore
* @param string $idHash
* @param string $rootClassName
* @return boolean
@ -1597,6 +1612,7 @@ class UnitOfWork implements PropertyChangedListener
* invoked on that entity at the beginning of the next commit of this
* UnitOfWork.
*
* @ignore
* @param object $entity
*/
public function scheduleOrphanRemoval($entity)
@ -1636,6 +1652,7 @@ class UnitOfWork implements PropertyChangedListener
* INTERNAL:
* Creates an entity. Used for reconstitution of entities during hydration.
*
* @ignore
* @param string $className The name of the entity class.
* @param array $data The data for the entity.
* @return object The created entity instance.
@ -1668,7 +1685,7 @@ class UnitOfWork implements PropertyChangedListener
$this->_entityStates[$oid] = self::STATE_MANAGED;
$this->_originalEntityData[$oid] = $data;
$this->_identityMap[$class->rootEntityName][$idHash] = $entity;
if ($entity instanceof \Doctrine\Common\NotifyPropertyChanged) {
if ($entity instanceof NotifyPropertyChanged) {
$entity->addPropertyChangedListener($this);
}
$overrideLocalValues = true;
@ -1727,6 +1744,7 @@ class UnitOfWork implements PropertyChangedListener
* INTERNAL:
* Sets a property value of the original data array of an entity.
*
* @ignore
* @param string $oid
* @param string $property
* @param mixed $value
@ -1856,7 +1874,7 @@ class UnitOfWork implements PropertyChangedListener
* @param array $id The identifier values.
* @param array $data The original entity data.
*/
public function registerManaged($entity, $id, $data)
public function registerManaged($entity, array $id, array $data)
{
$oid = spl_object_hash($entity);
$this->_entityIdentifiers[$oid] = $id;

View File

@ -108,6 +108,8 @@ class CmsUser
return false;
}
public function getAddress() { return $this->address; }
public function setAddress(CmsAddress $address) {
if ($this->address !== $address) {
$this->address = $address;

View File

@ -349,4 +349,86 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->refresh($user);
$this->assertEquals('developer', $user->status);
}
public function testAddToCollectionDoesNotInitialize()
{
$this->_em->getConfiguration()->setAllowPartialObjects(false);
$user = new CmsUser;
$user->name = 'Guilherme';
$user->username = 'gblanco';
$user->status = 'developer';
for ($i=0; $i<3; ++$i) {
$phone = new CmsPhonenumber;
$phone->phonenumber = 100 + $i;
$user->addPhonenumber($phone);
}
$this->_em->persist($user);
$this->_em->flush();
$this->_em->clear();
$this->assertEquals(3, $user->getPhonenumbers()->count());
$query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username='gblanco'");
$gblanco = $query->getSingleResult();
$this->assertFalse($gblanco->getPhonenumbers()->isInitialized());
$newPhone = new CmsPhonenumber;
$phone->phonenumber = 555;
$gblanco->addPhonenumber($phone);
$this->assertFalse($gblanco->getPhonenumbers()->isInitialized());
$this->_em->flush();
$this->_em->clear();
$query = $this->_em->createQuery("select u, p from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p where u.username='gblanco'");
$gblanco2 = $query->getSingleResult();
$this->assertEquals(4, $gblanco2->getPhonenumbers()->count());
$this->_em->getConfiguration()->setAllowPartialObjects(true);
}
public function testSetSetAssociationWithGetReference()
{
$user = new CmsUser;
$user->name = 'Guilherme';
$user->username = 'gblanco';
$user->status = 'developer';
$this->_em->persist($user);
$address = new CmsAddress;
$address->country = 'Germany';
$address->city = 'Berlin';
$address->zip = '12345';
$this->_em->persist($address);
$this->_em->flush();
$this->_em->detach($address);
$this->assertFalse($this->_em->contains($address));
$this->assertTrue($this->_em->contains($user));
// Assume we only got the identifier of the address and now want to attach
// that address to the user without actually loading it, using getReference().
$addressRef = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsAddress', $address->getId());
$user->setAddress($addressRef);
$this->_em->flush();
$this->_em->clear();
// Check with a fresh load that the association is indeed there
$query = $this->_em->createQuery("select u, a from Doctrine\Tests\Models\CMS\CmsUser u join u.address a where u.username='gblanco'");
$gblanco = $query->getSingleResult();
$this->assertTrue($gblanco instanceof CmsUser);
$this->assertTrue($gblanco->getAddress() instanceof CmsAddress);
$this->assertEquals('Berlin', $gblanco->getAddress()->getCity());
}
}