Это можно сделать с помощью $ virtualFields :
В модель голосования добавляю следующее виртуальное поле:
var $virtualFields = array(
'vote_count' => 'IFNULL( SUM( Vote.value ) , 0 )'
);
В модели Person я получаю это каждый раз, используя следующие отношения $ hasMany:
var $hasMany = array('Vote' => array('fields' => array('vote_count')));
Обратите внимание, что по умолчанию он всегда будет извлекать каждое поле в таблице голосования, это приведет к извлечению поля SUM 'voice_count' по умолчанию и покажет только одну строку, как и ожидалось, если вы выписали запрос полностью.
Если вы хотите получить все строки и удалить виртуальное поле SUM, вам нужно указать все поля (при необходимости) в массиве полей, кроме поля 'привели к подсчету', например,
var $hasMany = array('Vote' => array('fields' => array('id', 'value')));
Я бы предположил, что это лучше контролировать, если в модели Person есть пара функций, которые позволят вам на лету решить, как вы хотите получить голоса:
function allWithVoteCounts() {
$this->bindModel(array('hasMany' =>
array('Vote' => array(
'fields' => array('vote_count')
)
)
));
return $this->find('all');
}
function allVotes() {
$this->bindModel(array('hasMany' =>
array('Vote' => array(
'fields' => array('id', 'user_id', 'person_id', 'value', 'date')
)
)
));
return $this->find('all');
}
Тогда в контроллере вы можете позвонить:
$persons = $this->Person->allVotes();
или
$persons = $this->Person->allWithVoteCounts();