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?