Implemented three change tracking policys. First test for usage of NotifyPropertyChanged.
This commit is contained in:
parent
832f355a30
commit
5a00a9472c
@ -44,21 +44,10 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
'resultCacheImpl' => null,
|
||||
'queryCacheImpl' => null,
|
||||
'metadataCacheImpl' => null,
|
||||
'metadataDriverImpl' => new AnnotationDriver(),
|
||||
'automaticDirtyChecking' => true
|
||||
'metadataDriverImpl' => new AnnotationDriver()
|
||||
));
|
||||
}
|
||||
|
||||
public function setAutomaticDirtyChecking($bool)
|
||||
{
|
||||
$this->_attributes['automaticDirtyChecking'] = $bool;
|
||||
}
|
||||
|
||||
public function getAutomaticDirtyChecking()
|
||||
{
|
||||
return $this->_attributes['automaticDirtyChecking'];
|
||||
}
|
||||
|
||||
public function setMetadataDriverImpl($driverImpl)
|
||||
{
|
||||
$this->_attributes['metadataDriverImpl'] = $driverImpl;
|
||||
|
@ -383,7 +383,7 @@ final class ClassMetadata
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
//private $_changeTrackingPolicy;
|
||||
private $_changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT;
|
||||
|
||||
/**
|
||||
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
|
||||
@ -420,6 +420,51 @@ final class ClassMetadata
|
||||
return $this->_reflectionProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getChangeTrackingPolicy()
|
||||
{
|
||||
return $this->_changeTrackingPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param integer $policy
|
||||
*/
|
||||
public function setChangeTrackingPolicy($policy)
|
||||
{
|
||||
$this->_changeTrackingPolicy = $policy;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isChangeTrackingDeferredExplicit()
|
||||
{
|
||||
return $this->_changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_EXPLICIT;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isChangeTrackingPolicyDeferredImplicit()
|
||||
{
|
||||
return $this->_changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_IMPLICIT;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isChangeTrackingNotify()
|
||||
{
|
||||
return $this->_changeTrackingPolicy == self::CHANGETRACKING_NOTIFY;
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* Adds a reflection property. Usually only used by the ClassMetadataFactory
|
||||
|
@ -309,27 +309,27 @@ class UnitOfWork implements PropertyChangedListener
|
||||
foreach ($entities as $entity) {
|
||||
$entitySet[get_class($entity)][] = $entity;
|
||||
}
|
||||
} else if ( ! $this->_em->getConfiguration()->getAutomaticDirtyChecking()) {
|
||||
$entitySet = $this->_scheduledForDirtyCheck;
|
||||
} else {
|
||||
$entitySet = $this->_identityMap;
|
||||
}
|
||||
|
||||
foreach ($entitySet as $className => $entities) {
|
||||
$class = $this->_em->getClassMetadata($className);
|
||||
if ( ! $class->isInheritanceTypeNone() && count($entities) > 0) {
|
||||
$class = $this->_em->getClassMetadata(get_class($entities[key($entities)]));
|
||||
}
|
||||
|
||||
/*
|
||||
// Skip class if change tracking happens through notification
|
||||
if ($class->isChangeTrackingNotify()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If change tracking is explicit, then only compute changes on explicitly saved entities
|
||||
$entitiesToProcess = $class->isChangeTrackingDeferredExplicit() ?
|
||||
$this->_scheduledForDirtyCheck[$className] : $entities;
|
||||
*/
|
||||
|
||||
foreach ($entities as $entity) {
|
||||
if ( ! $class->isInheritanceTypeNone() && count($entitiesToProcess) > 0) {
|
||||
$class = $this->_em->getClassMetadata(get_class($entitiesToProcess[key($entitiesToProcess)]));
|
||||
}
|
||||
|
||||
foreach ($entitiesToProcess as $entity) {
|
||||
$oid = spl_object_hash($entity);
|
||||
$state = $this->getEntityState($entity);
|
||||
|
||||
@ -970,11 +970,8 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$class = $this->_em->getClassMetadata(get_class($entity));
|
||||
switch ($this->getEntityState($entity)) {
|
||||
case self::STATE_MANAGED:
|
||||
// nothing to do, except if automatic dirty checking is disabled
|
||||
/*if ($class->isChangeTrackingDeferredExplicit()) {
|
||||
$this->scheduleForDirtyCheck($entity);
|
||||
}*/
|
||||
if ( ! $this->_em->getConfiguration()->getAutomaticDirtyChecking()) {
|
||||
// nothing to do, except if policy is "deferred explicit"
|
||||
if ($class->isChangeTrackingDeferredExplicit()) {
|
||||
$this->scheduleForDirtyCheck($entity);
|
||||
}
|
||||
break;
|
||||
@ -1399,7 +1396,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$oid = spl_object_hash($entity);
|
||||
$class = $this->_em->getClassMetadata(get_class($entity));
|
||||
|
||||
$this->_entityChangeSets[$oid][$propertyName] = array($oldValue => $newValue);
|
||||
$this->_entityChangeSets[$oid][$propertyName] = array($oldValue, $newValue);
|
||||
|
||||
if ($class->hasAssociation($propertyName)) {
|
||||
$assoc = $class->getAssociationMapping($name);
|
||||
|
@ -7,7 +7,6 @@ use Doctrine\Tests\Mocks\EntityManagerMock;
|
||||
use Doctrine\Tests\Mocks\UnitOfWorkMock;
|
||||
use Doctrine\Tests\Mocks\EntityPersisterMock;
|
||||
use Doctrine\Tests\Mocks\IdentityIdGeneratorMock;
|
||||
|
||||
use Doctrine\Tests\Models\Forum\ForumUser;
|
||||
use Doctrine\Tests\Models\Forum\ForumAvatar;
|
||||
|
||||
@ -124,54 +123,21 @@ class UnitOfWorkTest extends \Doctrine\Tests\OrmTestCase
|
||||
$this->assertEquals(0, count($avatarPersister->getDeletes()));
|
||||
}
|
||||
|
||||
/*public function testComputeEntityChangeSets()
|
||||
public function testChangeTrackingNotify()
|
||||
{
|
||||
// We need an ID generator for ForumAvatar, because we attach a NEW ForumAvatar
|
||||
// to a (faked) MANAGED instance. During changeset computation this will result
|
||||
// in the UnitOfWork requesting the Id generator of ForumAvatar.
|
||||
$avatarIdGeneratorMock = new IdentityIdGeneratorMock($this->_emMock);
|
||||
$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumAvatar', $avatarIdGeneratorMock);
|
||||
$entity = new NotifyChangedEntity;
|
||||
$entity->setData('thedata');
|
||||
$this->_unitOfWork->save($entity);
|
||||
|
||||
$user1 = new ForumUser();
|
||||
$user1->id = 1;
|
||||
$user1->username = "romanb";
|
||||
$user1->avatar = new ForumAvatar();
|
||||
// Fake managed state
|
||||
$this->_unitOfWork->setEntityState($user1, \Doctrine\ORM\UnitOfWork::STATE_MANAGED);
|
||||
|
||||
$user2 = new ForumUser();
|
||||
$user2->id = 2;
|
||||
$user2->username = "jwage";
|
||||
// Fake managed state
|
||||
$this->_unitOfWork->setEntityState($user2, \Doctrine\ORM\UnitOfWork::STATE_MANAGED);
|
||||
$this->assertTrue($this->_unitOfWork->isInIdentityMap($entity));
|
||||
|
||||
// Fake original entity date
|
||||
$this->_unitOfWork->setOriginalEntityData($user1, array(
|
||||
'id' => 1, 'username' => 'roman'
|
||||
));
|
||||
$this->_unitOfWork->setOriginalEntityData($user2, array(
|
||||
'id' => 2, 'username' => 'jon'
|
||||
));
|
||||
$entity->setData('newdata');
|
||||
|
||||
// Go
|
||||
$this->_unitOfWork->computeChangeSets(array($user1, $user2));
|
||||
$this->assertTrue($this->_unitOfWork->isRegisteredDirty($entity));
|
||||
|
||||
// Verify
|
||||
$user1ChangeSet = $this->_unitOfWork->getEntityChangeSet($user1);
|
||||
$this->assertTrue(is_array($user1ChangeSet));
|
||||
$this->assertEquals(2, count($user1ChangeSet));
|
||||
$this->assertTrue(isset($user1ChangeSet['username']));
|
||||
$this->assertEquals(array('roman' => 'romanb'), $user1ChangeSet['username']);
|
||||
$this->assertTrue(isset($user1ChangeSet['avatar']));
|
||||
$this->assertSame(array(null => $user1->avatar), $user1ChangeSet['avatar']);
|
||||
|
||||
$user2ChangeSet = $this->_unitOfWork->getEntityChangeSet($user2);
|
||||
$this->assertTrue(is_array($user2ChangeSet));
|
||||
$this->assertEquals(1, count($user2ChangeSet));
|
||||
$this->assertTrue(isset($user2ChangeSet['username']));
|
||||
$this->assertEquals(array('jon' => 'jwage'), $user2ChangeSet['username']);
|
||||
$this->assertEquals(array('data' => array('thedata', 'newdata')), $this->_unitOfWork->getEntityChangeSet($entity));
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
public function testSavingSingleEntityWithSequenceIdGeneratorSchedulesInsert()
|
||||
{
|
||||
@ -213,4 +179,50 @@ class UnitOfWorkTest extends \Doctrine\Tests\OrmTestCase
|
||||
//...
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @DoctrineEntity
|
||||
*/
|
||||
class NotifyChangedEntity implements \Doctrine\Common\NotifyPropertyChanged
|
||||
{
|
||||
private $_listeners = array();
|
||||
/**
|
||||
* @DoctrineId
|
||||
* @DoctrineColumn(type="integer")
|
||||
* @DoctrineGeneratedValue(strategy="auto")
|
||||
*/
|
||||
private $id;
|
||||
/**
|
||||
* @DoctrineColumn(type="varchar")
|
||||
*/
|
||||
private $data;
|
||||
|
||||
public function getId() {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getData() {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function setData($data) {
|
||||
if ($data != $this->data) {
|
||||
$this->_onPropertyChanged('data', $this->data, $data);
|
||||
$this->data = $data;
|
||||
}
|
||||
}
|
||||
|
||||
public function addPropertyChangedListener(\Doctrine\Common\PropertyChangedListener $listener)
|
||||
{
|
||||
$this->_listeners[] = $listener;
|
||||
}
|
||||
|
||||
protected function _onPropertyChanged($propName, $oldValue, $newValue) {
|
||||
if ($this->_listeners) {
|
||||
foreach ($this->_listeners as $listener) {
|
||||
$listener->propertyChanged($this, $propName, $oldValue, $newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user