diff --git a/lib/Cake/Model/Model.php b/lib/Cake/Model/Model.php index 69c53258d..12a37d846 100644 --- a/lib/Cake/Model/Model.php +++ b/lib/Cake/Model/Model.php @@ -1532,45 +1532,59 @@ class Model extends Object { $keys['old'] = isset($keys['old']) ? $keys['old'] : array(); foreach ($this->belongsTo as $parent => $assoc) { - $foreignKey = $assoc['foreignKey']; - $fkQuoted = $this->escapeField($assoc['foreignKey']); - if (!empty($assoc['counterCache'])) { - if ($assoc['counterCache'] === true) { - $assoc['counterCache'] = Inflector::underscore($this->alias) . '_count'; - } - if (!$this->{$parent}->hasField($assoc['counterCache'])) { - continue; - } - - if (!array_key_exists($foreignKey, $keys)) { - $keys[$foreignKey] = $this->field($foreignKey); - } - $recursive = (isset($assoc['counterScope']) ? 0 : -1); - $conditions = ($recursive === 0) ? (array)$assoc['counterScope'] : array(); - - if (isset($keys['old'][$foreignKey])) { - if ($keys['old'][$foreignKey] != $keys[$foreignKey]) { - $conditions[$fkQuoted] = $keys['old'][$foreignKey]; - $count = intval($this->find('count', compact('conditions', 'recursive'))); - - $this->{$parent}->updateAll( - array($assoc['counterCache'] => $count), - array($this->{$parent}->escapeField() => $keys['old'][$foreignKey]) - ); + if (!is_array($assoc['counterCache'])) { + if (isset($assoc['counterScope'])) { + $assoc['counterCache'] = array($assoc['counterCache'] => $assoc['counterScope']); + } else { + $assoc['counterCache'] = array($assoc['counterCache'] => array()); } } - $conditions[$fkQuoted] = $keys[$foreignKey]; - if ($recursive === 0) { - $conditions = array_merge($conditions, (array)$assoc['counterScope']); + $foreignKey = $assoc['foreignKey']; + $fkQuoted = $this->escapeField($assoc['foreignKey']); + + foreach ($assoc['counterCache'] as $field => $conditions) { + if (!is_string($field)) { + $field = Inflector::underscore($this->alias) . '_count'; + } + if (!$this->{$parent}->hasField($field)) { + continue; + } + if ($conditions === true) { + $conditions = array(); + } else { + $conditions = (array)$conditions; + } + + if (!array_key_exists($foreignKey, $keys)) { + $keys[$foreignKey] = $this->field($foreignKey); + } + $recursive = (empty($conditions) ? -1 : 0); + + if (isset($keys['old'][$foreignKey])) { + if ($keys['old'][$foreignKey] != $keys[$foreignKey]) { + $conditions[$fkQuoted] = $keys['old'][$foreignKey]; + $count = intval($this->find('count', compact('conditions', 'recursive'))); + + $this->{$parent}->updateAll( + array($field => $count), + array($this->{$parent}->escapeField() => $keys['old'][$foreignKey]) + ); + } + } + $conditions[$fkQuoted] = $keys[$foreignKey]; + + if ($recursive === 0) { + $conditions = array_merge($conditions, (array)$conditions); + } + $count = intval($this->find('count', compact('conditions', 'recursive'))); + + $this->{$parent}->updateAll( + array($field => $count), + array($this->{$parent}->escapeField() => $keys[$foreignKey]) + ); } - $count = intval($this->find('count', compact('conditions', 'recursive'))); - - $this->{$parent}->updateAll( - array($assoc['counterCache'] => $count), - array($this->{$parent}->escapeField() => $keys[$foreignKey]) - ); } } } diff --git a/lib/Cake/Test/Case/Model/ModelWriteTest.php b/lib/Cake/Test/Case/Model/ModelWriteTest.php index 82eccc7ab..bb495cb8e 100644 --- a/lib/Cake/Test/Case/Model/ModelWriteTest.php +++ b/lib/Cake/Test/Case/Model/ModelWriteTest.php @@ -468,6 +468,70 @@ class ModelWriteTest extends BaseModelTest { $this->assertEquals($result['Syfile']['item_count'], 1); } +/** + * Tests having multiple counter caches for an associated model + * + * @access public + * @return void + */ + public function testCounterCacheMultipleCaches() { + $this->loadFixtures('CounterCacheUser', 'CounterCachePost'); + $User = new CounterCacheUser(); + $Post = new CounterCachePost(); + $Post->unbindModel(array('belongsTo' => array('User')), false); + $Post->bindModel(array( + 'belongsTo' => array( + 'User' => array( + 'className' => 'CounterCacheUser', + 'foreignKey' => 'user_id', + 'counterCache' => array( + true, + 'posts_published' => array('Post.published' => true) + ) + ) + ) + ), false); + + // Count Increase + $user = $User->find('first', array( + 'conditions' => array('id' => 66), + 'recursive' => -1 + )); + $data = array('Post' => array( + 'id' => 22, + 'title' => 'New Post', + 'user_id' => 66, + 'published' => true + )); + $Post->save($data); + $result = $User->find('first', array( + 'conditions' => array('id' => 66), + 'recursive' => -1 + )); + $this->assertEquals(3, $result[$User->alias]['post_count']); + $this->assertEquals(2, $result[$User->alias]['posts_published']); + + // Count decrease + $Post->delete(1); + $result = $User->find('first', array( + 'conditions' => array('id' => 66), + 'recursive' => -1 + )); + $this->assertEquals(2, $result[$User->alias]['post_count']); + $this->assertEquals(2, $result[$User->alias]['posts_published']); + + // Count update + $data = $Post->find('first', array( + 'conditions' => array('id' => 1), + 'recursive' => -1 + )); + $data[$Post->alias]['user_id'] = 301; + $Post->save($data); + $result = $User->find('all',array('order' => 'User.id')); + $this->assertEquals(2, $result[0]['User']['post_count']); + $this->assertEquals(1, $result[1]['User']['posts_published']); + } + /** * test that beforeValidate returning false can abort saves. * diff --git a/lib/Cake/Test/Fixture/CounterCachePostFixture.php b/lib/Cake/Test/Fixture/CounterCachePostFixture.php index 05ef8f3a9..44c868ea8 100644 --- a/lib/Cake/Test/Fixture/CounterCachePostFixture.php +++ b/lib/Cake/Test/Fixture/CounterCachePostFixture.php @@ -30,11 +30,13 @@ class CounterCachePostFixture extends CakeTestFixture { 'id' => array('type' => 'integer', 'key' => 'primary'), 'title' => array('type' => 'string', 'length' => 255, 'null' => false), 'user_id' => array('type' => 'integer', 'null' => true), + 'user_id' => array('type' => 'integer', 'null' => true), + 'published' => array('type' => 'boolean', 'null' => false) ); public $records = array( - array('id' => 1, 'title' => 'Rock and Roll', 'user_id' => 66), - array('id' => 2, 'title' => 'Music', 'user_id' => 66), - array('id' => 3, 'title' => 'Food', 'user_id' => 301), + array('id' => 1, 'title' => 'Rock and Roll', 'user_id' => 66, 'published' => false), + array('id' => 2, 'title' => 'Music', 'user_id' => 66, 'published' => true), + array('id' => 3, 'title' => 'Food', 'user_id' => 301, 'published' => true), ); } diff --git a/lib/Cake/Test/Fixture/CounterCacheUserFixture.php b/lib/Cake/Test/Fixture/CounterCacheUserFixture.php index f3e6faf43..17f968f8f 100644 --- a/lib/Cake/Test/Fixture/CounterCacheUserFixture.php +++ b/lib/Cake/Test/Fixture/CounterCacheUserFixture.php @@ -29,11 +29,12 @@ class CounterCacheUserFixture extends CakeTestFixture { public $fields = array( 'id' => array('type' => 'integer', 'key' => 'primary'), 'name' => array('type' => 'string', 'length' => 255, 'null' => false), - 'post_count' => array('type' => 'integer', 'null' => true) + 'post_count' => array('type' => 'integer', 'null' => true), + 'posts_published' => array('type' => 'integer', 'null' => true) ); public $records = array( - array('id' => 66, 'name' => 'Alexander','post_count' => 2), - array('id' => 301, 'name' => 'Steven','post_count' => 1), + array('id' => 66, 'name' => 'Alexander', 'post_count' => 2, 'posts_published' => 1), + array('id' => 301, 'name' => 'Steven', 'post_count' => 1, 'posts_published' => 1), ); }