Fragment Caching

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...
<?php if($this->beginCache($id)) { ?>
...content to be cached...
<?php $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.

1. Caching Options

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.

Duration

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...
<?php if($this->beginCache($id, array('duration'=>3600))) { ?>
...content to be cached...
<?php $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.

Dependency

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...
<?php if($this->beginCache($id, array('dependency'=>array(
        'class'=>'system.caching.dependencies.CDbCacheDependency',
        'sql'=>'SELECT MAX(lastModified) FROM Post')))) { ?>
...content to be cached...
<?php $this->endCache(); } ?>
...other HTML content...

Variation

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.

Request Types

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...
<?php if($this->beginCache($id, array('requestTypes'=>array('GET')))) { ?>
...content to be cached...
<?php $this->endCache(); } ?>
...other HTML content...

2. Nested Caching

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...
<?php if($this->beginCache($id1)) { ?>
...outer content to be cached...
    <?php if($this->beginCache($id2)) { ?>
    ...inner content to be cached...
    <?php $this->endCache(); } ?>
...outer content to be cached...
<?php $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.

$Id$

Total 1 comment

#5654 report it
alinmircea at 2011/10/28 06:11pm
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.

Leave a comment

Please to leave your comment.