Как правильно кешировать

Появились непонятки с кешированием.

Возьмем пример с блогом. Есть PostController.php, модель Post.php, вьюшка show.php.

Например, мы хотим вывести страницу с постом.

В PostController.php в actionShow() делаем:




public function actionShow()

{

     ...

     $post = Post::model()->with('categories', '... something other ...')->together()->findByPk($_GET['id']);

     ...

     $this->render('show', array(

	 'model'=>$post,

     ));

}



Соответственно при выполнении вот этого выражения:

Post::model()->with(‘categories’, ‘… something other …’)->together()->findByPk($_GET[‘id’]);

тут же выполняется SQL запрос.

Хотелось бы во вьюшке show.php вставить кеширование:




<?php if($this->beginCache('chache-posts', array('duration'=>123456, 'varyByParam'=>array('id')) { ?>


<h1><?php echo $model->title; ?></h1>


<?php echo $model->text; ?>


<?php $this->endCache(); } ?>



Но т.к. SQL запрос на выборку данный и формирование этих данных уже выполнено в actionShow() в контроллере, то кеширование тут как бы и не помогает. Хочется кешировать именно уже финальный кусок html кода, а не саму модель, т.е. делать кеширование уже во вьюшке и не выполнять лишних запросов к БД.

Т.е. получается, что мне нужна ленивая загрузка модели. Если мы ее берем из кеша, то ничего делать не нужно, если формируем кеш, то загружаем модель.

Подскажите, как правильно кешировать и избежать описанных выше проблем? Как правильно сделать отложенную (ленивую) загрузку данных, чтобы выполнять запросы к БД и формирование данных только по требованию?

Нужно делать запрос внутри кэшируемого блока. Если логика сложна, то можно сделать отдельный метод в контроллере, возвращающий необходимые данные.

Конечно может возникнуть желание вынести проверку, нужно ли получать данные, в контроллер, но с реализацией возникнет много проблем.

А что мешает закешировать весь код внутри actionShow контроллера вместе с куском кода, получающим данные? Т.е. ту же конструкцию для кеша использовать не в отображении а в контролере?

Или это "против религии"?


public function actionShow()

{

     ...

if($this->beginCache('chache-posts', array('duration'=>123456, 'varyByParam'=>array('id')) {

     $post = Post::model()->with('categories', '... something other ...')->together()->findByPk($_GET['id']);

     ...

     $this->render('show', array(

         'model'=>$post,

     ));

$this->endCache(); }

}

Может быть покажете пример? :)

"Пример" чуть выше. Малоприменим так как в кеш поидее попадает всё вместе с лайоутом.

Вы правы, это не решение.

Возвращаясь к проблеме топикстартера.

mcast,

правильнее всего максимально упростить запрос получения поста. Такой запрос по первичному ключу должен всегда выполняться быстро.


$post = Post::model()->findByPk($_GET['id']);

В отображении использовать связанные поля, которые "лениво подгрузятся при первом обращении"


<?php echo $model->categories->name; ?>

Кешировать отображение как вы и предлагали.

В таком случае нужно использовать кэширование целой страницы с помощью фильтра, как описано в гайде: http://www.yiiframework.com/doc/guide/ru/caching.page

Тут, конечно, уже не будет проблем, описанных выше, т.к. код экшена выполняться вообще не будет.

а может все же кэшировать сам объект ? без вьюх и лайоутов?

http://www.yiiframework.com/doc/guide/caching.data

Пусть автор темы сам выбирает, что ему нужно кэшировать :)

Но я не вижу здесь смысла кэшировать объекты. Лучше вытащить из кэша сразу всю ранее сгенерированную страницу или её часть.