手動によるカウンターキャッシュの更新
counterCacheは便利だが、どうやら1モデルにつき1つしか登録できないようだ。
たとえばUserモデルとFriendモデルがあるとする。
Userモデルにはfriend_countフィールドがあり、Friendの数がカウンターキャッシュで更新できるようにする場合、Friendモデルには下記のような記述をする
var $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => '',
'counterCache' => 'friend_count',
'counterScope' => array('Friend.status' => 1),
),
);
単純に友達の数をカウントするだけならこれでいいが、さらに「特に親しい友達の数もカウントしたい」というような要望がある場合は別処理でカウントする必要がある(と思う)。
試しに次のように配列で入れてみたが、結果は上手くうごかなかった。
(Friendモデルにis_favoriteというフィールドを設け、このis_favoriteが1の要素の合計数を、Userモデルのfriend_favorite_countというフィールドに入れたいとする)
var $belongsTo = array(
'User' => array(
array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => '',
'counterCache' => 'friend_count',
'counterScope' => array('Friend.status' => 1),
),
array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => '',
'counterCache' => 'friend_favorite_count',
'counterScope' => array('Friend.status' => 1, 'Friend.is_favorite' => 1),
),
),
);
で、結局friend_favorite_countの方は、別に処理を書いて更新させることにする。
Friend.php
var $actsAs = array('CounterCache');
var $_del_user_id;
function afterSave ($created) {
// 新規登録時
if ($created) {
$this->id = $this->getLastInsertId();
}
$user_id = $this->Field('user_id');
$this->_updateFavoriteCount($user_id);
}
function beforeDelete () {
$this->_del_user_id = $this->Field('user_id');
return true;
}
function afterDelete () {
if ($this->_del_user_id) {
$this->_updateFavoriteCount($this->_del_user_id);
return true;
}
}
function _updateFavoriteCount($user_id = null) {
if (is_null($user_id)) return false;
$count = $this->find('count', array('conditions' => array('Friend.user_id' => $user_id, 'Friend.favorite' => 1, 'Friend.status' => 1)));
App::import('Model', 'User');
$User= new User();
$User->id = $user_id;
if ($User->saveField('friend_favorite_count', $count)) {
return true;
}
return false;
}
