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

от автора

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

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

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

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

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

public function actions(){         return array(             'list' => array(                 'view' => 'list',                 'class' => 'app\components\actions\GridAction',                 '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('app\widgets\grid\GridView',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 app\components\behaviors;  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)

Итог

ссылка на оригинал статьи http://habrahabr.ru/post/185842/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *