Странное поведение кеширования в CActiveRecord

в 23:07, , рубрики: cactiverecord, yii, yii framework, метки: , ,

Или повесть о том, как можно нечаянно выстрелить себе в ногу.

Исходные данные

Сижу себе отлаживаю код, который затрагивает кеширование CActiveRecord.
Последовательность:

  • Создаем модель
  • Задаем условия кеширования
  • Создаем CActiveDataProvider
  • Используем его при выводе CGridView

Часть кода № 1, контроллер:

public function actions(){
        return array(
            'list' => array(
                'view' => 'list',
                'class' => 'appcomponentsactionsGridAction',
                'columns' => array(
                    'display_name',
                    'email',
                    array(
                        'name' => 'role',
                        'filter' => array(
                            User::ROLE_ADMIN => Yii::t('admin','Administrator'),
                            User::ROLE_MANAGER => Yii::t('admin','Manager'),
                            User::ROLE_USER => Yii::t('admin','User')
                        )
                    )
                ),
                'beforeRender' => function() {
                    $this->breadcrumbs[] = Yii::t('admin', 'Manage users');
                },
                'model' => function(){
                    $model = new User('search');
                    return $model->cache(new Tags('users'));
                }
            );
}

Часть кода № 2, экшн:

ApplicationHelpers::loadData($this->model);

$provider = $this->model->search();
$filter = $this->model;

$grid = $this->controller->createWidget('appwidgetsgridGridView',array(
            'dataProvider' => $provider,
            'columns' => !empty($this->columns)?$this->columns:array(),
            'id' => ApplicationHelpers::safeHtmlName($this->controller)."_{$this->id}_grid",
            'filter' => $filter
));

Грид вывелся, смотрю лог:

Querying SQL: SELECT * FROM `tbl_user` `t` LIMIT 50
in
protected/widgets/grid/GridView.php
(18)
in
protected/components/actions/GridAction.php
(34)
in admin.php (18)

кешированием и не пахнет.
Параметры кеширования сохраняются внутри CActiveRecord в public static $db; и слетают после того, как инициализируется CActiveDataProvider в $this->model->search(). «Вот чудеса», недоумеваю я.
После пары минут дебага вспоминаю, что у меня к CActiveDataProvider привязан behavior.
Вот такой:

namespace appcomponentsbehaviors;

class AutoPagingBehavior extends CBehavior{
    public function attach($owner)
    {
        parent::attach($owner);

        $pageSize = Yii::app()->params['defaultPageSize'];

        if(isset($owner->id)){
            $pageSize = Yii::app()->user->getState('pagesize_'.$owner->id,Yii::app()->params['defaultPageSize']);
        }

        if($requestPageSize = Yii::app()->request->getParam('pagesize',false)){
            if(is_array($requestPageSize) && isset($requestPageSize[$owner->id])){
                $pageSize = $requestPageSize[$owner->id];
                Yii::app()->user->setState("pagesize_{$owner->id}",$pageSize);
            }else{
                $_GET['pagesize'] = [$owner->id => $pageSize];
            }
        }

        $owner->pagination->setPageSize($pageSize);
        if($pageSize == 'all')
            $owner->pagination = false;
    }

}

Дебаггер усиленно рапортует, что параметры кеширования слетают после Yii::app()->user->getState.
Смотрим наш WebUser.php, а там:

public function init(){
    parent::init();
    if(!$this->isGuest){
        $this->model = User::model()->findByEmail($this->id);
        if(empty($this->model)){
            $this->logout(true);
            Yii::app()->controller->redirect('/');
        }
    }
}

Вызов User::model()->findByEmail($this->id) это хелпер, в котором запускается кешированный поиск. И этот поиск благополучно перезаписывает параметры кеширования в public static $db, который в CActiveRecord.

Вывод

Получается, что в промежутке между заданием параметров кеширования для поиска и самим поиском через CActiveDataProvider нельзя выполнять другие кешированные вызовы любой модели, потому что CDbConnection один на всех. Путь исправления такого поведения очевиден — сохранять параметры кеширования непосредственно в экземпляре CActiveRecord и применять в момент выполнения запроса (CActiveRecord#query)

Итог

Странное поведение кеширования в CActiveRecord

Автор: AMar4enko

Источник

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


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