23use InvalidArgumentException;
30use Wikimedia\Mime\MimeAnalyzer;
61 private const MAX_CACHE_SIZE = 500;
64 private $mimeAnalyzer;
82 MimeAnalyzer $mimeAnalyzer
86 $this->cache =
new MapCacheLRU( self::MAX_CACHE_SIZE );
88 $this->mimeAnalyzer = $mimeAnalyzer;
109 public function findFile( $title, $options = [] ) {
110 if ( !is_array( $options ) ) {
112 $options = [
'time' => $options ];
114 if ( isset( $options[
'bypassCache'] ) ) {
115 $options[
'latest'] = $options[
'bypassCache'];
117 if ( isset( $options[
'time'] ) && $options[
'time'] !==
false ) {
118 $options[
'time'] =
wfTimestamp( TS_MW, $options[
'time'] );
120 $options[
'time'] =
false;
123 if ( !$this->reposInitialised ) {
127 $title = File::normalizeTitle( $title );
133 $dbkey = $title->getDBkey();
134 $timeKey = is_string( $options[
'time'] ) ? $options[
'time'] :
'';
135 if ( empty( $options[
'ignoreRedirect'] )
136 && empty( $options[
'private'] )
137 && empty( $options[
'latest'] )
139 if ( $this->cache->hasField( $dbkey, $timeKey, 60 ) ) {
140 return $this->cache->getField( $dbkey, $timeKey );
147 # Check the local repo
148 $image = $this->localRepo->findFile( $title, $options );
150 # Check the foreign repos
152 foreach ( $this->foreignRepos as $repo ) {
153 $image = $repo->findFile( $title, $options );
160 $image = $image instanceof
File ? $image :
false;
161 # Cache file existence or non-existence
162 if ( $useCache && ( !$image || $image->isCacheable() ) ) {
163 $this->cache->setField( $dbkey, $timeKey, $image );
186 public function findFiles( array $inputItems, $flags = 0 ) {
187 if ( !$this->reposInitialised ) {
192 foreach ( $inputItems as $item ) {
193 if ( !is_array( $item ) ) {
194 $item = [
'title' => $item ];
196 $item[
'title'] = File::normalizeTitle( $item[
'title'] );
197 if ( $item[
'title'] ) {
198 $items[$item[
'title']->getDBkey()] = $item;
202 $images = $this->localRepo->findFiles( $items, $flags );
204 foreach ( $this->foreignRepos as $repo ) {
206 $items = array_diff_key( $items, $images );
207 $images = array_merge( $images, $repo->findFiles( $items, $flags ) );
219 if ( !$this->reposInitialised ) {
223 $title = File::normalizeTitle( $title );
225 $redir = $this->localRepo->checkRedirect( $title );
230 foreach ( $this->foreignRepos as $repo ) {
231 $redir = $repo->checkRedirect( $title );
249 if ( !$this->reposInitialised ) {
253 $file = $this->localRepo->findFileFromKey( $hash, $options );
255 foreach ( $this->foreignRepos as $repo ) {
256 $file = $repo->findFileFromKey( $hash, $options );
273 if ( !$this->reposInitialised ) {
277 $result = $this->localRepo->findBySha1( $hash );
278 foreach ( $this->foreignRepos as $repo ) {
279 $result = array_merge( $result, $repo->findBySha1( $hash ) );
281 usort( $result, [ File::class,
'compare' ] );
293 if ( !$this->reposInitialised ) {
297 $result = $this->localRepo->findBySha1s( $hashes );
298 foreach ( $this->foreignRepos as $repo ) {
299 $result = array_merge_recursive( $result, $repo->findBySha1s( $hashes ) );
302 foreach ( $result as $hash => $files ) {
303 usort( $result[$hash], [ File::class,
'compare' ] );
315 if ( !$this->reposInitialised ) {
318 if ( $index ===
'local' ) {
321 return $this->foreignRepos[$index] ??
false;
330 if ( !$this->reposInitialised ) {
333 foreach ( $this->foreignRepos as $repo ) {
334 if ( $repo->name == $name ) {
350 return $this->
getRepo(
'local' );
362 if ( !$this->reposInitialised ) {
365 foreach ( $this->foreignRepos as $repo ) {
366 if ( $callback( $repo, ...$params ) ) {
379 if ( !$this->reposInitialised ) {
389 if ( $this->reposInitialised ) {
392 $this->reposInitialised =
true;
394 $this->localRepo = $this->
newRepo( $this->localInfo );
395 $this->foreignRepos = [];
396 foreach ( $this->foreignInfo as $key => $info ) {
397 $this->foreignRepos[$key] = $this->
newRepo( $info );
409 return $this->
newRepo( $info + $this->localInfo );
418 $class = $info[
'class'];
422 return new $class( $info );
430 private function splitVirtualUrl(
$url ) {
431 if ( !str_starts_with(
$url,
'mwrepo://' ) ) {
432 throw new InvalidArgumentException( __METHOD__ .
': unknown protocol' );
435 $bits = explode(
'/', substr(
$url, 9 ), 3 );
436 if ( count( $bits ) != 3 ) {
437 throw new InvalidArgumentException( __METHOD__ .
": invalid mwrepo URL: $url" );
449 [ $repoName, , ] = $this->splitVirtualUrl( $fileName );
450 if ( $repoName ===
'' ) {
453 $repo = $this->
getRepo( $repoName );
455 return $repo->getFileProps( $fileName );
459 return $mwProps->getPropsFromPath( $fileName,
true );
468 if ( $title ==
null ) {
469 $this->cache->clear();
470 } elseif ( is_string( $title ) ) {
471 $this->cache->clear( $title );
473 $this->cache->clear( $title->getDBkey() );
479class_alias( RepoGroup::class,
'RepoGroup' );
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
MimeMagic helper wrapper.
Interface for objects (potentially) representing an editable wiki page.