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.

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.

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:

If we do not set the duration, it would default to 60, meaning the cached
content will be invalidated after 60 seconds.

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:

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. This option has been available since
version 1.0.4.

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:

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.

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. When the data cached in the outer cache is
invalidated, the inner cache may still provide valid inner fragment.
However, it is not true vice versa. If the outer cache contains valid data,
it will always provide the cached copy, even though the content in the
inner cache already expires.