Как правильно задать в Yii2 default scope

в 15:45, , рубрики: Песочница, метки: , , ,

Yii2 зарелизился не так давно, и пока документация не полная, а рецепты в интернете не всегда верные, приходится через страдания разбираться в фрэймворке.

Проблема default scope в Yii2 существует уже больше года, еще с того времени, как Yii2 был в бета версии. Соответственно при поиске нас кидает на различные обсуждения, среди которых преобладает кривое решение. Этот пост должен решить данную проблему.

Решение, которое преобладает, выглядит так:

<Не используйте этот код>

namespace appcomponents;

class ActiveRecord extends yiidbActiveRecord
{
    public static function find()
    {
        return parent::find()->andWhere(['active' => 1]);
    }
}

</Не используйте этот код>

То-есть добавляем условие прямо в метод.

Но при наследовании нас ждут проблемы, если мы заходим добавить обычный scope или default scope.

Пример добавления scope из документации:

namespace appmodels;

use yiidbActiveRecord;
use yiidbActiveQuery;

class Comment extends ActiveRecord
{
    public static function find()
    {
        return new CommentQuery(get_called_class());
    }
}

class CommentQuery extends ActiveQuery
{
    public function active($state = true)
    {
        return $this->andWhere(['active' => $state]);
    }
}

Метод find наследуемого ActiveRecord будет затерт. И, к сожалению, именно это решение находится в поиске и ведет на гитхаб yii2.

Верное решение для default scope

Нужно создать свой ActiveQuery, и возвращать его в методе find. Так-же в этом ActiveQuery можно прописывать другие scopes, как это описано в мануале.

namespace appcomponents;

class ActiveRecord extends yiidbActiveRecord
{
    public static function find()
    {
        return new ActiveQuery(get_called_class());
    }
}

namespace appcomponents;

class ActiveQuery extends yiidbActiveQuery
{
    public function init()
    {
        parent::init();
        $modelClass = $this->modelClass;
        $tableName = $modelClass::tableName();
        $this->andWhere(['active' => 1]);
    }

} 

Если мы заходим в модели отнаследовать ActiveRecord, мы будем иметь доступ ко всем scopes, а если захотим добавить еще default scope или обычные scopes, просто нужно наследоваться от нашего ActiveQuery.

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js