Page Caching ============ Page caching refers to caching the content of a whole page. Page caching can occur at different places. For example, by choosing an appropriate page header, the client browser may cache the page being viewed for a limited time. The Web application itself can also store the page content in cache. Output Caching -------------- Page caching can be considered as a special case of [fragment caching](/doc/guide/caching.fragment). Because the content of a page is often generated by applying a layout to a view, it will not work if we simply call [beginCache()|CBaseController::beginCache] and [endCache()|CBaseController::endCache] in the layout. The reason is because the layout is applied within the [CController::render()] method AFTER the content view is evaluated. To cache a whole page, we should skip the execution of the action generating the page content. We can use [COutputCache] as an action [filter](/doc/guide/basics.controller#filter) to accomplish this task. The following code shows how we configure the cache filter: ~~~ [php] public function filters() { return array( array( 'COutputCache', 'duration'=>100, 'varyByParam'=>array('id'), ), ); } ~~~ The above filter configuration would make the filter to be applied to all actions in the controller. We may limit it to one or a few actions only by using the plus operator. More details can be found in [filter](/doc/guide/basics.controller#filter). > Tip: We can use [COutputCache] as a filter because it extends from [CFilterWidget], which means it is both a widget and a filter. In fact, the way a widget works is very similar to a filter: a widget (filter) begins before any enclosed content (action) is evaluated, and the widget (filter) ends after the enclosed content (action) is evaluated. HTTP Caching ------------ In addition to simply caching the output of an action, Yii introduced [CHttpCacheFilter] in version 1.1.11. This filter aids in setting the aforementioned headers to notify a client that a page's content has not been changed since the last request, so the server will not have to re-transmit the content. [CHttpCacheFilter] can be set up similar to [COutputCache]: ~~~ [php] public function filters() { return array( array( 'CHttpCacheFilter + index', 'lastModified'=>Yii::app()->db->createCommand("SELECT MAX(`update_time`) FROM {{post}}")->queryScalar(), ), ); } ~~~ The above code will set the `Last-Modified` header to the last date at which a post was updated. You can also use [CHttpCacheFilter::lastModifiedExpression] to set the `Last-Modified` header using a php expression. > Tip: Both, [CHttpCacheFilter::lastModifiedExpression] and [CHttpCacheFilter::lastModified] can take either an integer representing an epochal Unix timestamp or an arbitrary string representing a human-readable date. As long as later one can be parsed by [strtotime()](http://php.net/manual/function.strtotime.php), no further conversion is necessary. The "Entity Tag" (or `ETag` for short) header can be set in a similar fashion through [CHttpCacheFilter::etagSeed] and [CHttpCacheFilter::etagSeedExpression] , respectively. Both will be serialized (so you can use either a single value or an entire array) and are used to generate a quoted, base64-encoded SHA1 hash serving as content for the `ETag` header. This differs from the way the [Apache Webserver](http://httpd.apache.org) and others are generating their ETags. However, this method is perfectly in line with the RFC and turned out to be more feasible for use in a framework. > Note: In order to comply with [RFC 2616, section 13.3.4](http://tools.ietf.org/html/rfc2616#section-13.3.4), [CHttpCacheFilter] will send out `ETag` *and* `Last-Modified` headers if they can both be generated. Consequently, both will be used for cache validation if sent by the client. Since entity tags are hashes, they allow more complex and/or more precise caching strategies than `Last-Modified` headers. For instance, an ETag can be invalidated if the site has switched to another theme. > Tip: Expensive expressions for [CHttpCacheFilter::etagSeedExpression] may defeat the purpose of [CHttpCacheFilter] and introduce unnecessary overhead, since they need to be re-evaluated on every request. Try to find a simple expression that invalidates the cache if the page *content* has been modified. ### SEO Implications Search engine bots tend to respect cache headers. Since some crawlers have a limit on how many pages per domain they process within a certain time span, introducing caching headers may help indexing your site as they reduce the number of pages that need to be processed.