You are viewing revision #3 of this wiki article.
This version may not be up to date with the latest version.
You may want to view the differences to the latest version or see the changes made in this revision.
Since Yii 1.0.5 you can use named scopes with ActiveRecords. They are a great help in simplifying your query calls.
For example, say we have a lot of tables with a CreatedAt
column containing an integer UNIX timestamp. Now we want to add a named scope called between($start,$end)
to all our ActiveRecords so that in the end we could simply use it like this:
$start=strtotime('2009-01-01');
$end=strtotime('2009-12-31');
Post::model()->between($start,$end)->findAll($someCriteria);
This should return all Posts, matching $someCriteria
but only those created between $start
and $end
.
So let's first start with the named scope. Named scopes are usually defined in a method called scope
in our ActiveRecord. Since our named scope has parameters, we need to add an explicit method instead:
public function between($start,$end)
{
$this->getDbCriteria()->mergeWith(array(
'condition'=>'CreatedAt BETWEEN :start AND :end',
'params'=>array(':start'=>$start, ':end'=>$end)
));
return $this;
}
We could add this method to an ActiveRecord and between
would be ready to use. But as we want to have this feature for all our models, we will create a behavior instead. Therefore we put the code inside a class and modify it a little:
class BetweenBehavior extends CActiveRecordBehavior
{
public function between($start,$end)
{
$this->Owner->getDbCriteria()->mergeWith(array(
'condition'=>'CreatedAt BETWEEN :start AND :end',
'params'=>array(':start'=>$start, ':end'=>$end)
));
return $this->Owner;
}
}
We should save this file as BetweenBehavior.php
and put it somewhere where our application can find it (e.g. into an imported directory). Finally we have to add our behavior to all model files. To do that, we add a method called behaviors
:
class Post extends CActiveRecord {
// ...
public function behaviors()
{
return array(
'BetweenBehavior' => array('class'=>'BetweenBehavior')
);
}
// ...
}
That's it. Our named scope is ready to use with Post
. Feel free to improve the above code or come up with your own ideas for named scopes that are good candidates for a behavior.
Same column name in multiple tables
If you use AR::with() for eager loading then you might have ambiguous column names. I solved this in the behavior using:
$ocn = get_class($this->Owner); $this->Owner->getDbCriteria()->mergeWith(array( 'condition'=>"$ocn.colName", )); return $this->Owner;
Use CActiveRecord::getTableAlias() to disambiguate column names
Just for anyone stumbling on this, don't use the class name of the owner record to differentiate relations.
Use CActiveRecord::getTableAlias():
$this->owner->dbCriteria->mergeWith(array( 'condition'=>"{$this->owner->tableAlias}.colName = :colName", 'params' =>array(':colName' =>$someValue), )); return $this->owner;
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.