Исходные данные
Сижу себе отлаживаю код, который затрагивает кеширование 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/
Добавить комментарий