DDC-720 - Add support to flush only one entity (within cascade rules) through EntityManager#flush()
This commit is contained in:
parent
23560038b4
commit
f569a2a389
@ -328,10 +328,10 @@ class EntityManager implements ObjectManager
|
||||
* @throws Doctrine\ORM\OptimisticLockException If a version check on an entity that
|
||||
* makes use of optimistic locking fails.
|
||||
*/
|
||||
public function flush()
|
||||
public function flush($entity = null)
|
||||
{
|
||||
$this->errorIfClosed();
|
||||
$this->unitOfWork->commit();
|
||||
$this->unitOfWork->commit($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -255,10 +255,14 @@ class UnitOfWork implements PropertyChangedListener
|
||||
* 5) All entity deletions
|
||||
*
|
||||
*/
|
||||
public function commit()
|
||||
public function commit($entity = null)
|
||||
{
|
||||
// Compute changes done since last commit.
|
||||
$this->computeChangeSets();
|
||||
if ($entity === null) {
|
||||
$this->computeChangeSets();
|
||||
} else {
|
||||
$this->computeSingleEntityChangeSet($entity);
|
||||
}
|
||||
|
||||
if ( ! ($this->entityInsertions ||
|
||||
$this->entityDeletions ||
|
||||
@ -346,6 +350,51 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$this->scheduledForDirtyCheck =
|
||||
$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.
|
||||
|
@ -1030,4 +1030,144 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$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");
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user