Я разработал следующее решение:
class BlogEntry extends AppModel
{
var $hasMany = array( 'Comment' );
function beforeFind( $queryData )
{
$this->_bindMostRecentComment();
return $queryData;
}
function _bindMostRecentComment()
{
if ( isset($this->hasOne['MostRecentComment'])) { return; }
$dbo = $this->Comment->getDatasource();
$subQuery = String::insert("`MostRecentComment`.`id` = (:q)", array(
'q'=>$dbo->buildStatement(array(
'fields' => array( String::insert(':sqInnerComment:eq.:sqid:eq', array('sq'=>$dbo->startQuote, 'eq'=>$dbo->endQuote))),
'table' => $dbo->fullTableName($this->Comment),
'alias' => 'InnerComment',
'limit' => 1,
'order' => array('InnerComment.created'=>'DESC'),
'group' => null,
'conditions' => array(
'InnerComment.blog_entry_id = BlogEntry.id'
)
), $this->Comment)
));
$this->bindModel(array('hasOne'=>array(
'MostRecentComment'=>array(
'className' => 'Comment',
'conditions' => array( $subQuery )
)
)),false);
return;
}
// Other model stuff
}
Понятие простое. Метод _bindMostRecentComment
определяет довольно стандартную ассоциацию has-one, используя подзапрос в условиях ассоциации, чтобы гарантировать, что только самые последние комментарии будут присоединены к запросам BlogEntry. Сам метод вызывается непосредственно перед любыми Model::find()
вызовами, MostRecentComment каждого BlogEntry может быть отфильтрован или отсортирован по.
Я понимаю, что можно определить эту ассоциацию в члене класса hasOne
, но мне пришлось бы написать несколько необработанных SQL, что заставляет меня задуматься.
Я бы предпочел вызвать _bindMostRecentComment
из конструктора BlogEntry, но параметр Model :: bindModel (), который (согласно документации) делает перманент привязки, похоже, не работает, поэтому привязка должна быть сделано в обратном вызове beforeFind.