MediaWiki  REL1_19
RepoGroup.php
Go to the documentation of this file.
00001 <?php
00014 class RepoGroup {
00015 
00019         var $localRepo;
00020 
00021         var $foreignRepos, $reposInitialised = false;
00022         var $localInfo, $foreignInfo;
00023         var $cache;
00024 
00028         protected static $instance;
00029         const MAX_CACHE_SIZE = 1000;
00030 
00036         static function singleton() {
00037                 if ( self::$instance ) {
00038                         return self::$instance;
00039                 }
00040                 global $wgLocalFileRepo, $wgForeignFileRepos;
00041                 self::$instance = new RepoGroup( $wgLocalFileRepo, $wgForeignFileRepos );
00042                 return self::$instance;
00043         }
00044 
00049         static function destroySingleton() {
00050                 self::$instance = null;
00051         }
00052 
00061         static function setSingleton( $instance ) {
00062                 self::$instance = $instance;
00063         }
00064 
00074         function __construct( $localInfo, $foreignInfo ) {
00075                 $this->localInfo = $localInfo;
00076                 $this->foreignInfo = $foreignInfo;
00077                 $this->cache = array();
00078         }
00079 
00099         function findFile( $title, $options = array() ) {
00100                 if ( !is_array( $options ) ) {
00101                         // MW 1.15 compat
00102                         $options = array( 'time' => $options );
00103                 }
00104                 if ( !$this->reposInitialised ) {
00105                         $this->initialiseRepos();
00106                 }
00107                 $title = File::normalizeTitle( $title );
00108                 if ( !$title ) {
00109                         return false;
00110                 }
00111 
00112                 # Check the cache
00113                 if ( empty( $options['ignoreRedirect'] )
00114                         && empty( $options['private'] )
00115                         && empty( $options['bypassCache'] ) )
00116                 {
00117                         $useCache = true;
00118                         $time = isset( $options['time'] ) ? $options['time'] : '';
00119                         $dbkey = $title->getDBkey();
00120                         if ( isset( $this->cache[$dbkey][$time] ) ) {
00121                                 wfDebug( __METHOD__.": got File:$dbkey from process cache\n" );
00122                                 # Move it to the end of the list so that we can delete the LRU entry later
00123                                 $tmp = $this->cache[$dbkey];
00124                                 unset( $this->cache[$dbkey] );
00125                                 $this->cache[$dbkey] = $tmp;
00126                                 # Return the entry
00127                                 return $this->cache[$dbkey][$time];
00128                         } else {
00129                                 # Add a negative cache entry, may be overridden
00130                                 $this->trimCache();
00131                                 $this->cache[$dbkey][$time] = false;
00132                                 $cacheEntry =& $this->cache[$dbkey][$time];
00133                         }
00134                 } else {
00135                         $useCache = false;
00136                 }
00137 
00138                 # Check the local repo
00139                 $image = $this->localRepo->findFile( $title, $options );
00140                 if ( $image ) {
00141                         if ( $useCache ) {
00142                                 $cacheEntry = $image;
00143                         }
00144                         return $image;
00145                 }
00146 
00147                 # Check the foreign repos
00148                 foreach ( $this->foreignRepos as $repo ) {
00149                         $image = $repo->findFile( $title, $options );
00150                         if ( $image ) {
00151                                 if ( $useCache ) {
00152                                         $cacheEntry = $image;
00153                                 }
00154                                 return $image;
00155                         }
00156                 }
00157                 # Not found, do not override negative cache
00158                 return false;
00159         }
00160 
00161         function findFiles( $inputItems ) {
00162                 if ( !$this->reposInitialised ) {
00163                         $this->initialiseRepos();
00164                 }
00165 
00166                 $items = array();
00167                 foreach ( $inputItems as $item ) {
00168                         if ( !is_array( $item ) ) {
00169                                 $item = array( 'title' => $item );
00170                         }
00171                         $item['title'] = File::normalizeTitle( $item['title'] );
00172                         if ( $item['title'] ) {
00173                                 $items[$item['title']->getDBkey()] = $item;
00174                         }
00175                 }
00176 
00177                 $images = $this->localRepo->findFiles( $items );
00178 
00179                 foreach ( $this->foreignRepos as $repo ) {
00180                         // Remove found files from $items
00181                         foreach ( $images as $name => $image ) {
00182                                 unset( $items[$name] );
00183                         }
00184 
00185                         $images = array_merge( $images, $repo->findFiles( $items ) );
00186                 }
00187                 return $images;
00188         }
00189 
00193         function checkRedirect( Title $title ) {
00194                 if ( !$this->reposInitialised ) {
00195                         $this->initialiseRepos();
00196                 }
00197 
00198                 $redir = $this->localRepo->checkRedirect( $title );
00199                 if( $redir ) {
00200                         return $redir;
00201                 }
00202                 foreach ( $this->foreignRepos as $repo ) {
00203                         $redir = $repo->checkRedirect( $title );
00204                         if ( $redir ) {
00205                                 return $redir;
00206                         }
00207                 }
00208                 return false;
00209         }
00210 
00219         function findFileFromKey( $hash, $options = array() ) {
00220                 if ( !$this->reposInitialised ) {
00221                         $this->initialiseRepos();
00222                 }
00223 
00224                 $file = $this->localRepo->findFileFromKey( $hash, $options );
00225                 if ( !$file ) {
00226                         foreach ( $this->foreignRepos as $repo ) {
00227                                 $file = $repo->findFileFromKey( $hash, $options );
00228                                 if ( $file ) break;
00229                         }
00230                 }
00231                 return $file;
00232         }
00233 
00240         function findBySha1( $hash ) {
00241                 if ( !$this->reposInitialised ) {
00242                         $this->initialiseRepos();
00243                 }
00244 
00245                 $result = $this->localRepo->findBySha1( $hash );
00246                 foreach ( $this->foreignRepos as $repo ) {
00247                         $result = array_merge( $result, $repo->findBySha1( $hash ) );
00248                 }
00249                 return $result;
00250         }
00251 
00255         function getRepo( $index ) {
00256                 if ( !$this->reposInitialised ) {
00257                         $this->initialiseRepos();
00258                 }
00259                 if ( $index === 'local' ) {
00260                         return $this->localRepo;
00261                 } elseif ( isset( $this->foreignRepos[$index] ) ) {
00262                         return $this->foreignRepos[$index];
00263                 } else {
00264                         return false;
00265                 }
00266         }
00270         function getRepoByName( $name ) {
00271                 if ( !$this->reposInitialised ) {
00272                         $this->initialiseRepos();
00273                 }
00274                 foreach ( $this->foreignRepos as $repo ) {
00275                         if ( $repo->name == $name)
00276                                 return $repo;
00277                 }
00278                 return false;
00279         }
00280 
00287         function getLocalRepo() {
00288                 return $this->getRepo( 'local' );
00289         }
00290 
00298         function forEachForeignRepo( $callback, $params = array() ) {
00299                 foreach( $this->foreignRepos as $repo ) {
00300                         $args = array_merge( array( $repo ), $params );
00301                         if( call_user_func_array( $callback, $args ) ) {
00302                                 return true;
00303                         }
00304                 }
00305                 return false;
00306         }
00307 
00312         function hasForeignRepos() {
00313                 return (bool)$this->foreignRepos;
00314         }
00315 
00319         function initialiseRepos() {
00320                 if ( $this->reposInitialised ) {
00321                         return;
00322                 }
00323                 $this->reposInitialised = true;
00324 
00325                 $this->localRepo = $this->newRepo( $this->localInfo );
00326                 $this->foreignRepos = array();
00327                 foreach ( $this->foreignInfo as $key => $info ) {
00328                         $this->foreignRepos[$key] = $this->newRepo( $info );
00329                 }
00330         }
00331 
00335         protected function newRepo( $info ) {
00336                 $class = $info['class'];
00337                 return new $class( $info );
00338         }
00339 
00344         function splitVirtualUrl( $url ) {
00345                 if ( substr( $url, 0, 9 ) != 'mwrepo://' ) {
00346                         throw new MWException( __METHOD__.': unknown protocol' );
00347                 }
00348 
00349                 $bits = explode( '/', substr( $url, 9 ), 3 );
00350                 if ( count( $bits ) != 3 ) {
00351                         throw new MWException( __METHOD__.": invalid mwrepo URL: $url" );
00352                 }
00353                 return $bits;
00354         }
00355 
00356         function getFileProps( $fileName ) {
00357                 if ( FileRepo::isVirtualUrl( $fileName ) ) {
00358                         list( $repoName, /* $zone */, /* $rel */ ) = $this->splitVirtualUrl( $fileName );
00359                         if ( $repoName === '' ) {
00360                                 $repoName = 'local';
00361                         }
00362                         $repo = $this->getRepo( $repoName );
00363                         return $repo->getFileProps( $fileName );
00364                 } else {
00365                         return FSFile::getPropsFromPath( $fileName );
00366                 }
00367         }
00368 
00372         protected function trimCache() {
00373                 while ( count( $this->cache ) >= self::MAX_CACHE_SIZE ) {
00374                         reset( $this->cache );
00375                         $key = key( $this->cache );
00376                         wfDebug( __METHOD__.": evicting $key\n" );
00377                         unset( $this->cache[$key] );
00378                 }
00379         }
00380 
00385         public function clearCache( Title $title = null ) {
00386                 if ( $title == null ) {
00387                         $this->cache = array();
00388                 } else {
00389                         $dbKey = $title->getDBkey();
00390                         if ( isset( $this->cache[$dbKey] ) ) {
00391                                 unset( $this->cache[$dbKey] );
00392                         }
00393                 }
00394         }
00395 }