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