[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/cache/ -> CacheHelper.php (source)

   1  <?php
   2  /**
   3   * Cache of various elements in a single cache entry.
   4   *
   5   * This program is free software; you can redistribute it and/or modify
   6   * it under the terms of the GNU General Public License as published by
   7   * the Free Software Foundation; either version 2 of the License, or
   8   * (at your option) any later version.
   9   *
  10   * This program is distributed in the hope that it will be useful,
  11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13   * GNU General Public License for more details.
  14   *
  15   * You should have received a copy of the GNU General Public License along
  16   * with this program; if not, write to the Free Software Foundation, Inc.,
  17   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18   * http://www.gnu.org/copyleft/gpl.html
  19   *
  20   * @file
  21   * @license GNU GPL v2 or later
  22   * @author Jeroen De Dauw < [email protected] >
  23   */
  24  
  25  /**
  26   * Interface for all classes implementing CacheHelper functionality.
  27   *
  28   * @since 1.20
  29   */
  30  interface ICacheHelper {
  31      /**
  32       * Sets if the cache should be enabled or not.
  33       *
  34       * @since 1.20
  35       * @param bool $cacheEnabled
  36       */
  37  	function setCacheEnabled( $cacheEnabled );
  38  
  39      /**
  40       * Initializes the caching.
  41       * Should be called before the first time anything is added via addCachedHTML.
  42       *
  43       * @since 1.20
  44       *
  45       * @param int|null $cacheExpiry Sets the cache expiry, either ttl in seconds or unix timestamp.
  46       * @param bool|null $cacheEnabled Sets if the cache should be enabled or not.
  47       */
  48  	function startCache( $cacheExpiry = null, $cacheEnabled = null );
  49  
  50      /**
  51       * Get a cached value if available or compute it if not and then cache it if possible.
  52       * The provided $computeFunction is only called when the computation needs to happen
  53       * and should return a result value. $args are arguments that will be passed to the
  54       * compute function when called.
  55       *
  56       * @since 1.20
  57       *
  58       * @param callable $computeFunction
  59       * @param array|mixed $args
  60       * @param string|null $key
  61       *
  62       * @return mixed
  63       */
  64  	function getCachedValue( $computeFunction, $args = array(), $key = null );
  65  
  66      /**
  67       * Saves the HTML to the cache in case it got recomputed.
  68       * Should be called after the last time anything is added via addCachedHTML.
  69       *
  70       * @since 1.20
  71       */
  72  	function saveCache();
  73  
  74      /**
  75       * Sets the time to live for the cache, in seconds or a unix timestamp
  76       * indicating the point of expiry...
  77       *
  78       * @since 1.20
  79       *
  80       * @param int $cacheExpiry
  81       */
  82  	function setExpiry( $cacheExpiry );
  83  }
  84  
  85  /**
  86   * Helper class for caching various elements in a single cache entry.
  87   *
  88   * To get a cached value or compute it, use getCachedValue like this:
  89   * $this->getCachedValue( $callback );
  90   *
  91   * To add HTML that should be cached, use addCachedHTML like this:
  92   * $this->addCachedHTML( $callback );
  93   *
  94   * The callback function is only called when needed, so do all your expensive
  95   * computations here. This function should returns the HTML to be cached.
  96   * It should not add anything to the PageOutput object!
  97   *
  98   * Before the first addCachedHTML call, you should call $this->startCache();
  99   * After adding the last HTML that should be cached, call $this->saveCache();
 100   *
 101   * @since 1.20
 102   */
 103  class CacheHelper implements ICacheHelper {
 104      /**
 105       * The time to live for the cache, in seconds or a unix timestamp indicating the point of expiry.
 106       *
 107       * @since 1.20
 108       * @var int
 109       */
 110      protected $cacheExpiry = 3600;
 111  
 112      /**
 113       * List of HTML chunks to be cached (if !hasCached) or that where cached (of hasCached).
 114       * If not cached already, then the newly computed chunks are added here,
 115       * if it as cached already, chunks are removed from this list as they are needed.
 116       *
 117       * @since 1.20
 118       * @var array
 119       */
 120      protected $cachedChunks;
 121  
 122      /**
 123       * Indicates if the to be cached content was already cached.
 124       * Null if this information is not available yet.
 125       *
 126       * @since 1.20
 127       * @var bool|null
 128       */
 129      protected $hasCached = null;
 130  
 131      /**
 132       * If the cache is enabled or not.
 133       *
 134       * @since 1.20
 135       * @var bool
 136       */
 137      protected $cacheEnabled = true;
 138  
 139      /**
 140       * Function that gets called when initialization is done.
 141       *
 142       * @since 1.20
 143       * @var callable
 144       */
 145      protected $onInitHandler = false;
 146  
 147      /**
 148       * Elements to build a cache key with.
 149       *
 150       * @since 1.20
 151       * @var array
 152       */
 153      protected $cacheKey = array();
 154  
 155      /**
 156       * Sets if the cache should be enabled or not.
 157       *
 158       * @since 1.20
 159       * @param bool $cacheEnabled
 160       */
 161  	public function setCacheEnabled( $cacheEnabled ) {
 162          $this->cacheEnabled = $cacheEnabled;
 163      }
 164  
 165      /**
 166       * Initializes the caching.
 167       * Should be called before the first time anything is added via addCachedHTML.
 168       *
 169       * @since 1.20
 170       *
 171       * @param int|null $cacheExpiry Sets the cache expiry, either ttl in seconds or unix timestamp.
 172       * @param bool|null $cacheEnabled Sets if the cache should be enabled or not.
 173       */
 174  	public function startCache( $cacheExpiry = null, $cacheEnabled = null ) {
 175          if ( is_null( $this->hasCached ) ) {
 176              if ( !is_null( $cacheExpiry ) ) {
 177                  $this->cacheExpiry = $cacheExpiry;
 178              }
 179  
 180              if ( !is_null( $cacheEnabled ) ) {
 181                  $this->setCacheEnabled( $cacheEnabled );
 182              }
 183  
 184              $this->initCaching();
 185          }
 186      }
 187  
 188      /**
 189       * Returns a message that notifies the user he/she is looking at
 190       * a cached version of the page, including a refresh link.
 191       *
 192       * @since 1.20
 193       *
 194       * @param IContextSource $context
 195       * @param bool $includePurgeLink
 196       *
 197       * @return string
 198       */
 199  	public function getCachedNotice( IContextSource $context, $includePurgeLink = true ) {
 200          if ( $this->cacheExpiry < 86400 * 3650 ) {
 201              $message = $context->msg(
 202                  'cachedspecial-viewing-cached-ttl',
 203                  $context->getLanguage()->formatDuration( $this->cacheExpiry )
 204              )->escaped();
 205          } else {
 206              $message = $context->msg(
 207                  'cachedspecial-viewing-cached-ts'
 208              )->escaped();
 209          }
 210  
 211          if ( $includePurgeLink ) {
 212              $refreshArgs = $context->getRequest()->getQueryValues();
 213              unset( $refreshArgs['title'] );
 214              $refreshArgs['action'] = 'purge';
 215  
 216              $subPage = $context->getTitle()->getFullText();
 217              $subPage = explode( '/', $subPage, 2 );
 218              $subPage = count( $subPage ) > 1 ? $subPage[1] : false;
 219  
 220              $message .= ' ' . Linker::link(
 221                  $context->getTitle( $subPage ),
 222                  $context->msg( 'cachedspecial-refresh-now' )->escaped(),
 223                  array(),
 224                  $refreshArgs
 225              );
 226          }
 227  
 228          return $message;
 229      }
 230  
 231      /**
 232       * Initializes the caching if not already done so.
 233       * Should be called before any of the caching functionality is used.
 234       *
 235       * @since 1.20
 236       */
 237  	protected function initCaching() {
 238          if ( $this->cacheEnabled && is_null( $this->hasCached ) ) {
 239              $cachedChunks = wfGetCache( CACHE_ANYTHING )->get( $this->getCacheKeyString() );
 240  
 241              $this->hasCached = is_array( $cachedChunks );
 242              $this->cachedChunks = $this->hasCached ? $cachedChunks : array();
 243  
 244              if ( $this->onInitHandler !== false ) {
 245                  call_user_func( $this->onInitHandler, $this->hasCached );
 246              }
 247          }
 248      }
 249  
 250      /**
 251       * Get a cached value if available or compute it if not and then cache it if possible.
 252       * The provided $computeFunction is only called when the computation needs to happen
 253       * and should return a result value. $args are arguments that will be passed to the
 254       * compute function when called.
 255       *
 256       * @since 1.20
 257       *
 258       * @param callable $computeFunction
 259       * @param array|mixed $args
 260       * @param string|null $key
 261       *
 262       * @return mixed
 263       */
 264  	public function getCachedValue( $computeFunction, $args = array(), $key = null ) {
 265          $this->initCaching();
 266  
 267          if ( $this->cacheEnabled && $this->hasCached ) {
 268              $value = null;
 269  
 270              if ( is_null( $key ) ) {
 271                  $itemKey = array_keys( array_slice( $this->cachedChunks, 0, 1 ) );
 272                  $itemKey = array_shift( $itemKey );
 273  
 274                  if ( !is_integer( $itemKey ) ) {
 275                      wfWarn( "Attempted to get item with non-numeric key while " .
 276                          "the next item in the queue has a key ($itemKey) in " . __METHOD__ );
 277                  } elseif ( is_null( $itemKey ) ) {
 278                      wfWarn( "Attempted to get an item while the queue is empty in " . __METHOD__ );
 279                  } else {
 280                      $value = array_shift( $this->cachedChunks );
 281                  }
 282              } else {
 283                  if ( array_key_exists( $key, $this->cachedChunks ) ) {
 284                      $value = $this->cachedChunks[$key];
 285                      unset( $this->cachedChunks[$key] );
 286                  } else {
 287                      wfWarn( "There is no item with key '$key' in this->cachedChunks in " . __METHOD__ );
 288                  }
 289              }
 290          } else {
 291              if ( !is_array( $args ) ) {
 292                  $args = array( $args );
 293              }
 294  
 295              $value = call_user_func_array( $computeFunction, $args );
 296  
 297              if ( $this->cacheEnabled ) {
 298                  if ( is_null( $key ) ) {
 299                      $this->cachedChunks[] = $value;
 300                  } else {
 301                      $this->cachedChunks[$key] = $value;
 302                  }
 303              }
 304          }
 305  
 306          return $value;
 307      }
 308  
 309      /**
 310       * Saves the HTML to the cache in case it got recomputed.
 311       * Should be called after the last time anything is added via addCachedHTML.
 312       *
 313       * @since 1.20
 314       */
 315  	public function saveCache() {
 316          if ( $this->cacheEnabled && $this->hasCached === false && !empty( $this->cachedChunks ) ) {
 317              wfGetCache( CACHE_ANYTHING )->set(
 318                  $this->getCacheKeyString(),
 319                  $this->cachedChunks,
 320                  $this->cacheExpiry
 321              );
 322          }
 323      }
 324  
 325      /**
 326       * Sets the time to live for the cache, in seconds or a unix timestamp
 327       * indicating the point of expiry...
 328       *
 329       * @since 1.20
 330       *
 331       * @param int $cacheExpiry
 332       */
 333  	public function setExpiry( $cacheExpiry ) {
 334          $this->cacheExpiry = $cacheExpiry;
 335      }
 336  
 337      /**
 338       * Returns the cache key to use to cache this page's HTML output.
 339       * Is constructed from the special page name and language code.
 340       *
 341       * @since 1.20
 342       *
 343       * @return string
 344       * @throws MWException
 345       */
 346  	protected function getCacheKeyString() {
 347          if ( $this->cacheKey === array() ) {
 348              throw new MWException( 'No cache key set, so cannot obtain or save the CacheHelper values.' );
 349          }
 350  
 351          return call_user_func_array( 'wfMemcKey', $this->cacheKey );
 352      }
 353  
 354      /**
 355       * Sets the cache key that should be used.
 356       *
 357       * @since 1.20
 358       *
 359       * @param array $cacheKey
 360       */
 361  	public function setCacheKey( array $cacheKey ) {
 362          $this->cacheKey = $cacheKey;
 363      }
 364  
 365      /**
 366       * Rebuild the content, even if it's already cached.
 367       * This effectively has the same effect as purging the cache,
 368       * since it will be overridden with the new value on the next request.
 369       *
 370       * @since 1.20
 371       */
 372  	public function rebuildOnDemand() {
 373          $this->hasCached = false;
 374      }
 375  
 376      /**
 377       * Sets a function that gets called when initialization of the cache is done.
 378       *
 379       * @since 1.20
 380       *
 381       * @param callable $handlerFunction
 382       */
 383  	public function setOnInitializedHandler( $handlerFunction ) {
 384          $this->onInitHandler = $handlerFunction;
 385      }
 386  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1