X-Git-Url: https://scripts.mit.edu/gitweb/autoinstallsdev/mediawiki.git/blobdiff_plain/19e297c21b10b1b8a3acad5e73fc71dcb35db44a..6932310fd58ebef145fa01eb76edf7150284d8ea:/includes/actions/CachedAction.php diff --git a/includes/actions/CachedAction.php b/includes/actions/CachedAction.php new file mode 100644 index 00000000..864094de --- /dev/null +++ b/includes/actions/CachedAction.php @@ -0,0 +1,189 @@ + + * @since 1.20 + */ + +/** + * Abstract action class with scaffolding for caching HTML and other values + * in a single blob. + * + * Before using any of the caching functionality, call startCache. + * After the last call to either getCachedValue or addCachedHTML, call saveCache. + * + * To get a cached value or compute it, use getCachedValue like this: + * $this->getCachedValue( $callback ); + * + * To add HTML that should be cached, use addCachedHTML like this: + * $this->addCachedHTML( $callback ); + * + * The callback function is only called when needed, so do all your expensive + * computations here. This function should returns the HTML to be cached. + * It should not add anything to the PageOutput object! + * + * @ingroup Actions + */ +abstract class CachedAction extends FormlessAction implements ICacheHelper { + + /** + * CacheHelper object to which we forward the non-SpecialPage specific caching work. + * Initialized in startCache. + * + * @since 1.20 + * @var CacheHelper + */ + protected $cacheHelper; + + /** + * If the cache is enabled or not. + * + * @since 1.20 + * @var bool + */ + protected $cacheEnabled = true; + + /** + * Sets if the cache should be enabled or not. + * + * @since 1.20 + * @param bool $cacheEnabled + */ + public function setCacheEnabled( $cacheEnabled ) { + $this->cacheHelper->setCacheEnabled( $cacheEnabled ); + } + + /** + * Initializes the caching. + * Should be called before the first time anything is added via addCachedHTML. + * + * @since 1.20 + * + * @param int|null $cacheExpiry Sets the cache expiry, either ttl in seconds or unix timestamp. + * @param bool|null $cacheEnabled Sets if the cache should be enabled or not. + */ + public function startCache( $cacheExpiry = null, $cacheEnabled = null ) { + $this->cacheHelper = new CacheHelper(); + + $this->cacheHelper->setCacheEnabled( $this->cacheEnabled ); + $this->cacheHelper->setOnInitializedHandler( [ $this, 'onCacheInitialized' ] ); + + $keyArgs = $this->getCacheKey(); + + if ( array_key_exists( 'action', $keyArgs ) && $keyArgs['action'] === 'purge' ) { + unset( $keyArgs['action'] ); + } + + $this->cacheHelper->setCacheKey( $keyArgs ); + + if ( $this->getRequest()->getText( 'action' ) === 'purge' ) { + $this->cacheHelper->rebuildOnDemand(); + } + + $this->cacheHelper->startCache( $cacheExpiry, $cacheEnabled ); + } + + /** + * Get a cached value if available or compute it if not and then cache it if possible. + * The provided $computeFunction is only called when the computation needs to happen + * and should return a result value. $args are arguments that will be passed to the + * compute function when called. + * + * @since 1.20 + * + * @param callable $computeFunction + * @param array|mixed $args + * @param string|null $key + * + * @return mixed + */ + public function getCachedValue( $computeFunction, $args = [], $key = null ) { + return $this->cacheHelper->getCachedValue( $computeFunction, $args, $key ); + } + + /** + * Add some HTML to be cached. + * This is done by providing a callback function that should + * return the HTML to be added. It will only be called if the + * item is not in the cache yet or when the cache has been invalidated. + * + * @since 1.20 + * + * @param callable $computeFunction + * @param array $args + * @param string|null $key + */ + public function addCachedHTML( $computeFunction, $args = [], $key = null ) { + $html = $this->cacheHelper->getCachedValue( $computeFunction, $args, $key ); + $this->getOutput()->addHTML( $html ); + } + + /** + * Saves the HTML to the cache in case it got recomputed. + * Should be called after the last time anything is added via addCachedHTML. + * + * @since 1.20 + */ + public function saveCache() { + $this->cacheHelper->saveCache(); + } + + /** + * Sets the time to live for the cache, in seconds or a unix timestamp + * indicating the point of expiry. + * + * @since 1.20 + * + * @param int $cacheExpiry + */ + public function setExpiry( $cacheExpiry ) { + $this->cacheHelper->setExpiry( $cacheExpiry ); + } + + /** + * Returns the variables used to constructed the cache key in an array. + * + * @since 1.20 + * + * @return array + */ + protected function getCacheKey() { + return [ + get_class( $this->page ), + $this->getName(), + $this->getLanguage()->getCode() + ]; + } + + /** + * Gets called after the cache got initialized. + * + * @since 1.20 + * + * @param bool $hasCached + */ + public function onCacheInitialized( $hasCached ) { + if ( $hasCached ) { + $this->getOutput()->setSubtitle( $this->cacheHelper->getCachedNotice( $this->getContext() ) ); + } + } +}