Skip to content

Commit

Permalink
add _orignal to Entity and fix Counter cache update
Browse files Browse the repository at this point in the history
  • Loading branch information
antograssiot committed Oct 5, 2014
1 parent 838ba24 commit 21c52d2
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 12 deletions.
46 changes: 46 additions & 0 deletions src/Datasource/EntityTrait.php
Expand Up @@ -31,6 +31,13 @@ trait EntityTrait {
*/
protected $_properties = [];

/**
* Holds all properties that have been changed and their original values for this entity
*
* @var array
*/
protected $_original = [];

/**
* List of property names that should **not** be included in JSON or Array
* representations of this Entity.
Expand Down Expand Up @@ -223,6 +230,10 @@ public function set($property, $value = null, $options = []) {

$this->dirty($p, true);

if (!isset($this->_original[$p]) && isset($this->_properties[$p]) && $this->_properties[$p] !== $value) {
$this->_original[$p] = $this->_properties[$p];
}

if (!$options['setter']) {
$this->_properties[$p] = $value;
continue;
Expand Down Expand Up @@ -263,6 +274,23 @@ public function &get($property) {
return $value;
}

/**
* Returns the value of an original property by name
*
* @param string $property the name of the property for which original value is retrieved.
* @return mixed
* @throws \InvalidArgumentException if an empty property name is passed.
*/
public function getOriginal($property) {
if (!strlen((string)$property)) {
throw new \InvalidArgumentException('Cannot get an empty property');
}
if (isset($this->_original[$property])) {
return $this->_original[$property];
}
return $this->get($property);
}

/**
* Returns whether this entity contains a property named $property
* regardless of if it is empty.
Expand Down Expand Up @@ -471,6 +499,23 @@ public function extract(array $properties, $onlyDirty = false) {
return $result;
}

/**
* Returns an array with the requested original properties
* stored in this entity, indexed by property name
*
* @param array $properties List of properties to be returned
* @return array
*/
public function extractOriginal(array $properties) {
$result = [];
foreach ($properties as $property) {
if (($this->getOriginal($property) !== null) && ($this->getOriginal($property) !== $this->get($property))) {
$result[$property] = $this->getOriginal($property);
}
}
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
Expand Down Expand Up @@ -764,6 +809,7 @@ public function __debugInfo() {
'accessible' => array_filter($this->_accessible),
'properties' => $this->_properties,
'dirty' => $this->_dirty,
'original' => $this->_original,
'virtual' => $this->_virtual,
'errors' => $this->_errors,
'repository' => $this->_repositoryAlias
Expand Down
10 changes: 10 additions & 0 deletions src/Model/Behavior/CounterCacheBehavior.php
Expand Up @@ -153,6 +153,11 @@ protected function _processAssociation(Event $event, Entity $entity, Association
$countConditions = $entity->extract($foreignKeys);
$updateConditions = array_combine($primaryKeys, $countConditions);

$countOriginalConditions = $entity->extractOriginal($foreignKeys);
if ($countOriginalConditions !== []) {
$updateOriginalConditions = array_combine($primaryKeys, $countOriginalConditions);
}

foreach ($settings as $field => $config) {
if (is_int($field)) {
$field = $config;
Expand All @@ -166,6 +171,11 @@ protected function _processAssociation(Event $event, Entity $entity, Association
}

$assoc->target()->updateAll([$field => $count], $updateConditions);

if (isset($updateOriginalConditions)) {
$count = $this->_getCount($config, $countOriginalConditions);
$assoc->target()->updateAll([$field => $count], $updateOriginalConditions);
}
}
}

Expand Down
36 changes: 36 additions & 0 deletions tests/Fixture/CounterCacheCategoriesFixture.php
@@ -0,0 +1,36 @@
<?php
/**
* CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
* @since 3.0.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Test\Fixture;

use Cake\TestSuite\Fixture\TestFixture;

/**
* Short description for class.
*
*/
class CounterCacheCategoriesFixture extends TestFixture {

public $fields = array(
'id' => ['type' => 'integer'],
'name' => ['type' => 'string', 'length' => 255, 'null' => false],
'post_count' => ['type' => 'integer', 'null' => true],
'_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]]
);

public $records = array(
array('name' => 'Sport', 'post_count' => 1),
array('name' => 'Music', 'post_count' => 2),
);
}
7 changes: 4 additions & 3 deletions tests/Fixture/CounterCachePostsFixture.php
Expand Up @@ -26,13 +26,14 @@ class CounterCachePostsFixture extends TestFixture {
'id' => ['type' => 'integer'],
'title' => ['type' => 'string', 'length' => 255],
'user_id' => ['type' => 'integer', 'null' => true],
'category_id' => ['type' => 'integer', 'null' => true],
'published' => ['type' => 'boolean', 'null' => false, 'default' => false],
'_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]]
);

public $records = array(
array('title' => 'Rock and Roll', 'user_id' => 1, 'published' => 0),
array('title' => 'Music', 'user_id' => 1, 'published' => 1),
array('title' => 'Food', 'user_id' => 2, 'published' => 1),
array('title' => 'Rock and Roll', 'user_id' => 1, 'category_id' => 1, 'published' => 0),
array('title' => 'Music', 'user_id' => 1, 'category_id' => 2, 'published' => 1),
array('title' => 'Food', 'user_id' => 2, 'category_id' => 2, 'published' => 1),
);
}
36 changes: 32 additions & 4 deletions tests/TestCase/Model/Behavior/CounterCacheBehaviorTest.php
Expand Up @@ -46,7 +46,8 @@ class CounterCacheBehaviorTest extends TestCase {
*/
public $fixtures = [
'core.counter_cache_users',
'core.counter_cache_posts'
'core.counter_cache_posts',
'core.counter_cache_categories',
];

/**
Expand All @@ -63,6 +64,11 @@ public function setUp() {
'connection' => $this->connection
]);

$this->category = TableRegistry::get('Categories', [
'table' => 'counter_cache_categories',
'connection' => $this->connection
]);

$this->post = new PostTable([
'alias' => 'Post',
'table' => 'counter_cache_posts',
Expand Down Expand Up @@ -162,26 +168,38 @@ public function testDelete() {
*/
public function testUpdate() {
$this->post->belongsTo('Users');
$this->post->belongsTo('Categories');

$this->post->addBehavior('CounterCache', [
'Users' => [
'post_count'
]
],
'Categories' => [
'post_count'
],
]);

$user1 = $this->_getUser(1);
$user2 = $this->_getUser(2);
$category1 = $this->_getCategory(1);
$category2 = $this->_getCategory(2);
$post = $this->post->find('all')->first();
$this->assertEquals(2, $user1->get('post_count'));
$this->assertEquals(1, $user2->get('post_count'));
$this->assertEquals(1, $category1->get('post_count'));
$this->assertEquals(2, $category2->get('post_count'));

$entity = $this->post->patchEntity($post, ['user_id' => 2]);
$entity = $this->post->patchEntity($post, ['user_id' => 2, 'category_id' => 2]);
$this->post->save($entity);

$user1 = $this->_getUser(1);
$user2 = $this->_getUser(2);
$category1 = $this->_getCategory(1);
$category2 = $this->_getCategory(2);
$this->assertEquals(1, $user1->get('post_count'));
$this->assertEquals(2, $user2->get('post_count'));
$this->assertEquals(0, $category1->get('post_count'));
$this->assertEquals(3, $category2->get('post_count'));
}

/**
Expand Down Expand Up @@ -309,11 +327,21 @@ protected function _getEntity() {
}

/**
* Returns entity for user 1
* Returns entity for user
*
* @return Entity
*/
protected function _getUser($id = 1) {
return $this->user->find('all')->where(['id' => $id])->first();
}

/**
* Returns entity for category
*
* @return Entity
*/
protected function _getCategory($id = 1) {
return $this->category->find('all')->where(['id' => $id])->first();
}

}
14 changes: 12 additions & 2 deletions tests/TestCase/ORM/EntityTest.php
Expand Up @@ -30,14 +30,20 @@ class EntityTest extends TestCase {
*/
public function testSetOneParamNoSetters() {
$entity = new Entity;
$this->assertNull($entity->getOriginal('foo'));
$entity->set('foo', 'bar');
$this->assertEquals('bar', $entity->foo);
$this->assertEquals('bar', $entity->getOriginal('foo'));

$entity->set('foo', 'baz');
$this->assertEquals('baz', $entity->foo);
$this->assertEquals('bar', $entity->getOriginal('foo'));

$entity->set('id', 1);
$this->assertSame(1, $entity->id);
$this->assertEquals(1, $entity->getOriginal('id'));
$this->assertEquals('bar', $entity->getOriginal('foo'));

}

/**
Expand All @@ -57,6 +63,8 @@ public function testSetMultiplePropertiesNoSetters() {
$this->assertEquals('baz', $entity->foo);
$this->assertSame(2, $entity->id);
$this->assertSame(3, $entity->thing);
$this->assertEquals('bar', $entity->getOriginal('foo'));
$this->assertEquals(1, $entity->getOriginal('id'));
}

/**
Expand Down Expand Up @@ -570,11 +578,12 @@ public function testClean() {
* @return void
*/
public function testIsNew() {
$entity = new Entity([
$data = [
'id' => 1,
'title' => 'Foo',
'author_id' => 3
]);
];
$entity = new Entity($data);
$this->assertTrue($entity->isNew());

$entity->isNew(true);
Expand Down Expand Up @@ -1062,6 +1071,7 @@ public function testDebugInfo() {
'accessible' => ['*' => true, 'name' => true],
'properties' => ['foo' => 'bar'],
'dirty' => ['foo' => true],
'original' => [],
'virtual' => ['baz'],
'errors' => ['foo' => ['An error']],
'repository' => 'foos'
Expand Down
3 changes: 0 additions & 3 deletions tests/TestCase/ORM/TableTest.php
Expand Up @@ -3005,9 +3005,6 @@ public function testBelongsToManyIntegration() {
$this->assertEquals(4, $tags[2]->id);
$this->assertEquals(1, $tags[2]->_joinData->article_id);
$this->assertEquals(4, $tags[2]->_joinData->tag_id);

$article = $table->find('all')->where(['id' => 1])->contain(['tags'])->first();
$this->assertEquals($tags, $article->tags);
}

/**
Expand Down

0 comments on commit 21c52d2

Please sign in to comment.