MediaWiki
REL1_20
|
00001 <?php 00029 class RepoGroup { 00033 var $localRepo; 00034 00035 var $foreignRepos, $reposInitialised = false; 00036 var $localInfo, $foreignInfo; 00037 var $cache; 00038 00042 protected static $instance; 00043 const MAX_CACHE_SIZE = 500; 00044 00050 static function singleton() { 00051 if ( self::$instance ) { 00052 return self::$instance; 00053 } 00054 global $wgLocalFileRepo, $wgForeignFileRepos; 00055 self::$instance = new RepoGroup( $wgLocalFileRepo, $wgForeignFileRepos ); 00056 return self::$instance; 00057 } 00058 00063 static function destroySingleton() { 00064 self::$instance = null; 00065 } 00066 00075 static function setSingleton( $instance ) { 00076 self::$instance = $instance; 00077 } 00078 00088 function __construct( $localInfo, $foreignInfo ) { 00089 $this->localInfo = $localInfo; 00090 $this->foreignInfo = $foreignInfo; 00091 $this->cache = array(); 00092 } 00093 00113 function findFile( $title, $options = array() ) { 00114 if ( !is_array( $options ) ) { 00115 // MW 1.15 compat 00116 $options = array( 'time' => $options ); 00117 } 00118 if ( !$this->reposInitialised ) { 00119 $this->initialiseRepos(); 00120 } 00121 $title = File::normalizeTitle( $title ); 00122 if ( !$title ) { 00123 return false; 00124 } 00125 00126 # Check the cache 00127 if ( empty( $options['ignoreRedirect'] ) 00128 && empty( $options['private'] ) 00129 && empty( $options['bypassCache'] ) ) 00130 { 00131 $time = isset( $options['time'] ) ? $options['time'] : ''; 00132 $dbkey = $title->getDBkey(); 00133 if ( isset( $this->cache[$dbkey][$time] ) ) { 00134 wfDebug( __METHOD__.": got File:$dbkey from process cache\n" ); 00135 # Move it to the end of the list so that we can delete the LRU entry later 00136 $this->pingCache( $dbkey ); 00137 # Return the entry 00138 return $this->cache[$dbkey][$time]; 00139 } 00140 $useCache = true; 00141 } else { 00142 $useCache = false; 00143 } 00144 00145 # Check the local repo 00146 $image = $this->localRepo->findFile( $title, $options ); 00147 00148 # Check the foreign repos 00149 if ( !$image ) { 00150 foreach ( $this->foreignRepos as $repo ) { 00151 $image = $repo->findFile( $title, $options ); 00152 if ( $image ) { 00153 break; 00154 } 00155 } 00156 } 00157 00158 $image = $image ? $image : false; // type sanity 00159 # Cache file existence or non-existence 00160 if ( $useCache && ( !$image || $image->isCacheable() ) ) { 00161 $this->trimCache(); 00162 $this->cache[$dbkey][$time] = $image; 00163 } 00164 00165 return $image; 00166 } 00167 00172 function findFiles( $inputItems ) { 00173 if ( !$this->reposInitialised ) { 00174 $this->initialiseRepos(); 00175 } 00176 00177 $items = array(); 00178 foreach ( $inputItems as $item ) { 00179 if ( !is_array( $item ) ) { 00180 $item = array( 'title' => $item ); 00181 } 00182 $item['title'] = File::normalizeTitle( $item['title'] ); 00183 if ( $item['title'] ) { 00184 $items[$item['title']->getDBkey()] = $item; 00185 } 00186 } 00187 00188 $images = $this->localRepo->findFiles( $items ); 00189 00190 foreach ( $this->foreignRepos as $repo ) { 00191 // Remove found files from $items 00192 foreach ( $images as $name => $image ) { 00193 unset( $items[$name] ); 00194 } 00195 00196 $images = array_merge( $images, $repo->findFiles( $items ) ); 00197 } 00198 return $images; 00199 } 00200 00206 function checkRedirect( Title $title ) { 00207 if ( !$this->reposInitialised ) { 00208 $this->initialiseRepos(); 00209 } 00210 00211 $redir = $this->localRepo->checkRedirect( $title ); 00212 if( $redir ) { 00213 return $redir; 00214 } 00215 foreach ( $this->foreignRepos as $repo ) { 00216 $redir = $repo->checkRedirect( $title ); 00217 if ( $redir ) { 00218 return $redir; 00219 } 00220 } 00221 return false; 00222 } 00223 00232 function findFileFromKey( $hash, $options = array() ) { 00233 if ( !$this->reposInitialised ) { 00234 $this->initialiseRepos(); 00235 } 00236 00237 $file = $this->localRepo->findFileFromKey( $hash, $options ); 00238 if ( !$file ) { 00239 foreach ( $this->foreignRepos as $repo ) { 00240 $file = $repo->findFileFromKey( $hash, $options ); 00241 if ( $file ) break; 00242 } 00243 } 00244 return $file; 00245 } 00246 00253 function findBySha1( $hash ) { 00254 if ( !$this->reposInitialised ) { 00255 $this->initialiseRepos(); 00256 } 00257 00258 $result = $this->localRepo->findBySha1( $hash ); 00259 foreach ( $this->foreignRepos as $repo ) { 00260 $result = array_merge( $result, $repo->findBySha1( $hash ) ); 00261 } 00262 usort( $result, 'File::compare' ); 00263 return $result; 00264 } 00265 00272 function findBySha1s( array $hashes ) { 00273 if ( !$this->reposInitialised ) { 00274 $this->initialiseRepos(); 00275 } 00276 00277 $result = $this->localRepo->findBySha1s( $hashes ); 00278 foreach ( $this->foreignRepos as $repo ) { 00279 $result = array_merge_recursive( $result, $repo->findBySha1s( $hashes ) ); 00280 } 00281 //sort the merged (and presorted) sublist of each hash 00282 foreach( $result as $hash => $files ) { 00283 usort( $result[$hash], 'File::compare' ); 00284 } 00285 return $result; 00286 } 00287 00293 function getRepo( $index ) { 00294 if ( !$this->reposInitialised ) { 00295 $this->initialiseRepos(); 00296 } 00297 if ( $index === 'local' ) { 00298 return $this->localRepo; 00299 } elseif ( isset( $this->foreignRepos[$index] ) ) { 00300 return $this->foreignRepos[$index]; 00301 } else { 00302 return false; 00303 } 00304 } 00305 00311 function getRepoByName( $name ) { 00312 if ( !$this->reposInitialised ) { 00313 $this->initialiseRepos(); 00314 } 00315 foreach ( $this->foreignRepos as $repo ) { 00316 if ( $repo->name == $name ) { 00317 return $repo; 00318 } 00319 } 00320 return false; 00321 } 00322 00329 function getLocalRepo() { 00330 return $this->getRepo( 'local' ); 00331 } 00332 00341 function forEachForeignRepo( $callback, $params = array() ) { 00342 foreach( $this->foreignRepos as $repo ) { 00343 $args = array_merge( array( $repo ), $params ); 00344 if( call_user_func_array( $callback, $args ) ) { 00345 return true; 00346 } 00347 } 00348 return false; 00349 } 00350 00355 function hasForeignRepos() { 00356 return (bool)$this->foreignRepos; 00357 } 00358 00362 function initialiseRepos() { 00363 if ( $this->reposInitialised ) { 00364 return; 00365 } 00366 $this->reposInitialised = true; 00367 00368 $this->localRepo = $this->newRepo( $this->localInfo ); 00369 $this->foreignRepos = array(); 00370 foreach ( $this->foreignInfo as $key => $info ) { 00371 $this->foreignRepos[$key] = $this->newRepo( $info ); 00372 } 00373 } 00374 00378 protected function newRepo( $info ) { 00379 $class = $info['class']; 00380 return new $class( $info ); 00381 } 00382 00389 function splitVirtualUrl( $url ) { 00390 if ( substr( $url, 0, 9 ) != 'mwrepo://' ) { 00391 throw new MWException( __METHOD__.': unknown protocol' ); 00392 } 00393 00394 $bits = explode( '/', substr( $url, 9 ), 3 ); 00395 if ( count( $bits ) != 3 ) { 00396 throw new MWException( __METHOD__.": invalid mwrepo URL: $url" ); 00397 } 00398 return $bits; 00399 } 00400 00405 function getFileProps( $fileName ) { 00406 if ( FileRepo::isVirtualUrl( $fileName ) ) { 00407 list( $repoName, /* $zone */, /* $rel */ ) = $this->splitVirtualUrl( $fileName ); 00408 if ( $repoName === '' ) { 00409 $repoName = 'local'; 00410 } 00411 $repo = $this->getRepo( $repoName ); 00412 return $repo->getFileProps( $fileName ); 00413 } else { 00414 return FSFile::getPropsFromPath( $fileName ); 00415 } 00416 } 00417 00421 protected function pingCache( $key ) { 00422 if ( isset( $this->cache[$key] ) ) { 00423 $tmp = $this->cache[$key]; 00424 unset( $this->cache[$key] ); 00425 $this->cache[$key] = $tmp; 00426 } 00427 } 00428 00432 protected function trimCache() { 00433 while ( count( $this->cache ) >= self::MAX_CACHE_SIZE ) { 00434 reset( $this->cache ); 00435 $key = key( $this->cache ); 00436 wfDebug( __METHOD__.": evicting $key\n" ); 00437 unset( $this->cache[$key] ); 00438 } 00439 } 00440 00445 public function clearCache( Title $title = null ) { 00446 if ( $title == null ) { 00447 $this->cache = array(); 00448 } else { 00449 $dbKey = $title->getDBkey(); 00450 if ( isset( $this->cache[$dbKey] ) ) { 00451 unset( $this->cache[$dbKey] ); 00452 } 00453 } 00454 } 00455 }