Caching the block - how?

Consider I want to cache left menu, that is built using quite expensive queries. How should I do that?

I see the following approach:

  1. Use CDbCache (what tables should be there in the DB for that?)

  2. in the controller I query DB and build associative array for the menu

  3. I pass it to view

  4. use caching for the fragment:

<?php if($this->beginCache($id, array('duration'=>3600))) 


$this->beginWidget('CTreeView', array('data' => $data));

$this->endCache(); } ?>

Everything is fine, but DB queries are not chaced - they will be excecuted anyway.

Sure, I can use data caching for queries and fragment caching for the CTreeView… But is there more intelligent way?

First you should use $this->widget instead of $this->beginWidget for CTreeView because it doesn't need body content.

Because you mainly want to save the time generating $data, you can write a getter method for it in the controller. Calling this getter method will be expensive, but because it is called inside the fragment cache, it will only be called when the cache is invalidated.

great! thanks!

How can I refer to controller object from the view context?

Use $this. $this always refers to the controller object, unless the view belongs to a widget. In that case, $this refers to the widget object. Accessing data via $this is known as pull, while your earlier approach is push.

Hmm, so to leverage the view cache appropriately, we have to change the way we initialize $data objects in view files? The standard way seems to be initializing $data vars in controllers, and then passing it to the view file.

But now, we have to setup getter methods for each piece of data, then calling it in view file? Is this the best way?

Also, is it possible to set multiple cache types in the configuration or programmatically?

For example, I want to use MemCache for data caching in controllers with Yii::app()->cache()

and then FileCache for caching view files with $this->beginCache

Both ways of supplying data are fine. One is called push, the other pull. Defining getters is a bit more troublesome, but it has the benefit of "laziness".

You can declare different cache application components in app config, and then specify the ID of the cache component to be used in a particular COutputCache.