Skip to content

Commit

Permalink
Implemented Entity::dirty() to mark changes in properties, this will
Browse files Browse the repository at this point in the history
help at later point to only save those properties that were actually
changed
  • Loading branch information
lorenzo committed Oct 25, 2013
1 parent e3c0867 commit 7ebe584
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 6 deletions.
52 changes: 47 additions & 5 deletions Cake/ORM/Entity.php
Expand Up @@ -39,6 +39,14 @@ class Entity implements \ArrayAccess, \JsonSerializable {
*/
protected $_className;

/**
* Holds a list of the properties that where modified after that where added or
* modified after this object was originally created.
*
* @var array
*/
protected $_dirty = [];

/**
* Holds a cached list of methods that exist in the instanced class
*
Expand Down Expand Up @@ -151,12 +159,21 @@ public function set($property, $value = true, $useSetters = true) {
$useSetters = $value;
}

if (!$useSetters) {
$this->_properties = $property + $this->_properties;
return $this;
}

foreach ($property as $p => $value) {
$markDirty = true;
if (isset($this->_properties[$p])) {
$markDirty = $value !== $this->_properties[$p];
}

if ($markDirty) {
$this->dirty($p, true);
}

if (!$useSetters) {
$this->_properties[$p] = $value;
continue;
}

$setter = 'set' . Inflector::camelize($p);
if ($this->_methodExists($setter)) {
$value = $this->{$setter}($value);
Expand Down Expand Up @@ -320,4 +337,29 @@ public function extract(array $properties) {
return $result;
}

/**
* Sets the dirty status of a single property. If called with no second
* argument, it will return whether the property was modified or not
* after the object creation.
*
* @param string $property the field to set or check status for
* @param null|boolean true means the property was changed, false means
* it was not changed and null will make the function return current state
* for that property
* @return boolean whether the property was changed or not
*/
public function dirty($property, $isDirty = null) {
if ($isDirty === null) {
return isset($this->_dirty[$property]);
}

if (!$isDirty) {
unset($this->_dirty[$property]);
return false;
}

$this->_dirty[$property] = true;
return true;
}

}
45 changes: 45 additions & 0 deletions Cake/Test/TestCase/ORM/EntityTest.php
Expand Up @@ -447,4 +447,49 @@ public function testExtract() {
$expected = ['id' => 1, 'crazyness' => null];
$this->assertEquals($expected, $entity->extract(['id', 'crazyness']));
}

/**
* Tests dirty() method on a newly created object
*
* @return void
*/
public function testDirty() {
$entity = new \Cake\ORM\Entity([
'id' => 1,
'title' => 'Foo',
'author_id' => 3
]);
$this->assertTrue($entity->dirty('id'));
$this->assertTrue($entity->dirty('title'));
$this->assertTrue($entity->dirty('author_id'));

$entity->dirty('id', false);
$this->assertFalse($entity->dirty('id'));
$this->assertTrue($entity->dirty('title'));
$entity->dirty('title', false);
$this->assertFalse($entity->dirty('title'));
}

/**
* Tests dirty() when altering properties values and adding new ones
*
* @return void
*/
public function testDirtyChangingProperties() {
$entity = new \Cake\ORM\Entity([
'title' => 'Foo',
]);
$entity->dirty('title', false);
$this->assertFalse($entity->dirty('title'));
$entity->set('title', 'Foo');
$this->assertFalse($entity->dirty('title'));
$entity->set('title', 'Foo');
$this->assertFalse($entity->dirty('title'));
$entity->set('title', 'Something Else');
$this->assertTrue($entity->dirty('title'));

$entity->set('something', 'else');
$this->assertTrue($entity->dirty('something'));
}

}
3 changes: 2 additions & 1 deletion Cake/Test/TestCase/ORM/TableTest.php
Expand Up @@ -1235,7 +1235,8 @@ public function testAtomicSaveRollbackOnFailure() {
->will($this->returnValue($query));

$statement = $this->getMock('\Cake\Database\Statement\StatementDecorator');
$statement->expects($this->once())->method('rowCount')->will($this->returnValue(0));
$statement->expects($this->once())->method('rowCount')
->will($this->returnValue(0));
$connection->expects($this->once())->method('begin');
$connection->expects($this->once())->method('rollback');
$query->expects($this->once())->method('executeStatement')
Expand Down

0 comments on commit 7ebe584

Please sign in to comment.