Skip to content

Commit

Permalink
Implemented feature to allow multiple counter caches per associated m…
Browse files Browse the repository at this point in the history
…odel.
  • Loading branch information
ADmad committed Aug 17, 2011
1 parent 54e1de9 commit c3884f4
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 39 deletions.
80 changes: 47 additions & 33 deletions lib/Cake/Model/Model.php
Expand Up @@ -1532,45 +1532,59 @@ public function updateCounterCache($keys = array(), $created = false) {
$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 (!is_array($assoc['counterCache'])) {
if (isset($assoc['counterScope'])) {
$assoc['counterCache'] = array($assoc['counterCache'] => $assoc['counterScope']);
} else {
$assoc['counterCache'] = array($assoc['counterCache'] => array());
}
}

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])
);
$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;
}
}
$conditions[$fkQuoted] = $keys[$foreignKey];

if ($recursive === 0) {
$conditions = array_merge($conditions, (array)$assoc['counterScope']);
}
$count = intval($this->find('count', compact('conditions', 'recursive')));
if (!array_key_exists($foreignKey, $keys)) {
$keys[$foreignKey] = $this->field($foreignKey);
}
$recursive = (empty($conditions) ? -1 : 0);

$this->{$parent}->updateAll(
array($assoc['counterCache'] => $count),
array($this->{$parent}->escapeField() => $keys[$foreignKey])
);
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);

This comment has been minimized.

Copy link
@ceeram

ceeram Apr 24, 2014

Contributor

What is this line doing?

This comment has been minimized.

Copy link
@ADmad

ADmad Apr 25, 2014

Author Member

Your guess is good as mine, the commit was done 3 years ago 😄

This comment has been minimized.

Copy link
@jippi

jippi Apr 25, 2014

Contributor

worst memory ever @ADmad

}
$count = intval($this->find('count', compact('conditions', 'recursive')));

$this->{$parent}->updateAll(
array($field => $count),
array($this->{$parent}->escapeField() => $keys[$foreignKey])
);
}
}
}
}
Expand Down
64 changes: 64 additions & 0 deletions lib/Cake/Test/Case/Model/ModelWriteTest.php
Expand Up @@ -468,6 +468,70 @@ public function testSaveWithCounterCacheScope() {
$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.
*
Expand Down
8 changes: 5 additions & 3 deletions lib/Cake/Test/Fixture/CounterCachePostFixture.php
Expand Up @@ -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),
);
}
7 changes: 4 additions & 3 deletions lib/Cake/Test/Fixture/CounterCacheUserFixture.php
Expand Up @@ -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),
);
}

0 comments on commit c3884f4

Please sign in to comment.