MediaWiki  REL1_23
RepoGroup.php
Go to the documentation of this file.
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 }