hi,
let’s assume we have a forum web application with a Thread model that HAS_MANY posts, and a post can be published or unpublished according to publish_status column (1=published)
for most users they should only see published, and in some rare cases we might want to display even unpublished (eg. admin)
we faced the case of many developers forget to check for publish status,
and we want to force that.
we thought about using a scoops like the sample code in reference (Post::model()->published()->findAll()
but in our case we are in the middle of relation (I’m not sure if getTableAlias would work in an early stage as the scope)
Our case looks like this
Thread::model()->with(‘posts’)->publishedPosts()->findByPk($thread_id);
or
Thread::model()->publishedPosts()->with(‘posts’)->findByPk($thread_id);
I thought about a solution, I call it subrelation, it used like this
$thread=Thread::model()->with(‘all_posts’)->findByPk($thread_id);
$thread->posts // will be publish posts only
the code is like this
// in models/Thread.php
public function relations()
{
return array(
'posts' => array(self::HAS_MANY, 'ThreadPost', 'thread_id', 'on'=>'posts.publish_status=1'),
'all_posts' => array(self::HAS_MANY, 'ThreadPost', 'thread_id'),
);
}
public function subrelations() {
return array('posts'=>array('all_posts', 'publishedFilter'));
}
protected static function publishedFilter($superset) {
$subset=array();
foreach($superset as $e) {
if ($e->publish_status==1) $subset[]=$e;
}
return $subset;
}
public function getRelated($name, $refresh=false, $params=array()) {
$sub=$this->subrelations();
if (!$refresh && isset($sub[$name])) {
list($other_name,$filter)=$sub[$name];
if($this->hasRelated($other_name))
return $this->_related[$name]=call_user_func(array(get_class($this),$filter), $this->_related[$other_name]);
}
return parent::getRelated($name, $refresh, $params);
}