MediaWiki  REL1_22
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 ) {
00242                     break;
00243                 }
00244             }
00245         }
00246         return $file;
00247     }
00248 
00255     function findBySha1( $hash ) {
00256         if ( !$this->reposInitialised ) {
00257             $this->initialiseRepos();
00258         }
00259 
00260         $result = $this->localRepo->findBySha1( $hash );
00261         foreach ( $this->foreignRepos as $repo ) {
00262             $result = array_merge( $result, $repo->findBySha1( $hash ) );
00263         }
00264         usort( $result, 'File::compare' );
00265         return $result;
00266     }
00267 
00274     function findBySha1s( array $hashes ) {
00275         if ( !$this->reposInitialised ) {
00276             $this->initialiseRepos();
00277         }
00278 
00279         $result = $this->localRepo->findBySha1s( $hashes );
00280         foreach ( $this->foreignRepos as $repo ) {
00281             $result = array_merge_recursive( $result, $repo->findBySha1s( $hashes ) );
00282         }
00283         //sort the merged (and presorted) sublist of each hash
00284         foreach ( $result as $hash => $files ) {
00285             usort( $result[$hash], 'File::compare' );
00286         }
00287         return $result;
00288     }
00289 
00295     function getRepo( $index ) {
00296         if ( !$this->reposInitialised ) {
00297             $this->initialiseRepos();
00298         }
00299         if ( $index === 'local' ) {
00300             return $this->localRepo;
00301         } elseif ( isset( $this->foreignRepos[$index] ) ) {
00302             return $this->foreignRepos[$index];
00303         } else {
00304             return false;
00305         }
00306     }
00307 
00313     function getRepoByName( $name ) {
00314         if ( !$this->reposInitialised ) {
00315             $this->initialiseRepos();
00316         }
00317         foreach ( $this->foreignRepos as $repo ) {
00318             if ( $repo->name == $name ) {
00319                 return $repo;
00320             }
00321         }
00322         return false;
00323     }
00324 
00331     function getLocalRepo() {
00332         return $this->getRepo( 'local' );
00333     }
00334 
00343     function forEachForeignRepo( $callback, $params = array() ) {
00344         foreach ( $this->foreignRepos as $repo ) {
00345             $args = array_merge( array( $repo ), $params );
00346             if ( call_user_func_array( $callback, $args ) ) {
00347                 return true;
00348             }
00349         }
00350         return false;
00351     }
00352 
00357     function hasForeignRepos() {
00358         return (bool)$this->foreignRepos;
00359     }
00360 
00364     function initialiseRepos() {
00365         if ( $this->reposInitialised ) {
00366             return;
00367         }
00368         $this->reposInitialised = true;
00369 
00370         $this->localRepo = $this->newRepo( $this->localInfo );
00371         $this->foreignRepos = array();
00372         foreach ( $this->foreignInfo as $key => $info ) {
00373             $this->foreignRepos[$key] = $this->newRepo( $info );
00374         }
00375     }
00376 
00380     protected function newRepo( $info ) {
00381         $class = $info['class'];
00382         return new $class( $info );
00383     }
00384 
00391     function splitVirtualUrl( $url ) {
00392         if ( substr( $url, 0, 9 ) != 'mwrepo://' ) {
00393             throw new MWException( __METHOD__ . ': unknown protocol' );
00394         }
00395 
00396         $bits = explode( '/', substr( $url, 9 ), 3 );
00397         if ( count( $bits ) != 3 ) {
00398             throw new MWException( __METHOD__ . ": invalid mwrepo URL: $url" );
00399         }
00400         return $bits;
00401     }
00402 
00407     function getFileProps( $fileName ) {
00408         if ( FileRepo::isVirtualUrl( $fileName ) ) {
00409             list( $repoName, /* $zone */, /* $rel */ ) = $this->splitVirtualUrl( $fileName );
00410             if ( $repoName === '' ) {
00411                 $repoName = 'local';
00412             }
00413             $repo = $this->getRepo( $repoName );
00414             return $repo->getFileProps( $fileName );
00415         } else {
00416             return FSFile::getPropsFromPath( $fileName );
00417         }
00418     }
00419 
00423     protected function pingCache( $key ) {
00424         if ( isset( $this->cache[$key] ) ) {
00425             $tmp = $this->cache[$key];
00426             unset( $this->cache[$key] );
00427             $this->cache[$key] = $tmp;
00428         }
00429     }
00430 
00434     protected function trimCache() {
00435         while ( count( $this->cache ) >= self::MAX_CACHE_SIZE ) {
00436             reset( $this->cache );
00437             $key = key( $this->cache );
00438             wfDebug( __METHOD__ . ": evicting $key\n" );
00439             unset( $this->cache[$key] );
00440         }
00441     }
00442 
00447     public function clearCache( Title $title = null ) {
00448         if ( $title == null ) {
00449             $this->cache = array();
00450         } else {
00451             $dbKey = $title->getDBkey();
00452             if ( isset( $this->cache[$dbKey] ) ) {
00453                 unset( $this->cache[$dbKey] );
00454             }
00455         }
00456     }
00457 }