MediaWiki
REL1_23
|
00001 <?php 00029 class RepoGroup { 00031 protected $localRepo; 00032 00034 protected $foreignRepos; 00035 00037 protected $reposInitialised = false; 00038 00040 protected $localInfo; 00041 00043 protected $foreignInfo; 00044 00046 protected $cache; 00047 00049 protected static $instance; 00050 00052 const MAX_CACHE_SIZE = 500; 00053 00059 static function singleton() { 00060 if ( self::$instance ) { 00061 return self::$instance; 00062 } 00063 global $wgLocalFileRepo, $wgForeignFileRepos; 00064 self::$instance = new RepoGroup( $wgLocalFileRepo, $wgForeignFileRepos ); 00065 00066 return self::$instance; 00067 } 00068 00073 static function destroySingleton() { 00074 self::$instance = null; 00075 } 00076 00085 static function setSingleton( $instance ) { 00086 self::$instance = $instance; 00087 } 00088 00098 function __construct( $localInfo, $foreignInfo ) { 00099 $this->localInfo = $localInfo; 00100 $this->foreignInfo = $foreignInfo; 00101 $this->cache = new ProcessCacheLRU( self::MAX_CACHE_SIZE ); 00102 } 00103 00120 function findFile( $title, $options = array() ) { 00121 if ( !is_array( $options ) ) { 00122 // MW 1.15 compat 00123 $options = array( 'time' => $options ); 00124 } 00125 if ( !$this->reposInitialised ) { 00126 $this->initialiseRepos(); 00127 } 00128 $title = File::normalizeTitle( $title ); 00129 if ( !$title ) { 00130 return false; 00131 } 00132 00133 # Check the cache 00134 if ( empty( $options['ignoreRedirect'] ) 00135 && empty( $options['private'] ) 00136 && empty( $options['bypassCache'] ) 00137 ) { 00138 $time = isset( $options['time'] ) ? $options['time'] : ''; 00139 $dbkey = $title->getDBkey(); 00140 if ( $this->cache->has( $dbkey, $time, 60 ) ) { 00141 return $this->cache->get( $dbkey, $time ); 00142 } 00143 $useCache = true; 00144 } else { 00145 $useCache = false; 00146 } 00147 00148 # Check the local repo 00149 $image = $this->localRepo->findFile( $title, $options ); 00150 00151 # Check the foreign repos 00152 if ( !$image ) { 00153 foreach ( $this->foreignRepos as $repo ) { 00154 $image = $repo->findFile( $title, $options ); 00155 if ( $image ) { 00156 break; 00157 } 00158 } 00159 } 00160 00161 $image = $image ? $image : false; // type sanity 00162 # Cache file existence or non-existence 00163 if ( $useCache && ( !$image || $image->isCacheable() ) ) { 00164 $this->cache->set( $dbkey, $time, $image ); 00165 } 00166 00167 return $image; 00168 } 00169 00191 function findFiles( array $inputItems, $flags = 0 ) { 00192 if ( !$this->reposInitialised ) { 00193 $this->initialiseRepos(); 00194 } 00195 00196 $items = array(); 00197 foreach ( $inputItems as $item ) { 00198 if ( !is_array( $item ) ) { 00199 $item = array( 'title' => $item ); 00200 } 00201 $item['title'] = File::normalizeTitle( $item['title'] ); 00202 if ( $item['title'] ) { 00203 $items[$item['title']->getDBkey()] = $item; 00204 } 00205 } 00206 00207 $images = $this->localRepo->findFiles( $items, $flags ); 00208 00209 foreach ( $this->foreignRepos as $repo ) { 00210 // Remove found files from $items 00211 foreach ( $images as $name => $image ) { 00212 unset( $items[$name] ); 00213 } 00214 00215 $images = array_merge( $images, $repo->findFiles( $items, $flags ) ); 00216 } 00217 00218 return $images; 00219 } 00220 00226 function checkRedirect( Title $title ) { 00227 if ( !$this->reposInitialised ) { 00228 $this->initialiseRepos(); 00229 } 00230 00231 $redir = $this->localRepo->checkRedirect( $title ); 00232 if ( $redir ) { 00233 return $redir; 00234 } 00235 00236 foreach ( $this->foreignRepos as $repo ) { 00237 $redir = $repo->checkRedirect( $title ); 00238 if ( $redir ) { 00239 return $redir; 00240 } 00241 } 00242 00243 return false; 00244 } 00245 00254 function findFileFromKey( $hash, $options = array() ) { 00255 if ( !$this->reposInitialised ) { 00256 $this->initialiseRepos(); 00257 } 00258 00259 $file = $this->localRepo->findFileFromKey( $hash, $options ); 00260 if ( !$file ) { 00261 foreach ( $this->foreignRepos as $repo ) { 00262 $file = $repo->findFileFromKey( $hash, $options ); 00263 if ( $file ) { 00264 break; 00265 } 00266 } 00267 } 00268 00269 return $file; 00270 } 00271 00278 function findBySha1( $hash ) { 00279 if ( !$this->reposInitialised ) { 00280 $this->initialiseRepos(); 00281 } 00282 00283 $result = $this->localRepo->findBySha1( $hash ); 00284 foreach ( $this->foreignRepos as $repo ) { 00285 $result = array_merge( $result, $repo->findBySha1( $hash ) ); 00286 } 00287 usort( $result, 'File::compare' ); 00288 00289 return $result; 00290 } 00291 00298 function findBySha1s( array $hashes ) { 00299 if ( !$this->reposInitialised ) { 00300 $this->initialiseRepos(); 00301 } 00302 00303 $result = $this->localRepo->findBySha1s( $hashes ); 00304 foreach ( $this->foreignRepos as $repo ) { 00305 $result = array_merge_recursive( $result, $repo->findBySha1s( $hashes ) ); 00306 } 00307 //sort the merged (and presorted) sublist of each hash 00308 foreach ( $result as $hash => $files ) { 00309 usort( $result[$hash], 'File::compare' ); 00310 } 00311 00312 return $result; 00313 } 00314 00320 function getRepo( $index ) { 00321 if ( !$this->reposInitialised ) { 00322 $this->initialiseRepos(); 00323 } 00324 if ( $index === 'local' ) { 00325 return $this->localRepo; 00326 } elseif ( isset( $this->foreignRepos[$index] ) ) { 00327 return $this->foreignRepos[$index]; 00328 } else { 00329 return false; 00330 } 00331 } 00332 00338 function getRepoByName( $name ) { 00339 if ( !$this->reposInitialised ) { 00340 $this->initialiseRepos(); 00341 } 00342 foreach ( $this->foreignRepos as $repo ) { 00343 if ( $repo->name == $name ) { 00344 return $repo; 00345 } 00346 } 00347 00348 return false; 00349 } 00350 00357 function getLocalRepo() { 00358 return $this->getRepo( 'local' ); 00359 } 00360 00369 function forEachForeignRepo( $callback, $params = array() ) { 00370 foreach ( $this->foreignRepos as $repo ) { 00371 $args = array_merge( array( $repo ), $params ); 00372 if ( call_user_func_array( $callback, $args ) ) { 00373 return true; 00374 } 00375 } 00376 00377 return false; 00378 } 00379 00384 function hasForeignRepos() { 00385 return (bool)$this->foreignRepos; 00386 } 00387 00391 function initialiseRepos() { 00392 if ( $this->reposInitialised ) { 00393 return; 00394 } 00395 $this->reposInitialised = true; 00396 00397 $this->localRepo = $this->newRepo( $this->localInfo ); 00398 $this->foreignRepos = array(); 00399 foreach ( $this->foreignInfo as $key => $info ) { 00400 $this->foreignRepos[$key] = $this->newRepo( $info ); 00401 } 00402 } 00403 00407 protected function newRepo( $info ) { 00408 $class = $info['class']; 00409 00410 return new $class( $info ); 00411 } 00412 00419 function splitVirtualUrl( $url ) { 00420 if ( substr( $url, 0, 9 ) != 'mwrepo://' ) { 00421 throw new MWException( __METHOD__ . ': unknown protocol' ); 00422 } 00423 00424 $bits = explode( '/', substr( $url, 9 ), 3 ); 00425 if ( count( $bits ) != 3 ) { 00426 throw new MWException( __METHOD__ . ": invalid mwrepo URL: $url" ); 00427 } 00428 00429 return $bits; 00430 } 00431 00436 function getFileProps( $fileName ) { 00437 if ( FileRepo::isVirtualUrl( $fileName ) ) { 00438 list( $repoName, /* $zone */, /* $rel */ ) = $this->splitVirtualUrl( $fileName ); 00439 if ( $repoName === '' ) { 00440 $repoName = 'local'; 00441 } 00442 $repo = $this->getRepo( $repoName ); 00443 00444 return $repo->getFileProps( $fileName ); 00445 } else { 00446 return FSFile::getPropsFromPath( $fileName ); 00447 } 00448 } 00449 00454 public function clearCache( Title $title = null ) { 00455 if ( $title == null ) { 00456 $this->cache->clear(); 00457 } else { 00458 $this->cache->clear( $title->getDBkey() ); 00459 } 00460 } 00461 }