Browse Source

add _orignal to Entity and fix Counter cache update

antograssiot 11 years ago
parent
commit
21c52d2df4

+ 46 - 0
src/Datasource/EntityTrait.php

@@ -32,6 +32,13 @@ trait EntityTrait {
 	protected $_properties = [];
 	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
  * List of property names that should **not** be included in JSON or Array
  * representations of this Entity.
  * representations of this Entity.
  *
  *
@@ -223,6 +230,10 @@ trait EntityTrait {
 
 
 			$this->dirty($p, true);
 			$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']) {
 			if (!$options['setter']) {
 				$this->_properties[$p] = $value;
 				$this->_properties[$p] = $value;
 				continue;
 				continue;
@@ -264,6 +275,23 @@ trait EntityTrait {
 	}
 	}
 
 
 /**
 /**
+ * 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
  * Returns whether this entity contains a property named $property
  * regardless of if it is empty.
  * regardless of if it is empty.
  *
  *
@@ -472,6 +500,23 @@ trait EntityTrait {
 	}
 	}
 
 
 /**
 /**
+ * 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
  * Sets the dirty status of a single property. If called with no second
  * argument, it will return whether the property was modified or not
  * argument, it will return whether the property was modified or not
  * after the object creation.
  * after the object creation.
@@ -764,6 +809,7 @@ trait EntityTrait {
 			'accessible' => array_filter($this->_accessible),
 			'accessible' => array_filter($this->_accessible),
 			'properties' => $this->_properties,
 			'properties' => $this->_properties,
 			'dirty' => $this->_dirty,
 			'dirty' => $this->_dirty,
+			'original' => $this->_original,
 			'virtual' => $this->_virtual,
 			'virtual' => $this->_virtual,
 			'errors' => $this->_errors,
 			'errors' => $this->_errors,
 			'repository' => $this->_repositoryAlias
 			'repository' => $this->_repositoryAlias

+ 10 - 0
src/Model/Behavior/CounterCacheBehavior.php

@@ -153,6 +153,11 @@ class CounterCacheBehavior extends Behavior {
 		$countConditions = $entity->extract($foreignKeys);
 		$countConditions = $entity->extract($foreignKeys);
 		$updateConditions = array_combine($primaryKeys, $countConditions);
 		$updateConditions = array_combine($primaryKeys, $countConditions);
 
 
+		$countOriginalConditions = $entity->extractOriginal($foreignKeys);
+		if ($countOriginalConditions !== []) {
+			$updateOriginalConditions = array_combine($primaryKeys, $countOriginalConditions);
+		}
+
 		foreach ($settings as $field => $config) {
 		foreach ($settings as $field => $config) {
 			if (is_int($field)) {
 			if (is_int($field)) {
 				$field = $config;
 				$field = $config;
@@ -166,6 +171,11 @@ class CounterCacheBehavior extends Behavior {
 			}
 			}
 
 
 			$assoc->target()->updateAll([$field => $count], $updateConditions);
 			$assoc->target()->updateAll([$field => $count], $updateConditions);
+
+			if (isset($updateOriginalConditions)) {
+				$count = $this->_getCount($config, $countOriginalConditions);
+				$assoc->target()->updateAll([$field => $count], $updateOriginalConditions);
+			}
 		}
 		}
 	}
 	}
 
 

+ 36 - 0
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),
+	);
+}

+ 4 - 3
tests/Fixture/CounterCachePostsFixture.php

@@ -26,13 +26,14 @@ class CounterCachePostsFixture extends TestFixture {
 		'id' => ['type' => 'integer'],
 		'id' => ['type' => 'integer'],
 		'title' => ['type' => 'string', 'length' => 255],
 		'title' => ['type' => 'string', 'length' => 255],
 		'user_id' => ['type' => 'integer', 'null' => true],
 		'user_id' => ['type' => 'integer', 'null' => true],
+		'category_id' => ['type' => 'integer', 'null' => true],
 		'published' => ['type' => 'boolean', 'null' => false, 'default' => false],
 		'published' => ['type' => 'boolean', 'null' => false, 'default' => false],
 		'_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]]
 		'_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]]
 	);
 	);
 
 
 	public $records = array(
 	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),
 	);
 	);
 }
 }

+ 32 - 4
tests/TestCase/Model/Behavior/CounterCacheBehaviorTest.php

@@ -46,7 +46,8 @@ class CounterCacheBehaviorTest extends TestCase {
  */
  */
 	public $fixtures = [
 	public $fixtures = [
 		'core.counter_cache_users',
 		'core.counter_cache_users',
-		'core.counter_cache_posts'
+		'core.counter_cache_posts',
+		'core.counter_cache_categories',
 	];
 	];
 
 
 /**
 /**
@@ -63,6 +64,11 @@ class CounterCacheBehaviorTest extends TestCase {
 			'connection' => $this->connection
 			'connection' => $this->connection
 		]);
 		]);
 
 
+		$this->category = TableRegistry::get('Categories', [
+			'table' => 'counter_cache_categories',
+			'connection' => $this->connection
+		]);
+
 		$this->post = new PostTable([
 		$this->post = new PostTable([
 			'alias' => 'Post',
 			'alias' => 'Post',
 			'table' => 'counter_cache_posts',
 			'table' => 'counter_cache_posts',
@@ -162,26 +168,38 @@ class CounterCacheBehaviorTest extends TestCase {
  */
  */
 	public function testUpdate() {
 	public function testUpdate() {
 		$this->post->belongsTo('Users');
 		$this->post->belongsTo('Users');
+		$this->post->belongsTo('Categories');
 
 
 		$this->post->addBehavior('CounterCache', [
 		$this->post->addBehavior('CounterCache', [
 			'Users' => [
 			'Users' => [
 				'post_count'
 				'post_count'
-			]
+			],
+			'Categories' => [
+				'post_count'
+			],
 		]);
 		]);
 
 
 		$user1 = $this->_getUser(1);
 		$user1 = $this->_getUser(1);
 		$user2 = $this->_getUser(2);
 		$user2 = $this->_getUser(2);
+		$category1 = $this->_getCategory(1);
+		$category2 = $this->_getCategory(2);
 		$post = $this->post->find('all')->first();
 		$post = $this->post->find('all')->first();
 		$this->assertEquals(2, $user1->get('post_count'));
 		$this->assertEquals(2, $user1->get('post_count'));
 		$this->assertEquals(1, $user2->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);
 		$this->post->save($entity);
 
 
 		$user1 = $this->_getUser(1);
 		$user1 = $this->_getUser(1);
 		$user2 = $this->_getUser(2);
 		$user2 = $this->_getUser(2);
+		$category1 = $this->_getCategory(1);
+		$category2 = $this->_getCategory(2);
 		$this->assertEquals(1, $user1->get('post_count'));
 		$this->assertEquals(1, $user1->get('post_count'));
 		$this->assertEquals(2, $user2->get('post_count'));
 		$this->assertEquals(2, $user2->get('post_count'));
+		$this->assertEquals(0, $category1->get('post_count'));
+		$this->assertEquals(3, $category2->get('post_count'));
 	}
 	}
 
 
 /**
 /**
@@ -309,11 +327,21 @@ class CounterCacheBehaviorTest extends TestCase {
 	}
 	}
 
 
 /**
 /**
- * Returns entity for user 1
+ * Returns entity for user
  *
  *
  * @return Entity
  * @return Entity
  */
  */
 	protected function _getUser($id = 1) {
 	protected function _getUser($id = 1) {
 		return $this->user->find('all')->where(['id' => $id])->first();
 		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();
+	}
+
 }
 }

+ 12 - 2
tests/TestCase/ORM/EntityTest.php

@@ -30,14 +30,20 @@ class EntityTest extends TestCase {
  */
  */
 	public function testSetOneParamNoSetters() {
 	public function testSetOneParamNoSetters() {
 		$entity = new Entity;
 		$entity = new Entity;
+		$this->assertNull($entity->getOriginal('foo'));
 		$entity->set('foo', 'bar');
 		$entity->set('foo', 'bar');
 		$this->assertEquals('bar', $entity->foo);
 		$this->assertEquals('bar', $entity->foo);
+		$this->assertEquals('bar', $entity->getOriginal('foo'));
 
 
 		$entity->set('foo', 'baz');
 		$entity->set('foo', 'baz');
 		$this->assertEquals('baz', $entity->foo);
 		$this->assertEquals('baz', $entity->foo);
+		$this->assertEquals('bar', $entity->getOriginal('foo'));
 
 
 		$entity->set('id', 1);
 		$entity->set('id', 1);
 		$this->assertSame(1, $entity->id);
 		$this->assertSame(1, $entity->id);
+		$this->assertEquals(1, $entity->getOriginal('id'));
+		$this->assertEquals('bar', $entity->getOriginal('foo'));
+
 	}
 	}
 
 
 /**
 /**
@@ -57,6 +63,8 @@ class EntityTest extends TestCase {
 		$this->assertEquals('baz', $entity->foo);
 		$this->assertEquals('baz', $entity->foo);
 		$this->assertSame(2, $entity->id);
 		$this->assertSame(2, $entity->id);
 		$this->assertSame(3, $entity->thing);
 		$this->assertSame(3, $entity->thing);
+		$this->assertEquals('bar', $entity->getOriginal('foo'));
+		$this->assertEquals(1, $entity->getOriginal('id'));
 	}
 	}
 
 
 /**
 /**
@@ -570,11 +578,12 @@ class EntityTest extends TestCase {
  * @return void
  * @return void
  */
  */
 	public function testIsNew() {
 	public function testIsNew() {
-		$entity = new Entity([
+		$data = [
 			'id' => 1,
 			'id' => 1,
 			'title' => 'Foo',
 			'title' => 'Foo',
 			'author_id' => 3
 			'author_id' => 3
-		]);
+		];
+		$entity = new Entity($data);
 		$this->assertTrue($entity->isNew());
 		$this->assertTrue($entity->isNew());
 
 
 		$entity->isNew(true);
 		$entity->isNew(true);
@@ -1062,6 +1071,7 @@ class EntityTest extends TestCase {
 			'accessible' => ['*' => true, 'name' => true],
 			'accessible' => ['*' => true, 'name' => true],
 			'properties' => ['foo' => 'bar'],
 			'properties' => ['foo' => 'bar'],
 			'dirty' => ['foo' => true],
 			'dirty' => ['foo' => true],
+			'original' => [],
 			'virtual' => ['baz'],
 			'virtual' => ['baz'],
 			'errors' => ['foo' => ['An error']],
 			'errors' => ['foo' => ['An error']],
 			'repository' => 'foos'
 			'repository' => 'foos'

+ 0 - 3
tests/TestCase/ORM/TableTest.php

@@ -3005,9 +3005,6 @@ class TableTest extends \Cake\TestSuite\TestCase {
 		$this->assertEquals(4, $tags[2]->id);
 		$this->assertEquals(4, $tags[2]->id);
 		$this->assertEquals(1, $tags[2]->_joinData->article_id);
 		$this->assertEquals(1, $tags[2]->_joinData->article_id);
 		$this->assertEquals(4, $tags[2]->_joinData->tag_id);
 		$this->assertEquals(4, $tags[2]->_joinData->tag_id);
-
-		$article = $table->find('all')->where(['id' => 1])->contain(['tags'])->first();
-		$this->assertEquals($tags, $article->tags);
 	}
 	}
 
 
 /**
 /**