Commit of various live hacks
[mediawiki.git] / includes / CacheHelper.php
blob6b6a5940ff71df71dbefb8437642e68dd62120cf
1 <?php
3 /**
4 * Interface for all classes implementing CacheHelper functionality.
6 * @since 1.20
8 * @licence GNU GPL v2 or later
9 * @author Jeroen De Dauw < jeroendedauw@gmail.com >
11 interface ICacheHelper {
13 /**
14 * Sets if the cache should be enabled or not.
16 * @since 1.20
17 * @param boolean $cacheEnabled
19 function setCacheEnabled( $cacheEnabled );
21 /**
22 * Initializes the caching.
23 * Should be called before the first time anything is added via addCachedHTML.
25 * @since 1.20
27 * @param integer|null $cacheExpiry Sets the cache expiry, either ttl in seconds or unix timestamp.
28 * @param boolean|null $cacheEnabled Sets if the cache should be enabled or not.
30 function startCache( $cacheExpiry = null, $cacheEnabled = null );
32 /**
33 * Get a cached value if available or compute it if not and then cache it if possible.
34 * The provided $computeFunction is only called when the computation needs to happen
35 * and should return a result value. $args are arguments that will be passed to the
36 * compute function when called.
38 * @since 1.20
40 * @param {function} $computeFunction
41 * @param array|mixed $args
42 * @param string|null $key
44 * @return mixed
46 function getCachedValue( $computeFunction, $args = array(), $key = null );
48 /**
49 * Saves the HTML to the cache in case it got recomputed.
50 * Should be called after the last time anything is added via addCachedHTML.
52 * @since 1.20
54 function saveCache();
56 /**
57 * Sets the time to live for the cache, in seconds or a unix timestamp indicating the point of expiry..
59 * @since 1.20
61 * @param integer $cacheExpiry
63 function setExpiry( $cacheExpiry );
67 /**
68 * Helper class for caching various elements in a single cache entry.
70 * To get a cached value or compute it, use getCachedValue like this:
71 * $this->getCachedValue( $callback );
73 * To add HTML that should be cached, use addCachedHTML like this:
74 * $this->addCachedHTML( $callback );
76 * The callback function is only called when needed, so do all your expensive
77 * computations here. This function should returns the HTML to be cached.
78 * It should not add anything to the PageOutput object!
80 * Before the first addCachedHTML call, you should call $this->startCache();
81 * After adding the last HTML that should be cached, call $this->saveCache();
83 * @since 1.20
85 * @file CacheHelper.php
87 * @licence GNU GPL v2 or later
88 * @author Jeroen De Dauw < jeroendedauw@gmail.com >
90 class CacheHelper implements ICacheHelper {
92 /**
93 * The time to live for the cache, in seconds or a unix timestamp indicating the point of expiry.
95 * @since 1.20
96 * @var integer
98 protected $cacheExpiry = 3600;
101 * List of HTML chunks to be cached (if !hasCached) or that where cached (of hasCached).
102 * If not cached already, then the newly computed chunks are added here,
103 * if it as cached already, chunks are removed from this list as they are needed.
105 * @since 1.20
106 * @var array
108 protected $cachedChunks;
111 * Indicates if the to be cached content was already cached.
112 * Null if this information is not available yet.
114 * @since 1.20
115 * @var boolean|null
117 protected $hasCached = null;
120 * If the cache is enabled or not.
122 * @since 1.20
123 * @var boolean
125 protected $cacheEnabled = true;
128 * Function that gets called when initialization is done.
130 * @since 1.20
131 * @var function
133 protected $onInitHandler = false;
136 * Sets if the cache should be enabled or not.
138 * @since 1.20
139 * @param boolean $cacheEnabled
141 public function setCacheEnabled( $cacheEnabled ) {
142 $this->cacheEnabled = $cacheEnabled;
146 * Initializes the caching.
147 * Should be called before the first time anything is added via addCachedHTML.
149 * @since 1.20
151 * @param integer|null $cacheExpiry Sets the cache expiry, either ttl in seconds or unix timestamp.
152 * @param boolean|null $cacheEnabled Sets if the cache should be enabled or not.
154 public function startCache( $cacheExpiry = null, $cacheEnabled = null ) {
155 if ( is_null( $this->hasCached ) ) {
156 if ( !is_null( $cacheExpiry ) ) {
157 $this->cacheExpiry = $cacheExpiry;
160 if ( !is_null( $cacheEnabled ) ) {
161 $this->setCacheEnabled( $cacheEnabled );
164 $this->initCaching();
169 * Returns a message that notifies the user he/she is looking at
170 * a cached version of the page, including a refresh link.
172 * @since 1.20
174 * @param IContextSource $context
175 * @param boolean $includePurgeLink
177 * @return string
179 public function getCachedNotice( IContextSource $context, $includePurgeLink = true ) {
180 if ( $this->cacheExpiry < 86400 * 3650 ) {
181 $message = $context->msg(
182 'cachedspecial-viewing-cached-ttl',
183 $context->getLanguage()->formatDuration( $this->cacheExpiry )
184 )->escaped();
186 else {
187 $message = $context->msg(
188 'cachedspecial-viewing-cached-ts'
189 )->escaped();
192 if ( $includePurgeLink ) {
193 $refreshArgs = $context->getRequest()->getQueryValues();
194 unset( $refreshArgs['title'] );
195 $refreshArgs['action'] = 'purge';
197 $subPage = $context->getTitle()->getFullText();
198 $subPage = explode( '/', $subPage, 2 );
199 $subPage = count( $subPage ) > 1 ? $subPage[1] : false;
201 $message .= ' ' . Linker::link(
202 $context->getTitle( $subPage ),
203 $context->msg( 'cachedspecial-refresh-now' )->escaped(),
204 array(),
205 $refreshArgs
209 return $message;
213 * Initializes the caching if not already done so.
214 * Should be called before any of the caching functionality is used.
216 * @since 1.20
218 protected function initCaching() {
219 if ( $this->cacheEnabled && is_null( $this->hasCached ) ) {
220 $cachedChunks = wfGetCache( CACHE_ANYTHING )->get( $this->getCacheKeyString() );
222 $this->hasCached = is_array( $cachedChunks );
223 $this->cachedChunks = $this->hasCached ? $cachedChunks : array();
225 if ( $this->onInitHandler !== false ) {
226 call_user_func( $this->onInitHandler, $this->hasCached );
232 * Get a cached value if available or compute it if not and then cache it if possible.
233 * The provided $computeFunction is only called when the computation needs to happen
234 * and should return a result value. $args are arguments that will be passed to the
235 * compute function when called.
237 * @since 1.20
239 * @param {function} $computeFunction
240 * @param array|mixed $args
241 * @param string|null $key
243 * @return mixed
245 public function getCachedValue( $computeFunction, $args = array(), $key = null ) {
246 $this->initCaching();
248 if ( $this->cacheEnabled && $this->hasCached ) {
249 $value = null;
251 if ( is_null( $key ) ) {
252 $itemKey = array_keys( array_slice( $this->cachedChunks, 0, 1 ) );
253 $itemKey = array_shift( $itemKey );
255 if ( !is_integer( $itemKey ) ) {
256 wfWarn( "Attempted to get item with non-numeric key while the next item in the queue has a key ($itemKey) in " . __METHOD__ );
258 elseif ( is_null( $itemKey ) ) {
259 wfWarn( "Attempted to get an item while the queue is empty in " . __METHOD__ );
261 else {
262 $value = array_shift( $this->cachedChunks );
265 else {
266 if ( array_key_exists( $key, $this->cachedChunks ) ) {
267 $value = $this->cachedChunks[$key];
268 unset( $this->cachedChunks[$key] );
270 else {
271 wfWarn( "There is no item with key '$key' in this->cachedChunks in " . __METHOD__ );
275 else {
276 if ( !is_array( $args ) ) {
277 $args = array( $args );
280 $value = call_user_func_array( $computeFunction, $args );
282 if ( $this->cacheEnabled ) {
283 if ( is_null( $key ) ) {
284 $this->cachedChunks[] = $value;
286 else {
287 $this->cachedChunks[$key] = $value;
292 return $value;
296 * Saves the HTML to the cache in case it got recomputed.
297 * Should be called after the last time anything is added via addCachedHTML.
299 * @since 1.20
301 public function saveCache() {
302 if ( $this->cacheEnabled && $this->hasCached === false && !empty( $this->cachedChunks ) ) {
303 wfGetCache( CACHE_ANYTHING )->set( $this->getCacheKeyString(), $this->cachedChunks, $this->cacheExpiry );
308 * Sets the time to live for the cache, in seconds or a unix timestamp indicating the point of expiry..
310 * @since 1.20
312 * @param integer $cacheExpiry
314 public function setExpiry( $cacheExpiry ) {
315 $this->cacheExpiry = $cacheExpiry;
319 * Returns the cache key to use to cache this page's HTML output.
320 * Is constructed from the special page name and language code.
322 * @since 1.20
324 * @return string
326 protected function getCacheKeyString() {
327 return call_user_func_array( 'wfMemcKey', $this->cacheKey );
331 * Sets the cache key that should be used.
333 * @since 1.20
335 * @param array $cacheKey
337 public function setCacheKey( array $cacheKey ) {
338 $this->cacheKey = $cacheKey;
342 * Rebuild the content, even if it's already cached.
343 * This effectively has the same effect as purging the cache,
344 * since it will be overridden with the new value on the next request.
346 * @since 1.20
348 public function rebuildOnDemand() {
349 $this->hasCached = false;
353 * Sets a function that gets called when initialization of the cache is done.
355 * @since 1.20
357 * @param $handlerFunction
359 public function setOnInitializedHandler( $handlerFunction ) {
360 $this->onInitHandler = $handlerFunction;