1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<?php
/* SVN FILE: $Id$ */
/**
 * CounterCache Behavior for CakePHP 1.2
 *
 * @filesource
 * @copyright      Copyright (c) 2006, iCoreTech
 * @author         $Author$
 * @version        $Rev$
 * @modifiedby     $LastChangedBy$
 * @lastmodified   $Date$
 * @license        http://www.opensource.org/licenses/mit-license.php The MIT License
 */
 
/**
  Usage example:
    var $actsAs = array(
        'CounterCache' => array('method' => 'count', 'updatetimefields' => true)
    );
 
    TODO: move $this->assocs[$assoc['foreignKey']] to $this->settings[$model->name]
    TODO: another counter methodology
*/
 
class CounterCacheBehavior extends ModelBehavior {
 
    var $defaultSettings = array('method' => 'count', 'updatetimefields' => true);
 
    function setup(&$model, $config = array()) {
        $method = $this->defaultSettings['method'];
        $updatetime = $this->defaultSettings['updatetimefields'];
 
        if (!empty($config['method'])) {
            $method = $config['method'];
        }
 
        if ($config['updatetimefields'] === false || $config['updatetimefields'] === true) {
            $updatetime = $config['updatetimefields'];
        } else {
            $updatetime = true;
        }
 
        if ($method != 'count') {
            // only count for now
            $method = 'count';
        }
       
        $this->settings[$model->name] = array(
            'method' => $method,
            'updatetimefields' => $updatetime
        );
    }
 
    function afterSave(&$model) {
 
        foreach ($model->__associations as $association) {
            if (!empty($model->{$association})) {
                $model->__backAssociation[$association] = $model->{$association};
            }
        }
        foreach ($model->__backAssociation['belongsTo'] as $parent => $assoc) {
            if (!isset($model->{$parent})) {
                $parent = $assoc['className'];
            }
            if (!empty($assoc['counterCache'])) {
                $assoc['counterCache'] = $assoc['counterCache'] === true ? Inflector::underscore($model->name).'_count' : $assoc['counterCache'];
                $assoc['foreignKey'] = !empty($assoc['foreignKey']) ? $assoc['foreignKey'] : Inflector::singularize($parent).'_id';
                if ($model->{$parent}->hasField($assoc['counterCache']) && !empty($model->data[$model->name][$assoc['foreignKey']])) {
                    $foreign_id = $model->data[$model->name][$assoc['foreignKey']];
                    $conditions = !empty($assoc['counterCacheConditions']) ? $assoc['counterCacheConditions'] : '1 = 1';
                    $model->{$parent}->create();
                    $model->{$parent}->id = $foreign_id;
                    $count = intval($model->findCount("{$model->name}.{$assoc['foreignKey']} = {$foreign_id} AND {$conditions}", -1));
                    if ($this->settings[$model->name]['updatetimefields'] === true) {
                        $model->{$parent}->saveField($assoc['counterCache'], $count);
                    } else {
                        $model->data[$parent][$assoc['counterCache']] = $count;
                        $model->{$parent}->save($model->data[$parent], false, array($assoc['counterCache']));
                    }
                }
            }
        } // end foreach
 
        return true;
    }
 
    function beforeDelete(&$model) {
        foreach ($model->__associations as $association) {
            if (!empty($model->{$association})) {
                $model->__backAssociation[$association] = $model->{$association};
            }
        }
        foreach ($model->__backAssociation['belongsTo'] as $parent => $assoc) {
            if (!isset($model->{$parent})) {
                $parent = $assoc['className'];
            }
            if (!empty($assoc['counterCache'])) {
                $assoc['counterCache'] = $assoc['counterCache'] === true ? Inflector::underscore($model->name).'_count' : $assoc['counterCache'];
                $assoc['foreignKey'] = !empty($assoc['foreignKey']) ? $assoc['foreignKey'] : Inflector::singularize($parent).'_id';
                if ($model->{$parent}->hasField($assoc['counterCache'])) {
                    $associations = $model->find(array($model->primaryKey => $model->id), array("{$model->name}.{$assoc['foreignKey']}"), null, -1);
                    $this->assocs[$assoc['foreignKey']] = $associations[$model->name][$assoc['foreignKey']];
                }
            }
        }
        return true;
    }
 
    function afterDelete(&$model) {
        foreach ($model->__associations as $association) {
            if (!empty($model->{$association})) {
                $model->__backAssociation[$association] = $model->{$association};
            }
        }
        foreach ($model->__backAssociation['belongsTo'] as $parent => $assoc) {
            if (!isset($model->{$parent})) {
                $parent = $assoc['className'];
            }
            if (!empty($assoc['counterCache'])) {
                $assoc['counterCache'] = $assoc['counterCache'] === true ? Inflector::underscore($model->name).'_count' : $assoc['counterCache'];
                $assoc['foreignKey'] = !empty($assoc['foreignKey']) ? $assoc['foreignKey'] : Inflector::singularize($parent).'_id';
                $conditions = !empty($assoc['counterCacheConditions']) ? $assoc['counterCacheConditions'] : '1 = 1';
                $count = intval($model->findCount("{$model->name}.{$assoc['foreignKey']} = {$this->assocs[$assoc['foreignKey']]} AND {$conditions}", -1));
                $model->{$parent}->id = $this->assocs[$assoc['foreignKey']];
               
                if ($this->settings[$model->name]['updatetimefields'] === true) {
                    $model->{$parent}->saveField($assoc['counterCache'], $count);
                } else {
                    $model->data[$parent][$assoc['counterCache']] = $count;
                    $model->{$parent}->save($model->data[$parent], false, array($assoc['counterCache']));
                }
 
            }
        }
        return true;
    }
 
} // end class