4 * Abstract special page class with scaffolding for caching the HTML output.
6 * To enable the caching functionality, the cacheExpiry field should be set
9 * To add HTML that should be cached, use addCachedHTML like this:
10 * $this->addCachedHTML( array( $this, 'displayCachedContent' ) );
12 * After adding the last HTML that should be cached, call $this->saveCache();
16 * @file SpecialCachedPage.php
17 * @ingroup SpecialPage
19 * @licence GNU GPL v2 or later
20 * @author Jeroen De Dauw < jeroendedauw@gmail.com >
22 abstract class SpecialCachedPage
extends SpecialPage
{
25 * The time to live for the cache, in seconds or a unix timestamp indicating the point of expiry.
30 protected $cacheExpiry = null;
33 * List of HTML chunks to be cached (if !hasCached) or that where cashed (of hasCached).
34 * If no cached already, then the newly computed chunks are added here,
35 * if it as cached already, chunks are removed from this list as they are needed.
40 protected $cachedChunks;
43 * Indicates if the to be cached content was already cached.
44 * Null if this information is not available yet.
49 protected $hasCached = null;
56 * @param string|null $subPage
58 public function execute( $subPage ) {
59 if ( $this->getRequest()->getText( 'action' ) === 'purge' ) {
60 $this->hasCached
= false;
63 if ( !is_null( $this->cacheExpiry
) ) {
66 if ( $this->hasCached
=== true ) {
67 $this->getOutput()->setSubtitle( $this->getCachedNotice( $subPage ) );
73 * Returns a message that notifies the user he/she is looking at
74 * a cached version of the page, including a refresh link.
78 * @param string|null $subPage
82 protected function getCachedNotice( $subPage ) {
83 $refreshArgs = $this->getRequest()->getQueryValues();
84 unset( $refreshArgs['title'] );
85 $refreshArgs['action'] = 'purge';
87 $refreshLink = Linker
::link(
88 $this->getTitle( $subPage ),
89 $this->msg( 'cachedspecial-refresh-now' )->escaped(),
94 if ( $this->cacheExpiry
< 1000000000 ) {
95 $message = $this->msg(
96 'cachedspecial-viewing-cached-ttl',
97 $this->getLanguage()->formatDuration( $this->cacheExpiry
)
101 $message = $this->msg(
102 'cachedspecial-viewing-cached-ts'
106 return $message . ' ' . $refreshLink;
110 * Initializes the caching if not already done so.
111 * Should be called before any of the caching functionality is used.
115 protected function initCaching() {
116 if ( is_null( $this->hasCached
) ) {
117 $cachedChunks = wfGetCache( CACHE_ANYTHING
)->get( $this->getCacheKey() );
119 $this->hasCached
= is_array( $cachedChunks );
120 $this->cachedChunks
= $this->hasCached ?
$cachedChunks : array();
125 * Add some HTML to be cached.
126 * This is done by providing a callback function that should
127 * return the HTML to be added. It will only be called if the
128 * item is not in the cache yet or when the cache has been invalidated.
132 * @param {function} $callback
134 * @param string|null $key
136 public function addCachedHTML( $callback, $args = array(), $key = null ) {
137 $this->initCaching();
139 if ( $this->hasCached
) {
142 if ( is_null( $key ) ) {
143 $itemKey = array_keys( array_slice( $this->cachedChunks
, 0, 1 ) );
144 $itemKey = array_shift( $itemKey );
146 if ( !is_integer( $itemKey ) ) {
147 wfWarn( "Attempted to get item with non-numeric key while the next item in the queue has a key ($itemKey) in " . __METHOD__
);
149 elseif ( is_null( $itemKey ) ) {
150 wfWarn( "Attempted to get an item while the queue is empty in " . __METHOD__
);
153 $html = array_shift( $this->cachedChunks
);
157 if ( array_key_exists( $key, $this->cachedChunks
) ) {
158 $html = $this->cachedChunks
[$key];
159 unset( $this->cachedChunks
[$key] );
162 wfWarn( "There is no item with key '$key' in this->cachedChunks in " . __METHOD__
);
167 $html = call_user_func_array( $callback, $args );
169 if ( is_null( $key ) ) {
170 $this->cachedChunks
[] = $html;
173 $this->cachedChunks
[$key] = $html;
177 $this->getOutput()->addHTML( $html );
181 * Saves the HTML to the cache in case it got recomputed.
182 * Should be called after the last time anything is added via addCachedHTML.
186 public function saveCache() {
187 if ( $this->hasCached
=== false && !empty( $this->cachedChunks
) ) {
188 wfGetCache( CACHE_ANYTHING
)->set( $this->getCacheKey(), $this->cachedChunks
, $this->cacheExpiry
);
193 * Sets the time to live for the cache, in seconds or a unix timestamp indicating the point of expiry..
197 * @param integer $cacheExpiry
199 protected function setExpirey( $cacheExpiry ) {
200 $this->cacheExpiry
= $cacheExpiry;
204 * Returns the cache key to use to cache this page's HTML output.
205 * Is constructed from the special page name and language code.
211 protected function getCacheKey() {
212 return wfMemcKey( $this->mName
, $this->getLanguage()->getCode() );