Skip to content

Instantly share code, notes, and snippets.

@chopstik
Forked from hmic/UpdateCounterCache.php
Last active April 21, 2020 02:16
Show Gist options
  • Save chopstik/2c370a42080b4c97ea4c7c95f449433a to your computer and use it in GitHub Desktop.
Save chopstik/2c370a42080b4c97ea4c7c95f449433a to your computer and use it in GitHub Desktop.
Cake3 update counter caches for association
<?php
namespace App\Model\Table\Traits;
use Cake\ORM\Query;
trait UpdateCounterCacheTrait
{
/**
* @param $association null|string|array
* null - update all CounterCaches
* string - update only the CounterCache for this association
* array - update CounterCaches for the listed associations,
* update only the fields listed like ['Tags' => ['count']]
* if no $cacheFields given, to update all set the key to true
* @param $cacheField null|string|array
* null - update all fields for the CounterCache(s)
* string - update only this field for the CounterCache(s)
* array - update the given fields in the CounterCache(s),
* overwriting possible set fields from the $association array
* @param $reset true|false
* reset the values to 0, if no matching entry could be found
* @return int
* if $verbose_return == false, the total number of updated fields
* @throws RuntimeException when the CounterCacheBehavior is not attached
*/
public function updateCounterCache($association = null, $cacheField = null, $reset = true)
{
$counterCache = $this->behaviors()->get('CounterCache');
if (!$counterCache) {
throw new \RuntimeException('CounterCacheBehavior is not attached.');
}
if (is_string($association)) {
$association = [$association => true];
}
if (is_string($cacheField)) {
$cacheField = [$cacheField];
}
$associations = $counterCache->config();
if ($association) {
$associations = array_intersect_key($associations, $association);
}
$total_count = 0;
foreach ($associations as $assocName => $config) {
$assoc = $this->{$assocName};
$foreign_key = $assoc->foreignKey();
$target = $assoc->target();
$conds = $assoc->conditions();
if ($cacheField) {
$config = array_intersect_key($config, array_flip($cacheField));
} elseif (is_array($association[$assocName])) {
$config = array_intersect_key($config, array_flip($association[$assocName]));
}
foreach ($config as $field => $options) {
if (is_numeric($field)) {
$field = $options;
$options = [];
}
if ($reset) {
$target->query()
->update()
->set($field, 0)
->where($conds)
->execute();
}
if (!isset($options['conditions'])) {
$options['conditions'] = [];
}
/** @var $result Query */
$result = $this->query()
->select([$foreign_key => $foreign_key, 'count' => $this->query()->func()->count('*')])
->where($options['conditions'])
->group($foreign_key)
->execute();
$totalrows = $result->count();
$rowcount = 0;
$count = 0;
while ($row = $result->fetch('assoc')) {
if ($rowcount++ > $totalrows / 100) {
$rowcount = 0;
}
$target->query()
->update()
->set($field, $row['count'])
->where([$target->primaryKey() => $row[$foreign_key]] + $conds)
->execute();
$count++;
}
$total_count += $count;
}
}
return $total_count;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment