MediaWiki  master
RepoGroup.php
Go to the documentation of this file.
1 <?php
26 
32 class RepoGroup {
34  protected $localRepo;
35 
37  protected $foreignRepos;
38 
40  protected $wanCache;
41 
43  protected $reposInitialised = false;
44 
46  protected $localInfo;
47 
49  protected $foreignInfo;
50 
52  protected $cache;
53 
55  private const MAX_CACHE_SIZE = 500;
56 
58  private $mimeAnalyzer;
59 
72  public function __construct(
73  $localInfo,
77  ) {
78  $this->localInfo = $localInfo;
79  $this->foreignInfo = $foreignInfo;
80  $this->cache = new MapCacheLRU( self::MAX_CACHE_SIZE );
81  $this->wanCache = $wanCache;
82  $this->mimeAnalyzer = $mimeAnalyzer;
83  }
84 
103  public function findFile( $title, $options = [] ) {
104  if ( !is_array( $options ) ) {
105  // MW 1.15 compat
106  $options = [ 'time' => $options ];
107  }
108  if ( isset( $options['bypassCache'] ) ) {
109  $options['latest'] = $options['bypassCache']; // b/c
110  }
111  $options += [ 'time' => false ];
112 
113  if ( !$this->reposInitialised ) {
114  $this->initialiseRepos();
115  }
116 
118  if ( !$title ) {
119  return false;
120  }
121 
122  # Check the cache
123  $dbkey = $title->getDBkey();
124  $timeKey = is_string( $options['time'] ) ? $options['time'] : '';
125  if ( empty( $options['ignoreRedirect'] )
126  && empty( $options['private'] )
127  && empty( $options['latest'] )
128  ) {
129  if ( $this->cache->hasField( $dbkey, $timeKey, 60 ) ) {
130  return $this->cache->getField( $dbkey, $timeKey );
131  }
132  $useCache = true;
133  } else {
134  $useCache = false;
135  }
136 
137  # Check the local repo
138  $image = $this->localRepo->findFile( $title, $options );
139 
140  # Check the foreign repos
141  if ( !$image ) {
142  foreach ( $this->foreignRepos as $repo ) {
143  $image = $repo->findFile( $title, $options );
144  if ( $image ) {
145  break;
146  }
147  }
148  }
149 
150  $image = $image instanceof File ? $image : false; // type sanity
151  # Cache file existence or non-existence
152  if ( $useCache && ( !$image || $image->isCacheable() ) ) {
153  $this->cache->setField( $dbkey, $timeKey, $image );
154  }
155 
156  return $image;
157  }
158 
176  public function findFiles( array $inputItems, $flags = 0 ) {
177  if ( !$this->reposInitialised ) {
178  $this->initialiseRepos();
179  }
180 
181  $items = [];
182  foreach ( $inputItems as $item ) {
183  if ( !is_array( $item ) ) {
184  $item = [ 'title' => $item ];
185  }
186  $item['title'] = File::normalizeTitle( $item['title'] );
187  if ( $item['title'] ) {
188  $items[$item['title']->getDBkey()] = $item;
189  }
190  }
191 
192  $images = $this->localRepo->findFiles( $items, $flags );
193 
194  foreach ( $this->foreignRepos as $repo ) {
195  // Remove found files from $items
196  foreach ( $images as $name => $image ) {
197  unset( $items[$name] );
198  }
199 
200  $images = array_merge( $images, $repo->findFiles( $items, $flags ) );
201  }
202 
203  return $images;
204  }
205 
211  public function checkRedirect( $title ) {
212  if ( !$this->reposInitialised ) {
213  $this->initialiseRepos();
214  }
215 
217 
218  $redir = $this->localRepo->checkRedirect( $title );
219  if ( $redir ) {
220  return $redir;
221  }
222 
223  foreach ( $this->foreignRepos as $repo ) {
224  $redir = $repo->checkRedirect( $title );
225  if ( $redir ) {
226  return $redir;
227  }
228  }
229 
230  return false;
231  }
232 
241  public function findFileFromKey( $hash, $options = [] ) {
242  if ( !$this->reposInitialised ) {
243  $this->initialiseRepos();
244  }
245 
246  $file = $this->localRepo->findFileFromKey( $hash, $options );
247  if ( !$file ) {
248  foreach ( $this->foreignRepos as $repo ) {
249  $file = $repo->findFileFromKey( $hash, $options );
250  if ( $file ) {
251  break;
252  }
253  }
254  }
255 
256  return $file;
257  }
258 
265  public function findBySha1( $hash ) {
266  if ( !$this->reposInitialised ) {
267  $this->initialiseRepos();
268  }
269 
270  $result = $this->localRepo->findBySha1( $hash );
271  foreach ( $this->foreignRepos as $repo ) {
272  $result = array_merge( $result, $repo->findBySha1( $hash ) );
273  }
274  usort( $result, [ File::class, 'compare' ] );
275 
276  return $result;
277  }
278 
285  public function findBySha1s( array $hashes ) {
286  if ( !$this->reposInitialised ) {
287  $this->initialiseRepos();
288  }
289 
290  $result = $this->localRepo->findBySha1s( $hashes );
291  foreach ( $this->foreignRepos as $repo ) {
292  $result = array_merge_recursive( $result, $repo->findBySha1s( $hashes ) );
293  }
294  // sort the merged (and presorted) sublist of each hash
295  foreach ( $result as $hash => $files ) {
296  usort( $result[$hash], [ File::class, 'compare' ] );
297  }
298 
299  return $result;
300  }
301 
307  public function getRepo( $index ) {
308  if ( !$this->reposInitialised ) {
309  $this->initialiseRepos();
310  }
311  if ( $index === 'local' ) {
312  return $this->localRepo;
313  }
314  return $this->foreignRepos[$index] ?? false;
315  }
316 
322  public function getRepoByName( $name ) {
323  if ( !$this->reposInitialised ) {
324  $this->initialiseRepos();
325  }
326  foreach ( $this->foreignRepos as $repo ) {
327  if ( $repo->name == $name ) {
328  return $repo;
329  }
330  }
331 
332  return false;
333  }
334 
341  public function getLocalRepo() {
342  // @phan-suppress-next-line PhanTypeMismatchReturnSuperType
343  return $this->getRepo( 'local' );
344  }
345 
354  public function forEachForeignRepo( $callback, $params = [] ) {
355  if ( !$this->reposInitialised ) {
356  $this->initialiseRepos();
357  }
358  foreach ( $this->foreignRepos as $repo ) {
359  if ( $callback( $repo, ...$params ) ) {
360  return true;
361  }
362  }
363 
364  return false;
365  }
366 
371  public function hasForeignRepos() {
372  if ( !$this->reposInitialised ) {
373  $this->initialiseRepos();
374  }
375  return (bool)$this->foreignRepos;
376  }
377 
381  public function initialiseRepos() {
382  if ( $this->reposInitialised ) {
383  return;
384  }
385  $this->reposInitialised = true;
386 
387  $this->localRepo = $this->newRepo( $this->localInfo );
388  $this->foreignRepos = [];
389  foreach ( $this->foreignInfo as $key => $info ) {
390  $this->foreignRepos[$key] = $this->newRepo( $info );
391  }
392  }
393 
400  public function newCustomLocalRepo( $info = [] ) {
401  // @phan-suppress-next-line PhanTypeMismatchReturnSuperType
402  return $this->newRepo( $info + $this->localInfo );
403  }
404 
410  protected function newRepo( $info ) {
411  $class = $info['class'];
412 
413  $info['wanCache'] = $this->wanCache;
414 
415  return new $class( $info );
416  }
417 
424  private function splitVirtualUrl( $url ) {
425  if ( substr( $url, 0, 9 ) != 'mwrepo://' ) {
426  throw new MWException( __METHOD__ . ': unknown protocol' );
427  }
428 
429  $bits = explode( '/', substr( $url, 9 ), 3 );
430  if ( count( $bits ) != 3 ) {
431  throw new MWException( __METHOD__ . ": invalid mwrepo URL: $url" );
432  }
433 
434  return $bits;
435  }
436 
441  public function getFileProps( $fileName ) {
442  if ( FileRepo::isVirtualUrl( $fileName ) ) {
443  list( $repoName, /* $zone */, /* $rel */ ) = $this->splitVirtualUrl( $fileName );
444  if ( $repoName === '' ) {
445  $repoName = 'local';
446  }
447  $repo = $this->getRepo( $repoName );
448 
449  return $repo->getFileProps( $fileName );
450  } else {
451  $mwProps = new MWFileProps( $this->mimeAnalyzer );
452 
453  return $mwProps->getPropsFromPath( $fileName, true );
454  }
455  }
456 
461  public function clearCache( $title = null ) {
462  if ( $title == null ) {
463  $this->cache->clear();
464  } elseif ( is_string( $title ) ) {
465  $this->cache->clear( $title );
466  } else {
467  $this->cache->clear( $title->getDBkey() );
468  }
469  }
470 }
RepoGroup\findFiles
findFiles(array $inputItems, $flags=0)
Search repositories for many files at once.
Definition: RepoGroup.php:176
Page\PageIdentity
Interface for objects (potentially) representing an editable wiki page.
Definition: PageIdentity.php:64
RepoGroup\hasForeignRepos
hasForeignRepos()
Does the installation have any foreign repos set up?
Definition: RepoGroup.php:371
RepoGroup\$cache
MapCacheLRU $cache
Definition: RepoGroup.php:52
MimeAnalyzer
Implements functions related to MIME types such as detection and mapping to file extension.
Definition: MimeAnalyzer.php:33
$file
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42
RepoGroup\newCustomLocalRepo
newCustomLocalRepo( $info=[])
Create a local repo with the specified option overrides.
Definition: RepoGroup.php:400
RepoGroup\$localRepo
LocalRepo $localRepo
Definition: RepoGroup.php:34
File\normalizeTitle
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:205
RepoGroup\findBySha1s
findBySha1s(array $hashes)
Find all instances of files with this keys.
Definition: RepoGroup.php:285
RepoGroup\findFile
findFile( $title, $options=[])
Search repositories for an image.
Definition: RepoGroup.php:103
FileRepo
Base class for file repositories.
Definition: FileRepo.php:45
RepoGroup\$reposInitialised
bool $reposInitialised
Definition: RepoGroup.php:43
File
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition: File.php:66
MWException
MediaWiki exception.
Definition: MWException.php:29
RepoGroup\forEachForeignRepo
forEachForeignRepo( $callback, $params=[])
Call a function for each foreign repo, with the repo object as the first parameter.
Definition: RepoGroup.php:354
RepoGroup\clearCache
clearCache( $title=null)
Clear RepoGroup process cache used for finding a file.
Definition: RepoGroup.php:461
RepoGroup\$foreignInfo
array $foreignInfo
Definition: RepoGroup.php:49
RepoGroup\MAX_CACHE_SIZE
const MAX_CACHE_SIZE
Maximum number of cache items.
Definition: RepoGroup.php:55
MapCacheLRU
Handles a simple LRU key/value map with a maximum number of entries.
Definition: MapCacheLRU.php:36
$title
$title
Definition: testCompression.php:38
MWFileProps
MimeMagic helper wrapper.
Definition: MWFileProps.php:28
RepoGroup\splitVirtualUrl
splitVirtualUrl( $url)
Split a virtual URL into repo, zone and rel parts.
Definition: RepoGroup.php:424
RepoGroup\initialiseRepos
initialiseRepos()
Initialise the $repos array.
Definition: RepoGroup.php:381
RepoGroup\$wanCache
WANObjectCache $wanCache
Definition: RepoGroup.php:40
RepoGroup\newRepo
newRepo( $info)
Create a repo class based on an info structure.
Definition: RepoGroup.php:410
RepoGroup\$mimeAnalyzer
MimeAnalyzer $mimeAnalyzer
Definition: RepoGroup.php:58
RepoGroup\checkRedirect
checkRedirect( $title)
Interface for FileRepo::checkRedirect()
Definition: RepoGroup.php:211
RepoGroup\getLocalRepo
getLocalRepo()
Get the local repository, i.e.
Definition: RepoGroup.php:341
RepoGroup\$localInfo
array $localInfo
Definition: RepoGroup.php:46
WANObjectCache
Multi-datacenter aware caching interface.
Definition: WANObjectCache.php:128
RepoGroup\findFileFromKey
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:241
RepoGroup\findBySha1
findBySha1( $hash)
Find all instances of files with this key.
Definition: RepoGroup.php:265
RepoGroup\$foreignRepos
FileRepo[] $foreignRepos
Definition: RepoGroup.php:37
RepoGroup\__construct
__construct( $localInfo, $foreignInfo, WANObjectCache $wanCache, MimeAnalyzer $mimeAnalyzer)
Construct a group of file repositories.
Definition: RepoGroup.php:72
FileRepo\isVirtualUrl
static isVirtualUrl( $url)
Determine if a string is an mwrepo:// URL.
Definition: FileRepo.php:290
RepoGroup
Prioritized list of file repositories.
Definition: RepoGroup.php:32
RepoGroup\getRepoByName
getRepoByName( $name)
Get the repo instance by its name.
Definition: RepoGroup.php:322
RepoGroup\getFileProps
getFileProps( $fileName)
Definition: RepoGroup.php:441
$hashes
$hashes
Definition: testCompression.php:71
RepoGroup\getRepo
getRepo( $index)
Get the repo instance with a given key.
Definition: RepoGroup.php:307
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
LocalRepo
A repository that stores files in the local filesystem and registers them in the wiki's own database.
Definition: LocalRepo.php:41