89 if ( self::$instance ===
null ) {
90 self::$instance =
new self();
99 public function queue( $path ) {
103 if ( $mtime ===
false ) {
104 if ( file_exists( $path ) ) {
105 $mtime = filemtime( $path );
107 throw new Exception(
"$path does not exist!" );
110 if ( $mtime ===
false ) {
111 $err = error_get_last();
112 throw new Exception(
"Couldn't stat $path: {$err['message']}" );
116 $this->queued[
$path] = $mtime;
125 if ( !$this->queued ) {
129 if ( $this->finished ) {
131 "The following paths tried to load late: "
132 . implode(
', ', array_keys( $this->queued ) )
145 $cache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
152 md5( json_encode( $this->queued + $versions ) )
154 $data =
$cache->get( $key );
162 $data[
'globals'][
'wgAutoloadClasses'] += $data[
'autoload'];
163 unset( $data[
'autoload'] );
166 $cache->set( $key, $data, 60 * 60 * 24 );
196 $this->finished =
true;
209 $autoloadClasses = [];
210 $autoloadNamespaces = [];
211 $autoloaderPaths = [];
214 $extDependencies = [];
217 foreach (
$queue as $path => $mtime ) {
218 $json = file_get_contents( $path );
219 if ( $json ===
false ) {
220 throw new Exception(
"Unable to read $path, does it exist?" );
222 $info = json_decode( $json,
true );
223 if ( !is_array( $info ) ) {
224 throw new Exception(
"$path is not a valid JSON file." );
227 if ( !isset( $info[
'manifest_version'] ) ) {
229 "{$info['name']}'s extension.json or skin.json does not have manifest_version",
234 $info[
'manifest_version'] = 1;
236 $version = $info[
'manifest_version'];
237 if ( $version < self::OLDEST_MANIFEST_VERSION || $version > self::MANIFEST_VERSION ) {
238 $incompatible[] =
"$path: unsupported manifest_version: {$version}";
241 $dir = dirname( $path );
242 if ( isset( $info[
'AutoloadClasses'] ) ) {
244 $GLOBALS[
'wgAutoloadClasses'] += $autoload;
245 $autoloadClasses += $autoload;
247 if ( isset( $info[
'AutoloadNamespaces'] ) ) {
248 $autoloadNamespaces += $this->
processAutoLoader( $dir, $info[
'AutoloadNamespaces'] );
253 $requires = $processor->getRequirements( $info );
256 if ( is_array( $requires ) && $requires && isset( $info[
'name'] ) ) {
257 $extDependencies[$info[
'name']] = $requires;
261 $autoloaderPaths = array_merge( $autoloaderPaths,
262 $processor->getExtraAutoloaderPaths( $dir, $info ) );
264 $processor->extractInfo( $path, $info, $version );
266 $data = $processor->getExtractedInfo();
267 $data[
'warnings'] = $warnings;
270 $incompatible = array_merge(
273 ->setLoadedExtensionsAndSkins( $data[
'credits'] )
274 ->checkArray( $extDependencies )
277 if ( $incompatible ) {
282 $data[
'globals'][
'wgAutoloadClasses'] = [];
283 $data[
'autoload'] = $autoloadClasses;
284 $data[
'autoloaderPaths'] = $autoloaderPaths;
285 $data[
'autoloaderNS'] = $autoloadNamespaces;
290 foreach ( $info[
'globals'] as $key => $val ) {
293 if ( is_array( $val ) && isset( $val[self::MERGE_STRATEGY] ) ) {
295 unset( $val[self::MERGE_STRATEGY] );
297 $mergeStrategy =
'array_merge';
307 if ( !is_array(
$GLOBALS[$key] ) || !is_array( $val ) ) {
312 switch ( $mergeStrategy ) {
313 case 'array_merge_recursive':
316 case 'array_replace_recursive':
319 case 'array_plus_2d':
329 throw new UnexpectedValueException(
"Unknown merge strategy '$mergeStrategy'" );
333 if ( isset( $info[
'autoloaderNS'] ) ) {
337 foreach ( $info[
'defines'] as $name => $val ) {
338 define( $name, $val );
340 foreach ( $info[
'autoloaderPaths'] as $path ) {
341 if ( file_exists( $path ) ) {
346 $this->loaded += $info[
'credits'];
347 if ( $info[
'attributes'] ) {
348 if ( !$this->attributes ) {
349 $this->attributes = $info[
'attributes'];
351 $this->attributes = array_merge_recursive( $this->attributes, $info[
'attributes'] );
355 foreach ( $info[
'callbacks'] as $name => $cb ) {
356 if ( !is_callable( $cb ) ) {
357 if ( is_array( $cb ) ) {
358 $cb =
'[ ' . implode(
', ', $cb ) .
' ]';
360 throw new UnexpectedValueException(
"callback '$cb' is not callable" );
362 call_user_func( $cb, $info[
'credits'][$name] );
374 public function load( $path ) {
376 $this->
queue( $path );
386 return isset( $this->loaded[$name] );
394 if ( isset( $this->attributes[$name] ) ) {
395 return $this->attributes[
$name];
419 foreach ( $files as &$file ) {
420 $file =
"$dir/$file";
int bool $wgExtensionInfoMTime
When loading extensions through the extension registration system, this can be used to invalidate the...
$wgVersion
MediaWiki version number.
$wgDevelopmentWarnings
If set to true MediaWiki will throw notices for some possible error conditions and for deprecated fun...
wfArrayPlus2d(array $baseArray, array $newValues)
Merges two (possibly) 2 dimensional arrays into the target array ($baseArray).
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
static string[] $psr4Namespaces
A BagOStuff object with no objects in it.
Copyright (C) 2018 Kunal Mehta legoktm@member.fsf.org
isLoaded( $name)
Whether a thing has been loaded.
array $queued
List of paths that should be loaded.
const MERGE_STRATEGY
Special key that defines the merge strategy.
getQueue()
Get the current load queue.
const MANIFEST_VERSION
Version of the highest supported manifest version Note: Update MANIFEST_VERSION_MW_VERSION when chang...
const OLDEST_MANIFEST_VERSION
Version of the oldest supported manifest version.
array $loaded
Array of loaded things, keyed by name, values are credits information.
const CACHE_VERSION
Bump whenever the registration cache needs resetting.
clearQueue()
Clear the current load queue.
static ExtensionRegistry $instance
const MANIFEST_VERSION_MW_VERSION
MediaWiki version constraint representing what the current highest MANIFEST_VERSION is supported in.
load( $path)
Loads and processes the given JSON file without delay.
const MEDIAWIKI_CORE
"requires" key that applies to MediaWiki core/$wgVersion
readFromQueue(array $queue)
Process a queue of extensions and return their extracted data.
exportExtractedData(array $info)
processAutoLoader( $dir, array $files)
Fully expand autoloader paths.
bool $finished
Whether we are done loading things.
getAllThings()
Get information about all things.
finish()
After this is called, no more extensions can be loaded.
array $attributes
Items in the JSON file that aren't being set as globals.
Provides functions to check a set of extensions with dependencies against a set of loaded extensions ...
Allows to change the fields on the form that will be generated $name
returning false will NOT prevent logging $e