Commit 5a00a947 authored by romanb's avatar romanb

Implemented three change tracking policys. First test for usage of NotifyPropertyChanged.

parent 832f355a
......@@ -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);
$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);
// Fake original entity date
$this->_unitOfWork->setOriginalEntityData($user1, array(
'id' => 1, 'username' => 'roman'
));
$this->_unitOfWork->setOriginalEntityData($user2, array(
'id' => 2, 'username' => 'jon'
));
// Go
$this->_unitOfWork->computeChangeSets(array($user1, $user2));
// 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']);
$entity = new NotifyChangedEntity;
$entity->setData('thedata');
$this->_unitOfWork->save($entity);
$this->assertTrue($this->_unitOfWork->isInIdentityMap($entity));
$entity->setData('newdata');
$this->assertTrue($this->_unitOfWork->isRegisteredDirty($entity));
$this->assertEquals(array('data' => array('thedata', 'newdata')), $this->_unitOfWork->getEntityChangeSet($entity));
}
*/
/*
public function testSavingSingleEntityWithSequenceIdGeneratorSchedulesInsert()
{
......@@ -214,3 +180,49 @@ 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);
}
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment