00001 <?php
00013 class RepoGroup {
00014 var $localRepo, $foreignRepos, $reposInitialised = false;
00015 var $localInfo, $foreignInfo;
00016 var $cache;
00017
00018 protected static $instance;
00019 const MAX_CACHE_SIZE = 1000;
00020
00025 static function singleton() {
00026 if ( self::$instance ) {
00027 return self::$instance;
00028 }
00029 global $wgLocalFileRepo, $wgForeignFileRepos;
00030 self::$instance = new RepoGroup( $wgLocalFileRepo, $wgForeignFileRepos );
00031 return self::$instance;
00032 }
00033
00038 static function destroySingleton() {
00039 self::$instance = null;
00040 }
00041
00045 static function setSingleton( $instance ) {
00046 self::$instance = $instance;
00047 }
00048
00056 function __construct( $localInfo, $foreignInfo ) {
00057 $this->localInfo = $localInfo;
00058 $this->foreignInfo = $foreignInfo;
00059 $this->cache = array();
00060 }
00061
00080 function findFile( $title, $options = array() ) {
00081 if ( !is_array( $options ) ) {
00082
00083 $options = array( 'time' => $options );
00084 }
00085 if ( !$this->reposInitialised ) {
00086 $this->initialiseRepos();
00087 }
00088 if ( !($title instanceof Title) ) {
00089 $title = Title::makeTitleSafe( NS_FILE, $title );
00090 if ( !is_object( $title ) ) {
00091 return false;
00092 }
00093 }
00094
00095 # Check the cache
00096 if ( empty( $options['ignoreRedirect'] )
00097 && empty( $options['private'] )
00098 && empty( $options['bypassCache'] ) )
00099 {
00100 $useCache = true;
00101 $time = isset( $options['time'] ) ? $options['time'] : '';
00102 $dbkey = $title->getDBkey();
00103 if ( isset( $this->cache[$dbkey][$time] ) ) {
00104 wfDebug( __METHOD__.": got File:$dbkey from process cache\n" );
00105 # Move it to the end of the list so that we can delete the LRU entry later
00106 $tmp = $this->cache[$dbkey];
00107 unset( $this->cache[$dbkey] );
00108 $this->cache[$dbkey] = $tmp;
00109 # Return the entry
00110 return $this->cache[$dbkey][$time];
00111 } else {
00112 # Add a negative cache entry, may be overridden
00113 $this->trimCache();
00114 $this->cache[$dbkey][$time] = false;
00115 $cacheEntry =& $this->cache[$dbkey][$time];
00116 }
00117 } else {
00118 $useCache = false;
00119 }
00120
00121 # Check the local repo
00122 $image = $this->localRepo->findFile( $title, $options );
00123 if ( $image ) {
00124 if ( $useCache ) {
00125 $cacheEntry = $image;
00126 }
00127 return $image;
00128 }
00129
00130 # Check the foreign repos
00131 foreach ( $this->foreignRepos as $repo ) {
00132 $image = $repo->findFile( $title, $options );
00133 if ( $image ) {
00134 if ( $useCache ) {
00135 $cacheEntry = $image;
00136 }
00137 return $image;
00138 }
00139 }
00140 # Not found, do not override negative cache
00141 return false;
00142 }
00143
00144 function findFiles( $inputItems ) {
00145 if ( !$this->reposInitialised ) {
00146 $this->initialiseRepos();
00147 }
00148
00149 $items = array();
00150 foreach ( $inputItems as $item ) {
00151 if ( !is_array( $item ) ) {
00152 $item = array( 'title' => $item );
00153 }
00154 if ( !( $item['title'] instanceof Title ) )
00155 $item['title'] = Title::makeTitleSafe( NS_FILE, $item['title'] );
00156 if ( $item['title'] )
00157 $items[$item['title']->getDBkey()] = $item;
00158 }
00159
00160 $images = $this->localRepo->findFiles( $items );
00161
00162 foreach ( $this->foreignRepos as $repo ) {
00163
00164 foreach ( $images as $name => $image ) {
00165 unset( $items[$name] );
00166 }
00167
00168 $images = array_merge( $images, $repo->findFiles( $items ) );
00169 }
00170 return $images;
00171 }
00172
00176 function checkRedirect( $title ) {
00177 if ( !$this->reposInitialised ) {
00178 $this->initialiseRepos();
00179 }
00180
00181 $redir = $this->localRepo->checkRedirect( $title );
00182 if( $redir ) {
00183 return $redir;
00184 }
00185 foreach ( $this->foreignRepos as $repo ) {
00186 $redir = $repo->checkRedirect( $title );
00187 if ( $redir ) {
00188 return $redir;
00189 }
00190 }
00191 return false;
00192 }
00193
00194 function findBySha1( $hash ) {
00195 if ( !$this->reposInitialised ) {
00196 $this->initialiseRepos();
00197 }
00198
00199 $result = $this->localRepo->findBySha1( $hash );
00200 foreach ( $this->foreignRepos as $repo )
00201 $result = array_merge( $result, $repo->findBySha1( $hash ) );
00202 return $result;
00203 }
00204
00208 function getRepo( $index ) {
00209 if ( !$this->reposInitialised ) {
00210 $this->initialiseRepos();
00211 }
00212 if ( $index === 'local' ) {
00213 return $this->localRepo;
00214 } elseif ( isset( $this->foreignRepos[$index] ) ) {
00215 return $this->foreignRepos[$index];
00216 } else {
00217 return false;
00218 }
00219 }
00223 function getRepoByName( $name ) {
00224 if ( !$this->reposInitialised ) {
00225 $this->initialiseRepos();
00226 }
00227 foreach ( $this->foreignRepos as $key => $repo ) {
00228 if ( $repo->name == $name)
00229 return $repo;
00230 }
00231 return false;
00232 }
00233
00238 function getLocalRepo() {
00239 return $this->getRepo( 'local' );
00240 }
00241
00249 function forEachForeignRepo( $callback, $params = array() ) {
00250 foreach( $this->foreignRepos as $repo ) {
00251 $args = array_merge( array( $repo ), $params );
00252 if( call_user_func_array( $callback, $args ) ) {
00253 return true;
00254 }
00255 }
00256 return false;
00257 }
00258
00263 function hasForeignRepos() {
00264 return (bool)$this->foreignRepos;
00265 }
00266
00270 function initialiseRepos() {
00271 if ( $this->reposInitialised ) {
00272 return;
00273 }
00274 $this->reposInitialised = true;
00275
00276 $this->localRepo = $this->newRepo( $this->localInfo );
00277 $this->foreignRepos = array();
00278 foreach ( $this->foreignInfo as $key => $info ) {
00279 $this->foreignRepos[$key] = $this->newRepo( $info );
00280 }
00281 }
00282
00286 protected function newRepo( $info ) {
00287 $class = $info['class'];
00288 return new $class( $info );
00289 }
00290
00295 function splitVirtualUrl( $url ) {
00296 if ( substr( $url, 0, 9 ) != 'mwrepo://' ) {
00297 throw new MWException( __METHOD__.': unknown protoocl' );
00298 }
00299
00300 $bits = explode( '/', substr( $url, 9 ), 3 );
00301 if ( count( $bits ) != 3 ) {
00302 throw new MWException( __METHOD__.": invalid mwrepo URL: $url" );
00303 }
00304 return $bits;
00305 }
00306
00307 function getFileProps( $fileName ) {
00308 if ( FileRepo::isVirtualUrl( $fileName ) ) {
00309 list( $repoName, , ) = $this->splitVirtualUrl( $fileName );
00310 if ( $repoName === '' ) {
00311 $repoName = 'local';
00312 }
00313 $repo = $this->getRepo( $repoName );
00314 return $repo->getFileProps( $fileName );
00315 } else {
00316 return File::getPropsFromPath( $fileName );
00317 }
00318 }
00319
00323 function trimCache() {
00324 while ( count( $this->cache ) >= self::MAX_CACHE_SIZE ) {
00325 reset( $this->cache );
00326 $key = key( $this->cache );
00327 wfDebug( __METHOD__.": evicting $key\n" );
00328 unset( $this->cache[$key] );
00329 }
00330 }
00331 }