Fragment caching refers to caching a fragment of a page. For example, if a page displays a summary of yearly sale in a table, we can store this table in cache to eliminate the time needed to generate it for each request.
To use fragment caching, we call CController::beginCache() and CController::endCache() in a controller's view script. The two methods mark the beginning and the end of the page content that should be cached, respectively. Like data caching, we need an ID to identify the fragment being cached.
...other HTML content... if($this->beginCache($id)) { ...content to be cached... $this->endCache(); } ...other HTML content...
In the above, if beginCache() returns
false, the cached content will be automatically inserted at the place;
otherwise, the content inside the if
-statement will be executed and be
cached when endCache() is invoked.
When calling beginCache(), we can supply an array as the second parameter consisting of caching options to customize the fragment caching. As a matter of fact, the beginCache() and endCache() methods are a convenient wrapper of the COutputCache widget. Therefore, the caching options can be initial values for any properties of COutputCache.
Perhaps the most commonly option is duration which specifies how long the content can remain valid in cache. It is similar to the expiration parameter of CCache::set(). The following code caches the content fragment for at most one hour:
...other HTML content... if($this->beginCache($id, array('duration'=>3600))) { ...content to be cached... $this->endCache(); } ...other HTML content...
If we do not set the duration, it would default to 60, meaning the cached content will be invalidated after 60 seconds.
Starting from version 1.1.8, if the duration is set 0, any existing cached content will be removed from the cache. If the duration is a negative value, the cache will be disabled, but existing cached content will remain in the cache. Prior to version 1.1.8, if the duration is 0 or negative, the cache will be disabled.
Like data caching, content fragment being cached can also have dependencies. For example, the content of a post being displayed depends on whether or not the post is modified.
To specify a dependency, we set the dependency
option, which can be either an object implementing ICacheDependency or a
configuration array that can be used to generate the dependency object. The
following code specifies the fragment content depends on the change of
lastModified
column value:
...other HTML content... if($this->beginCache($id, array('dependency'=>array( 'class'=>'system.caching.dependencies.CDbCacheDependency', 'sql'=>'SELECT MAX(lastModified) FROM Post')))) { ...content to be cached... $this->endCache(); } ...other HTML content...
Content being cached may be variated according to some parameters. For example, the personal profile may look differently to different users. To cache the profile content, we would like the cached copy to be variated according to user IDs. This essentially means that we should use different IDs when calling beginCache().
Instead of asking developers to variate the IDs according to some scheme, COutputCache is built-in with such a feature. Below is a summary.
varyByRoute: by setting this option to true, the cached content will be variated according to route. Therefore, each combination of the requested controller and action will have a separate cached content.
varyBySession: by setting this option to true, we can make the cached content to be variated according to session IDs. Therefore, each user session may see different content and they are all served from cache.
varyByParam: by setting this option to an
array of names, we can make the cached content to be variated according to
the values of the specified GET parameters. For example, if a page displays
the content of a post according to the id
GET parameter, we can specify
varyByParam to be array('id')
so that we can
cache the content for each post. Without such variation, we would only be
able to cache a single post.
varyByExpression: by setting this option to a PHP expression, we can make the cached content to be variated according to the result of this PHP expression.
Sometimes we want the fragment caching to be enabled only for certain types of request. For example, for a page displaying a form, we only want to cache the form when it is initially requested (via GET request). Any subsequent display (via POST request) of the form should not be cached because the form may contain user input. To do so, we can specify the requestTypes option:
...other HTML content... if($this->beginCache($id, array('requestTypes'=>array('GET')))) { ...content to be cached... $this->endCache(); } ...other HTML content...
Fragment caching can be nested. That is, a cached fragment is enclosed within a bigger fragment that is also cached. For example, the comments are cached in an inner fragment cache, and they are cached together with the post content in an outer fragment cache.
...other HTML content... if($this->beginCache($id1)) { ...outer content to be cached... if($this->beginCache($id2)) { ...inner content to be cached... $this->endCache(); } ...outer content to be cached... $this->endCache(); } ...other HTML content...
Different caching options can be set to the nested caches. For example, the inner cache and the outer cache in the above example can be set with different duration values. Even when the data cached in the outer cache is invalidated, the inner cache may still provide the valid inner fragment. However, it is not true vice versa. If the outer cache is evaluated to be valid, it will continue to provide the same cached copy even after the content in the inner cache has been invalidated. You must be careful in setting the durations or the dependencies of the nested caches, otherwise the outdated inner fragments may be kept in the outer fragment.
Found a typo or you think this page needs improvement?
Edit it on github !
Caching parent and child
The statement about caching parent and child can be a bit hard to understand. I know I read the phrase 4 times..
To sum it up. If your child cache expires, make sure your parent cache expires as well.
if(parent.isCached) { getCache()//your child cache is in this cache. it does not get reloaded even if it expires } on the other hand if(!parent.isCached) { createCache() //will pass through the content //-> find the child cache and if(child.isCached) getCache() else createCache() }
so if your parent expires, your child may still be cached in which case only the parent is reloaded.
if your child expires, make sure your parent expires if you want the child reloaded. or it will reload the child from the parent cache even if the child has expired.
Signup or Login in order to comment.