MediaWiki  master
RepoGroup.php
Go to the documentation of this file.
1 <?php
25 
31 class RepoGroup {
33  protected $localRepo;
34 
36  protected $foreignRepos;
37 
39  protected $wanCache;
40 
42  protected $reposInitialised = false;
43 
45  protected $localInfo;
46 
48  protected $foreignInfo;
49 
51  protected $cache;
52 
54  const MAX_CACHE_SIZE = 500;
55 
60  static function singleton() {
61  return MediaWikiServices::getInstance()->getRepoGroup();
62  }
63 
68  static function destroySingleton() {
69  MediaWikiServices::getInstance()->resetServiceForTesting( 'RepoGroup' );
70  }
71 
77  static function setSingleton( $instance ) {
78  $services = MediaWikiServices::getInstance();
79  $services->disableService( 'RepoGroup' );
80  $services->redefineService( 'RepoGroup',
81  function () use ( $instance ) {
82  return $instance;
83  }
84  );
85  }
86 
99  $this->localInfo = $localInfo;
100  $this->foreignInfo = $foreignInfo;
101  $this->cache = new MapCacheLRU( self::MAX_CACHE_SIZE );
102  $this->wanCache = $wanCache;
103  }
104 
121  function findFile( $title, $options = [] ) {
122  if ( !is_array( $options ) ) {
123  // MW 1.15 compat
124  $options = [ 'time' => $options ];
125  }
126  if ( isset( $options['bypassCache'] ) ) {
127  $options['latest'] = $options['bypassCache']; // b/c
128  }
129  $options += [ 'time' => false ];
130 
131  if ( !$this->reposInitialised ) {
132  $this->initialiseRepos();
133  }
134 
136  if ( !$title ) {
137  return false;
138  }
139 
140  # Check the cache
141  $dbkey = $title->getDBkey();
142  $timeKey = is_string( $options['time'] ) ? $options['time'] : '';
143  if ( empty( $options['ignoreRedirect'] )
144  && empty( $options['private'] )
145  && empty( $options['latest'] )
146  ) {
147  if ( $this->cache->hasField( $dbkey, $timeKey, 60 ) ) {
148  return $this->cache->getField( $dbkey, $timeKey );
149  }
150  $useCache = true;
151  } else {
152  $useCache = false;
153  }
154 
155  # Check the local repo
156  $image = $this->localRepo->findFile( $title, $options );
157 
158  # Check the foreign repos
159  if ( !$image ) {
160  foreach ( $this->foreignRepos as $repo ) {
161  $image = $repo->findFile( $title, $options );
162  if ( $image ) {
163  break;
164  }
165  }
166  }
167 
168  $image = $image instanceof File ? $image : false; // type sanity
169  # Cache file existence or non-existence
170  if ( $useCache && ( !$image || $image->isCacheable() ) ) {
171  $this->cache->setField( $dbkey, $timeKey, $image );
172  }
173 
174  return $image;
175  }
176 
194  function findFiles( array $inputItems, $flags = 0 ) {
195  if ( !$this->reposInitialised ) {
196  $this->initialiseRepos();
197  }
198 
199  $items = [];
200  foreach ( $inputItems as $item ) {
201  if ( !is_array( $item ) ) {
202  $item = [ 'title' => $item ];
203  }
204  $item['title'] = File::normalizeTitle( $item['title'] );
205  if ( $item['title'] ) {
206  $items[$item['title']->getDBkey()] = $item;
207  }
208  }
209 
210  $images = $this->localRepo->findFiles( $items, $flags );
211 
212  foreach ( $this->foreignRepos as $repo ) {
213  // Remove found files from $items
214  foreach ( $images as $name => $image ) {
215  unset( $items[$name] );
216  }
217 
218  $images = array_merge( $images, $repo->findFiles( $items, $flags ) );
219  }
220 
221  return $images;
222  }
223 
229  function checkRedirect( Title $title ) {
230  if ( !$this->reposInitialised ) {
231  $this->initialiseRepos();
232  }
233 
234  $redir = $this->localRepo->checkRedirect( $title );
235  if ( $redir ) {
236  return $redir;
237  }
238 
239  foreach ( $this->foreignRepos as $repo ) {
240  $redir = $repo->checkRedirect( $title );
241  if ( $redir ) {
242  return $redir;
243  }
244  }
245 
246  return false;
247  }
248 
257  function findFileFromKey( $hash, $options = [] ) {
258  if ( !$this->reposInitialised ) {
259  $this->initialiseRepos();
260  }
261 
262  $file = $this->localRepo->findFileFromKey( $hash, $options );
263  if ( !$file ) {
264  foreach ( $this->foreignRepos as $repo ) {
265  $file = $repo->findFileFromKey( $hash, $options );
266  if ( $file ) {
267  break;
268  }
269  }
270  }
271 
272  return $file;
273  }
274 
281  function findBySha1( $hash ) {
282  if ( !$this->reposInitialised ) {
283  $this->initialiseRepos();
284  }
285 
286  $result = $this->localRepo->findBySha1( $hash );
287  foreach ( $this->foreignRepos as $repo ) {
288  $result = array_merge( $result, $repo->findBySha1( $hash ) );
289  }
290  usort( $result, 'File::compare' );
291 
292  return $result;
293  }
294 
301  function findBySha1s( array $hashes ) {
302  if ( !$this->reposInitialised ) {
303  $this->initialiseRepos();
304  }
305 
306  $result = $this->localRepo->findBySha1s( $hashes );
307  foreach ( $this->foreignRepos as $repo ) {
308  $result = array_merge_recursive( $result, $repo->findBySha1s( $hashes ) );
309  }
310  // sort the merged (and presorted) sublist of each hash
311  foreach ( $result as $hash => $files ) {
312  usort( $result[$hash], 'File::compare' );
313  }
314 
315  return $result;
316  }
317 
323  function getRepo( $index ) {
324  if ( !$this->reposInitialised ) {
325  $this->initialiseRepos();
326  }
327  if ( $index === 'local' ) {
328  return $this->localRepo;
329  }
330  return $this->foreignRepos[$index] ?? false;
331  }
332 
338  function getRepoByName( $name ) {
339  if ( !$this->reposInitialised ) {
340  $this->initialiseRepos();
341  }
342  foreach ( $this->foreignRepos as $repo ) {
343  if ( $repo->name == $name ) {
344  return $repo;
345  }
346  }
347 
348  return false;
349  }
350 
357  function getLocalRepo() {
359  $repo = $this->getRepo( 'local' );
360 
361  return $repo;
362  }
363 
372  function forEachForeignRepo( $callback, $params = [] ) {
373  if ( !$this->reposInitialised ) {
374  $this->initialiseRepos();
375  }
376  foreach ( $this->foreignRepos as $repo ) {
377  if ( $callback( $repo, ...$params ) ) {
378  return true;
379  }
380  }
381 
382  return false;
383  }
384 
389  function hasForeignRepos() {
390  if ( !$this->reposInitialised ) {
391  $this->initialiseRepos();
392  }
393  return (bool)$this->foreignRepos;
394  }
395 
399  function initialiseRepos() {
400  if ( $this->reposInitialised ) {
401  return;
402  }
403  $this->reposInitialised = true;
404 
405  $this->localRepo = $this->newRepo( $this->localInfo );
406  $this->foreignRepos = [];
407  foreach ( $this->foreignInfo as $key => $info ) {
408  $this->foreignRepos[$key] = $this->newRepo( $info );
409  }
410  }
411 
417  protected function newRepo( $info ) {
418  $class = $info['class'];
419 
420  $info['wanCache'] = $this->wanCache;
421 
422  return new $class( $info );
423  }
424 
431  function splitVirtualUrl( $url ) {
432  if ( substr( $url, 0, 9 ) != 'mwrepo://' ) {
433  throw new MWException( __METHOD__ . ': unknown protocol' );
434  }
435 
436  $bits = explode( '/', substr( $url, 9 ), 3 );
437  if ( count( $bits ) != 3 ) {
438  throw new MWException( __METHOD__ . ": invalid mwrepo URL: $url" );
439  }
440 
441  return $bits;
442  }
443 
448  function getFileProps( $fileName ) {
449  if ( FileRepo::isVirtualUrl( $fileName ) ) {
450  list( $repoName, /* $zone */, /* $rel */ ) = $this->splitVirtualUrl( $fileName );
451  if ( $repoName === '' ) {
452  $repoName = 'local';
453  }
454  $repo = $this->getRepo( $repoName );
455 
456  return $repo->getFileProps( $fileName );
457  } else {
458  $mwProps = new MWFileProps( MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer() );
459 
460  return $mwProps->getPropsFromPath( $fileName, true );
461  }
462  }
463 
468  public function clearCache( Title $title = null ) {
469  if ( $title == null ) {
470  $this->cache->clear();
471  } else {
472  $this->cache->clear( $title->getDBkey() );
473  }
474  }
475 }
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42
findFiles(array $inputItems, $flags=0)
Search repositories for many files at once.
Definition: RepoGroup.php:194
findFile( $title, $options=[])
Search repositories for an image.
Definition: RepoGroup.php:121
bool $reposInitialised
Definition: RepoGroup.php:42
__construct( $localInfo, $foreignInfo, $wanCache)
Construct a group of file repositories.
Definition: RepoGroup.php:98
LocalRepo $localRepo
Definition: RepoGroup.php:33
findFileFromKey( $hash, $options=[])
Find an instance of the file with this key, created at the specified time Returns false if the file d...
Definition: RepoGroup.php:257
static destroySingleton()
Definition: RepoGroup.php:68
getLocalRepo()
Get the local repository, i.e.
Definition: RepoGroup.php:357
getRepoByName( $name)
Get the repo instance by its name.
Definition: RepoGroup.php:338
A helper class for throttling authentication attempts.
static setSingleton( $instance)
Definition: RepoGroup.php:77
newRepo( $info)
Create a repo class based on an info structure.
Definition: RepoGroup.php:417
FileRepo [] $foreignRepos
Definition: RepoGroup.php:36
splitVirtualUrl( $url)
Split a virtual URL into repo, zone and rel parts.
Definition: RepoGroup.php:431
initialiseRepos()
Initialise the $repos array.
Definition: RepoGroup.php:399
getRepo( $index)
Get the repo instance with a given key.
Definition: RepoGroup.php:323
hasForeignRepos()
Does the installation have any foreign repos set up?
Definition: RepoGroup.php:389
static singleton()
Definition: RepoGroup.php:60
static isVirtualUrl( $url)
Determine if a string is an mwrepo:// URL.
Definition: FileRepo.php:264
array $localInfo
Definition: RepoGroup.php:45
forEachForeignRepo( $callback, $params=[])
Call a function for each foreign repo, with the repo object as the first parameter.
Definition: RepoGroup.php:372
array $foreignInfo
Definition: RepoGroup.php:48
MapCacheLRU $cache
Definition: RepoGroup.php:51
checkRedirect(Title $title)
Interface for FileRepo::checkRedirect()
Definition: RepoGroup.php:229
const MAX_CACHE_SIZE
Maximum number of cache items.
Definition: RepoGroup.php:54
clearCache(Title $title=null)
Clear RepoGroup process cache used for finding a file.
Definition: RepoGroup.php:468
findBySha1s(array $hashes)
Find all instances of files with this keys.
Definition: RepoGroup.php:301
MimeMagic helper wrapper.
Definition: MWFileProps.php:28
findBySha1( $hash)
Find all instances of files with this key.
Definition: RepoGroup.php:281
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition: File.php:61
WANObjectCache $wanCache
Definition: RepoGroup.php:39
static normalizeTitle( $title, $exception=false)
Given a string or Title object return either a valid Title object with namespace NS_FILE or null...
Definition: File.php:194
getFileProps( $fileName)
Definition: RepoGroup.php:448