I’ve been migrating from Yii1 to Yii2. One feature that I’ve been using in the Yii1 is parameterized scope and criteria merging.
For example I have a book with a field authorId, a flag isRemoved (I really hate deleting rows from database, I just like flagging it), and status whether a book is in the shelf or not.
/**
* @property authorId
* @property isRemoved
* @property status
*/
class Book extends CActiveRecord {
const STATUS_IS_NOT_REMOVED = 0;
const STATUS_IS_IN_SHELF = 0;
const STATUS_IS_BORROWED = 1;
const SCOPE_FILTER_WHERE_IS_NOT_REMOVED = 'scopeIsNotRemoved';
const SCOPE_FILTER_WHERE_IS_BORROWED = 'scopeIsBorrowed';
const SCOPE_FILTER_BY_AUTHOR_ID = 'scopeFilterByAuthorId';
public function scopes(){
$t = $this->tableAlias(); //avoid when used in the JOIN
return [
self::SCOPE_FILTER_WHERE_IS_NOT_REMOVED => [
'condition' => "`{$t}`.`isRemoved` = :notremoved",
'params' => [
':notremoved' => self::STATUS_IS_NOT_REMOVED,
]
],
self::SCOPE_FILTER_WHERE_IS_BORROWED => [
'condition' => "`{$t}`.`status` = :borrowed",
'params' => [
':borrowed' => self::STATUS_IS_BORROWED,
]
],
];
}
public function scopeFilterByAuthorId($authorId){
$t = $this->tableAlias();
$this->getCriteria()->mergeWith([
'condition' => "`{$t}`.`authorId` = :authorId",
'params' => [
':authorId' => $authorId
]
]);
return $this;
}
}
So let’s say I have a controller that display list of books that can be parameterized by $_GET params. The code above will be so useful.
public function actionIndex($showBorrowed = null, $authorId = null){
$criteria = new CDbCriteria([
'scopes' => [
Book::SCOPE_FILTER_WHERE_IS_NOT_REMOVED,
]
]);
if (!empty($showBorrowed)){
$criteria->mergeWith(new CDbCriteria([
'scopes' => [
Book::SCOPE_FILTER_WHERE_IS_NOT_BORROWED,
]
]));
}
if (!empty($authorId)){
$criteria->mergeWith(new CDbCriteria([
'scopes' => [
Book::SCOPE_FILTER_BY_AUTHOR_ID => [$authorId],
]
]));
}
$dataProvider = new CActiveDataProvider(Book::model(), [
'criteria' => $criteria,
]);
$this->render('index', [
'dataProvider' => $dataProvider
]);
}
or maybe in other controller for author panel, I can do this to show books from current logged user (i.e. the author herself).
public function actionIndex(){
$criteria = new CDbCriteria([
'scopes' => [
Book::SCOPE_FILTER_WHERE_IS_NOT_REMOVED,
Book::SCOPE_FILTER_BY_AUTHOR_ID => [Yii::app()->user->id],
]
]);
$dataProvider = new CActiveDataProvider(Book::model(), [
'criteria' => $criteria,
]);
$this->render('index', [
'dataProvider' => $dataProvider
]);
}
Using the scope and parameterized scope, I can do this really easy. And in addition by declaring scope as const, it’s really easy using IDE autocompletion.
Is there any way to do this in Yii2?