1
0
mirror of synced 2025-01-30 20:11:49 +03:00

DDC-720 - Add support to flush only one entity (within cascade rules) through EntityManager#flush()

This commit is contained in:
Benjamin Eberlei 2011-10-22 13:44:33 +02:00
parent 23560038b4
commit f569a2a389
3 changed files with 193 additions and 4 deletions

View File

@ -328,10 +328,10 @@ class EntityManager implements ObjectManager
* @throws Doctrine\ORM\OptimisticLockException If a version check on an entity that * @throws Doctrine\ORM\OptimisticLockException If a version check on an entity that
* makes use of optimistic locking fails. * makes use of optimistic locking fails.
*/ */
public function flush() public function flush($entity = null)
{ {
$this->errorIfClosed(); $this->errorIfClosed();
$this->unitOfWork->commit(); $this->unitOfWork->commit($entity);
} }
/** /**

View File

@ -255,10 +255,14 @@ class UnitOfWork implements PropertyChangedListener
* 5) All entity deletions * 5) All entity deletions
* *
*/ */
public function commit() public function commit($entity = null)
{ {
// Compute changes done since last commit. // Compute changes done since last commit.
$this->computeChangeSets(); if ($entity === null) {
$this->computeChangeSets();
} else {
$this->computeSingleEntityChangeSet($entity);
}
if ( ! ($this->entityInsertions || if ( ! ($this->entityInsertions ||
$this->entityDeletions || $this->entityDeletions ||
@ -346,6 +350,51 @@ class UnitOfWork implements PropertyChangedListener
$this->scheduledForDirtyCheck = $this->scheduledForDirtyCheck =
$this->orphanRemovals = array(); $this->orphanRemovals = array();
} }
/**
* Only flush the given entity according to a rulset that keeps the UoW consistent.
*
* 1. All entities scheduled for insertion, (orphan) removals and changes in collections are processed as well!
* 2. Read Only entities are skipped.
* 3. Proxies are skipped.
* 4. Only if entity is properly managed.
*
* @param Proxy $entity
* @return type
*/
private function computeSingleEntityChangeSet($entity)
{
if ( ! $this->isInIdentityMap($entity) ) {
throw new \InvalidArgumentException("Entity has to be managed for single computation " . self::objToStr($entity));
}
$class = $this->em->getClassMetadata(get_class($entity));
if ($class->isChangeTrackingDeferredImplicit()) {
$this->persist($entity);
}
// Compute changes for INSERTed entities first. This must always happen even in this case.
foreach ($this->entityInsertions as $entity) {
$class = $this->em->getClassMetadata(get_class($entity));
$this->computeChangeSet($class, $entity);
}
if ( $class->isReadOnly ) {
return;
}
// Ignore uninitialized proxy objects
if ($entity instanceof Proxy && ! $entity->__isInitialized__) {
return;
}
// Only MANAGED entities that are NOT SCHEDULED FOR INSERTION are processed here.
$oid = spl_object_hash($entity);
if ( ! isset($this->entityInsertions[$oid]) && isset($this->entityStates[$oid])) {
$this->computeChangeSet($class, $entity);
}
}
/** /**
* Executes any extra updates that have been scheduled. * Executes any extra updates that have been scheduled.

View File

@ -1030,4 +1030,144 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_DETACHED, $unitOfWork->getEntityState($address)); $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_DETACHED, $unitOfWork->getEntityState($address));
} }
/**
* @group DDC-720
*/
public function testFlushSingleManagedEntity()
{
$user = new CmsUser;
$user->name = 'Dominik';
$user->username = 'domnikl';
$user->status = 'developer';
$this->_em->persist($user);
$this->_em->flush();
$user->status = 'administrator';
$this->_em->flush($user);
$this->_em->clear();
$user = $this->_em->find(get_class($user), $user->id);
$this->assertEquals('administrator', $user->status);
}
/**
* @group DDC-720
*/
public function testFlushSingleUnmanagedEntity()
{
$user = new CmsUser;
$user->name = 'Dominik';
$user->username = 'domnikl';
$user->status = 'developer';
$this->setExpectedException('InvalidArgumentException', 'Entity has to be managed for single computation');
$this->_em->flush($user);
}
/**
* @group DDC-720
*/
public function testFlushSingleAndNewEntity()
{
$user = new CmsUser;
$user->name = 'Dominik';
$user->username = 'domnikl';
$user->status = 'developer';
$this->_em->persist($user);
$this->_em->flush();
$otherUser = new CmsUser;
$otherUser->name = 'Dominik2';
$otherUser->username = 'domnikl2';
$otherUser->status = 'developer';
$user->status = 'administrator';
$this->_em->persist($otherUser);
$this->_em->flush($user);
$this->assertTrue($this->_em->contains($otherUser), "Other user is contained in EntityManager");
$this->assertTrue($otherUser->id > 0, "other user has an id");
}
/**
* @group DDC-720
*/
public function testFlushAndCascadePersist()
{
$user = new CmsUser;
$user->name = 'Dominik';
$user->username = 'domnikl';
$user->status = 'developer';
$this->_em->persist($user);
$this->_em->flush();
$address = new CmsAddress();
$address->city = "Springfield";
$address->zip = "12354";
$address->country = "Germany";
$address->street = "Foo Street";
$address->user = $user;
$user->address = $address;
$this->_em->flush($user);
$this->assertTrue($this->_em->contains($address), "Other user is contained in EntityManager");
$this->assertTrue($address->id > 0, "other user has an id");
}
/**
* @group DDC-720
*/
public function testFlushSingleAndNoCascade()
{
$user = new CmsUser;
$user->name = 'Dominik';
$user->username = 'domnikl';
$user->status = 'developer';
$this->_em->persist($user);
$this->_em->flush();
$article1 = new CmsArticle();
$article1->topic = 'Foo';
$article1->text = 'Foo Text';
$article1->author = $user;
$user->articles[] = $article1;
$this->setExpectedException('InvalidArgumentException', "A new entity was found through the relationship 'Doctrine\Tests\Models\CMS\CmsUser#articles'");
$this->_em->flush($user);
}
/**
* @group DDC-720
*/
public function testProxyIsIgnored()
{
$user = new CmsUser;
$user->name = 'Dominik';
$user->username = 'domnikl';
$user->status = 'developer';
$this->_em->persist($user);
$this->_em->flush();
$this->_em->clear();
$user = $this->_em->getReference(get_class($user), $user->id);
$otherUser = new CmsUser;
$otherUser->name = 'Dominik2';
$otherUser->username = 'domnikl2';
$otherUser->status = 'developer';
$this->_em->persist($otherUser);
$this->_em->flush($user);
$this->assertTrue($this->_em->contains($otherUser), "Other user is contained in EntityManager");
$this->assertTrue($otherUser->id > 0, "other user has an id");
}
} }