00001 <?php 00002 00009 class DependencyWrapper { 00010 var $value; 00011 var $deps; 00012 00019 function __construct( $value = false, $deps = array() ) { 00020 $this->value = $value; 00021 if ( !is_array( $deps ) ) { 00022 $deps = array( $deps ); 00023 } 00024 $this->deps = $deps; 00025 } 00026 00030 function isExpired() { 00031 foreach ( $this->deps as $dep ) { 00032 if ( $dep->isExpired() ) { 00033 return true; 00034 } 00035 } 00036 return false; 00037 } 00038 00043 function initialiseDeps() { 00044 foreach ( $this->deps as $dep ) { 00045 $dep->loadDependencyValues(); 00046 } 00047 } 00048 00052 function getValue() { 00053 return $this->value; 00054 } 00055 00059 function storeToCache( $cache, $key, $expiry = 0 ) { 00060 $this->initialiseDeps(); 00061 $cache->set( $key, $this, $expiry ); 00062 } 00063 00081 static function getValueFromCache( $cache, $key, $expiry = 0, $callback = false, 00082 $callbackParams = array(), $deps = array() ) 00083 { 00084 $obj = $cache->get( $key ); 00085 if ( is_object( $obj ) && $obj instanceof DependencyWrapper && !$obj->isExpired() ) { 00086 $value = $obj->value; 00087 } elseif ( $callback ) { 00088 $value = call_user_func_array( $callback, $callbackParams ); 00089 # Cache the newly-generated value 00090 $wrapper = new DependencyWrapper( $value, $deps ); 00091 $wrapper->storeToCache( $cache, $key, $expiry ); 00092 } else { 00093 $value = null; 00094 } 00095 return $value; 00096 } 00097 } 00098 00102 abstract class CacheDependency { 00106 abstract function isExpired(); 00107 00111 function loadDependencyValues() {} 00112 } 00113 00117 class FileDependency extends CacheDependency { 00118 var $filename, $timestamp; 00119 00132 function __construct( $filename, $timestamp = null ) { 00133 $this->filename = $filename; 00134 $this->timestamp = $timestamp; 00135 } 00136 00137 function loadDependencyValues() { 00138 if ( is_null( $this->timestamp ) ) { 00139 if ( !file_exists( $this->filename ) ) { 00140 # Dependency on a non-existent file 00141 # This is a valid concept! 00142 $this->timestamp = false; 00143 } else { 00144 $this->timestamp = filemtime( $this->filename ); 00145 } 00146 } 00147 } 00148 00149 function isExpired() { 00150 if ( !file_exists( $this->filename ) ) { 00151 if ( $this->timestamp === false ) { 00152 # Still nonexistent 00153 return false; 00154 } else { 00155 # Deleted 00156 wfDebug( "Dependency triggered: {$this->filename} deleted.\n" ); 00157 return true; 00158 } 00159 } else { 00160 $lastmod = filemtime( $this->filename ); 00161 if ( $lastmod > $this->timestamp ) { 00162 # Modified or created 00163 wfDebug( "Dependency triggered: {$this->filename} changed.\n" ); 00164 return true; 00165 } else { 00166 # Not modified 00167 return false; 00168 } 00169 } 00170 } 00171 } 00172 00176 class TitleDependency extends CacheDependency { 00177 var $titleObj; 00178 var $ns, $dbk; 00179 var $touched; 00180 00185 function __construct( Title $title ) { 00186 $this->titleObj = $title; 00187 $this->ns = $title->getNamespace(); 00188 $this->dbk = $title->getDBkey(); 00189 } 00190 00191 function loadDependencyValues() { 00192 $this->touched = $this->getTitle()->getTouched(); 00193 } 00194 00198 function __sleep() { 00199 return array( 'ns', 'dbk', 'touched' ); 00200 } 00201 00202 function getTitle() { 00203 if ( !isset( $this->titleObj ) ) { 00204 $this->titleObj = Title::makeTitle( $this->ns, $this->dbk ); 00205 } 00206 return $this->titleObj; 00207 } 00208 00209 function isExpired() { 00210 $touched = $this->getTitle()->getTouched(); 00211 if ( $this->touched === false ) { 00212 if ( $touched === false ) { 00213 # Still missing 00214 return false; 00215 } else { 00216 # Created 00217 return true; 00218 } 00219 } elseif ( $touched === false ) { 00220 # Deleted 00221 return true; 00222 } elseif ( $touched > $this->touched ) { 00223 # Updated 00224 return true; 00225 } else { 00226 # Unmodified 00227 return false; 00228 } 00229 } 00230 } 00231 00235 class TitleListDependency extends CacheDependency { 00236 var $linkBatch; 00237 var $timestamps; 00238 00242 function __construct( LinkBatch $linkBatch ) { 00243 $this->linkBatch = $linkBatch; 00244 } 00245 00246 function calculateTimestamps() { 00247 # Initialise values to false 00248 $timestamps = array(); 00249 foreach ( $this->getLinkBatch()->data as $ns => $dbks ) { 00250 if ( count( $dbks ) > 0 ) { 00251 $timestamps[$ns] = array(); 00252 foreach ( $dbks as $dbk => $value ) { 00253 $timestamps[$ns][$dbk] = false; 00254 } 00255 } 00256 } 00257 00258 # Do the query 00259 if ( count( $timestamps ) ) { 00260 $dbr = wfGetDB( DB_SLAVE ); 00261 $where = $this->getLinkBatch()->constructSet( 'page', $dbr ); 00262 $res = $dbr->select( 'page', 00263 array( 'page_namespace', 'page_title', 'page_touched' ), 00264 $where, __METHOD__ ); 00265 while ( $row = $dbr->fetchObject( $res ) ) { 00266 $timestamps[$row->page_namespace][$row->page_title] = $row->page_touched; 00267 } 00268 } 00269 return $timestamps; 00270 } 00271 00272 function loadDependencyValues() { 00273 $this->timestamps = $this->calculateTimestamps(); 00274 } 00275 00276 function __sleep() { 00277 return array( 'timestamps' ); 00278 } 00279 00280 function getLinkBatch() { 00281 if ( !isset( $this->linkBatch ) ){ 00282 $this->linkBatch = new LinkBatch; 00283 $this->linkBatch->setArray( $this->timestamps ); 00284 } 00285 return $this->linkBatch; 00286 } 00287 00288 function isExpired() { 00289 $newTimestamps = $this->calculateTimestamps(); 00290 foreach ( $this->timestamps as $ns => $dbks ) { 00291 foreach ( $dbks as $dbk => $oldTimestamp ) { 00292 $newTimestamp = $newTimestamps[$ns][$dbk]; 00293 if ( $oldTimestamp === false ) { 00294 if ( $newTimestamp === false ) { 00295 # Still missing 00296 } else { 00297 # Created 00298 return true; 00299 } 00300 } elseif ( $newTimestamp === false ) { 00301 # Deleted 00302 return true; 00303 } elseif ( $newTimestamp > $oldTimestamp ) { 00304 # Updated 00305 return true; 00306 } else { 00307 # Unmodified 00308 } 00309 } 00310 } 00311 return false; 00312 } 00313 } 00314 00318 class GlobalDependency extends CacheDependency { 00319 var $name, $value; 00320 00321 function __construct( $name ) { 00322 $this->name = $name; 00323 $this->value = $GLOBALS[$name]; 00324 } 00325 00326 function isExpired() { 00327 return $GLOBALS[$this->name] != $this->value; 00328 } 00329 } 00330 00334 class ConstantDependency extends CacheDependency { 00335 var $name, $value; 00336 00337 function __construct( $name ) { 00338 $this->name = $name; 00339 $this->value = constant( $name ); 00340 } 00341 00342 function isExpired() { 00343 return constant( $this->name ) != $this->value; 00344 } 00345 }