14 MainConfigNames::ActionFilteredLogs,
15 MainConfigNames::Actions,
16 MainConfigNames::AddGroups,
17 MainConfigNames::APIFormatModules,
18 MainConfigNames::APIListModules,
19 MainConfigNames::APIMetaModules,
20 MainConfigNames::APIModules,
21 MainConfigNames::APIPropModules,
22 MainConfigNames::AuthManagerAutoConfig,
23 MainConfigNames::AvailableRights,
24 MainConfigNames::CentralIdLookupProviders,
25 MainConfigNames::ChangeCredentialsBlacklist,
26 MainConfigNames::ConfigRegistry,
27 MainConfigNames::ContentHandlers,
28 MainConfigNames::DefaultUserOptions,
29 MainConfigNames::ExtensionEntryPointListFiles,
30 MainConfigNames::ExtensionFunctions,
31 MainConfigNames::FeedClasses,
32 MainConfigNames::FileExtensions,
33 MainConfigNames::FilterLogTypes,
34 MainConfigNames::GrantPermissionGroups,
35 MainConfigNames::GrantPermissions,
36 MainConfigNames::GroupPermissions,
37 MainConfigNames::GroupsAddToSelf,
38 MainConfigNames::GroupsRemoveFromSelf,
39 MainConfigNames::HiddenPrefs,
40 MainConfigNames::ImplicitGroups,
41 MainConfigNames::JobClasses,
42 MainConfigNames::LogActions,
43 MainConfigNames::LogActionsHandlers,
44 MainConfigNames::LogHeaders,
45 MainConfigNames::LogNames,
46 MainConfigNames::LogRestrictions,
47 MainConfigNames::LogTypes,
48 MainConfigNames::MediaHandlers,
49 MainConfigNames::PasswordPolicy,
50 MainConfigNames::RateLimits,
51 MainConfigNames::RawHtmlMessages,
52 MainConfigNames::ReauthenticateTime,
53 MainConfigNames::RecentChangesFlags,
54 MainConfigNames::RemoveCredentialsBlacklist,
55 MainConfigNames::RemoveGroups,
56 MainConfigNames::ResourceLoaderSources,
57 MainConfigNames::RevokePermissions,
58 MainConfigNames::SessionProviders,
59 MainConfigNames::SpecialPages
67 protected const CORE_ATTRIBS = [
73 'TempUserSerialProviders',
74 'TempUserSerialMappings',
84 protected const MERGE_STRATEGIES = [
85 'wgAuthManagerAutoConfig' =>
'array_plus_2d',
86 'wgCapitalLinkOverrides' =>
'array_plus',
87 'wgExtraGenderNamespaces' =>
'array_plus',
88 'wgGrantPermissions' =>
'array_plus_2d',
89 'wgGroupPermissions' =>
'array_plus_2d',
90 'wgHooks' =>
'array_merge_recursive',
91 'wgNamespaceContentModels' =>
'array_plus',
92 'wgNamespaceProtection' =>
'array_plus',
93 'wgNamespacesWithSubpages' =>
'array_plus',
94 'wgPasswordPolicy' =>
'array_merge_recursive',
95 'wgRateLimits' =>
'array_plus_2d',
96 'wgRevokePermissions' =>
'array_plus_2d',
104 protected const CREDIT_ATTRIBS = [
122 protected const NOT_ATTRIBS = [
126 'load_composer_autoloader',
131 'ExtensionMessagesFiles',
133 'MessagePosterModule',
138 'ResourceFileModulePaths',
139 'ResourceModuleSkinStyles',
141 'ServiceWiringFiles',
152 'wgExtensionMessagesFiles' => [],
153 'wgMessagesDirs' => [],
198 $dir = dirname(
$path );
206 if ( isset( $info[
'ServiceWiringFiles'] ) ) {
208 'wgServiceWiringFiles',
210 $info[
'ServiceWiringFiles']
213 if ( isset( $info[
'ParserTestFiles'] ) ) {
217 $info[
'ParserTestFiles']
221 if ( isset( $info[
'callback'] ) ) {
222 $this->callbacks[$name] = $info[
'callback'];
227 if ( $version >= 2 ) {
235 if ( isset( $info[
'ParsoidModules'] ) ) {
236 foreach ( $info[
'ParsoidModules'] as &$module ) {
237 if ( is_string( $module ) ) {
238 $className = $module;
240 'class' => $className,
243 $module[
'name'] = $name;
247 if ( $version >= 2 ) {
251 foreach ( $info as $key => $val ) {
253 if ( in_array( $key, self::$globalSettings ) ) {
258 if ( $key[0] ===
'@' ) {
262 if ( $version >= 2 ) {
264 if ( in_array( $key, self::CORE_ATTRIBS ) ) {
269 if ( !in_array( $key, self::NOT_ATTRIBS )
270 && !in_array( $key, self::CREDIT_ATTRIBS )
284 if ( isset( $info[
'attributes'] ) ) {
285 foreach ( $info[
'attributes'] as $extName => $value ) {
293 foreach ( $this->globals as $key => $val ) {
294 if ( isset( self::MERGE_STRATEGIES[$key] ) ) {
300 foreach ( $this->extAttributes as $extName => $value ) {
302 if ( isset( $this->credits[$extName] ) ) {
303 foreach ( $value as $attrName => $attrValue ) {
306 $extName . $attrName,
311 unset( $this->extAttributes[$extName] );
326 if ( !$includeDev || !isset( $info[
'dev-requires'] ) ) {
327 return $info[
'requires'] ?? [];
330 if ( !isset( $info[
'requires'] ) ) {
331 return $info[
'dev-requires'] ?? [];
341 $pick =
static function ( $a, $b ) {
344 } elseif ( $b ===
null ) {
351 $req = $info[
'requires'];
352 $dev = $info[
'dev-requires'];
353 if ( isset( $req[
'MediaWiki'] ) || isset( $dev[
'MediaWiki'] ) ) {
354 $merged[
'MediaWiki'] = $pick(
355 $req[
'MediaWiki'] ??
null,
356 $dev[
'MediaWiki'] ??
null
360 $platform = array_merge(
361 array_keys( $req[
'platform'] ?? [] ),
362 array_keys( $dev[
'platform'] ?? [] )
365 foreach ( $platform as $pkey ) {
366 if ( $pkey ===
'php' ) {
368 $req[
'platform'][
'php'] ??
null,
369 $dev[
'platform'][
'php'] ??
null
374 $value = $dev[
'platform'][$pkey] ?? $req[
'platform'][$pkey];
376 $merged[
'platform'][$pkey] = $value;
380 foreach ( [
'extensions',
'skins' ] as $thing ) {
381 $things = array_merge(
382 array_keys( $req[$thing] ?? [] ),
383 array_keys( $dev[$thing] ?? [] )
385 foreach ( $things as $name ) {
386 $merged[$thing][$name] = $pick(
387 $req[$thing][$name] ??
null,
388 $dev[$thing][$name] ??
null
408 array $hookHandlersAttr,
412 if ( isset( $callback[
'handler'] ) ) {
413 $handlerName = $callback[
'handler'];
414 $handlerDefinition = $hookHandlersAttr[$handlerName] ??
false;
415 if ( !$handlerDefinition ) {
416 throw new UnexpectedValueException(
417 "Missing handler definition for $name in HookHandlers attribute in $path"
420 $callback[
'handler'] = $handlerDefinition;
421 $callback[
'extensionPath'] =
$path;
422 $this->attributes[
'Hooks'][$name][] = $callback;
424 foreach ( $callback as $callable ) {
425 if ( is_array( $callable ) ) {
426 if ( isset( $callable[
'handler'] ) ) {
429 $this->globals[
'wgHooks'][$name][] = $callable;
431 } elseif ( is_string( $callable ) ) {
450 array $hookHandlersAttr,
454 if ( isset( $hookHandlersAttr[$callback] ) ) {
456 'handler' => $hookHandlersAttr[$callback],
457 'extensionPath' =>
$path
459 $this->attributes[
'Hooks'][$name][] = $handler;
461 $this->globals[
'wgHooks'][$name][] = $callback;
474 $extName = $info[
'name'];
475 if ( isset( $info[
'Hooks'] ) ) {
476 $hookHandlersAttr = [];
477 foreach ( $info[
'HookHandlers'] ?? [] as $name => $def ) {
478 $hookHandlersAttr[$name] = [
'name' =>
"$extName-$name" ] + $def;
480 foreach ( $info[
'Hooks'] as $name => $callback ) {
481 if ( is_string( $callback ) ) {
483 } elseif ( is_array( $callback ) ) {
488 if ( isset( $info[
'DeprecatedHooks'] ) ) {
489 $deprecatedHooks = [];
490 foreach ( $info[
'DeprecatedHooks'] as $name => $deprecatedHookInfo ) {
491 $deprecatedHookInfo += [
'component' => $extName ];
492 $deprecatedHooks[$name] = $deprecatedHookInfo;
494 if ( isset( $this->attributes[
'DeprecatedHooks'] ) ) {
495 $this->attributes[
'DeprecatedHooks'] += $deprecatedHooks;
497 $this->attributes[
'DeprecatedHooks'] = $deprecatedHooks;
508 if ( isset( $info[
'namespaces'] ) ) {
509 foreach ( $info[
'namespaces'] as $ns ) {
510 if ( defined( $ns[
'constant'] ) ) {
513 $id = constant( $ns[
'constant'] );
517 $this->defines[ $ns[
'constant'] ] = $id;
519 if ( !( isset( $ns[
'conditional'] ) && $ns[
'conditional'] ) ) {
521 $this->attributes[
'ExtensionNamespaces'][$id] = $ns[
'name'];
523 if ( isset( $ns[
'movable'] ) && !$ns[
'movable'] ) {
524 $this->attributes[
'ImmovableNamespaces'][] = $id;
526 if ( isset( $ns[
'gender'] ) ) {
527 $this->globals[
'wgExtraGenderNamespaces'][$id] = $ns[
'gender'];
529 if ( isset( $ns[
'subpages'] ) && $ns[
'subpages'] ) {
530 $this->globals[
'wgNamespacesWithSubpages'][$id] =
true;
532 if ( isset( $ns[
'content'] ) && $ns[
'content'] ) {
533 $this->globals[
'wgContentNamespaces'][] = $id;
535 if ( isset( $ns[
'defaultcontentmodel'] ) ) {
536 $this->globals[
'wgNamespaceContentModels'][$id] = $ns[
'defaultcontentmodel'];
538 if ( isset( $ns[
'protection'] ) ) {
539 $this->globals[
'wgNamespaceProtection'][$id] = $ns[
'protection'];
541 if ( isset( $ns[
'capitallinkoverride'] ) ) {
542 $this->globals[
'wgCapitalLinkOverrides'][$id] = $ns[
'capitallinkoverride'];
544 if ( isset( $ns[
'includable'] ) && !$ns[
'includable'] ) {
545 $this->globals[
'wgNonincludableNamespaces'][] = $id;
552 $defaultPaths = $info[
'ResourceFileModulePaths'] ??
false;
553 if ( isset( $defaultPaths[
'localBasePath'] ) ) {
554 if ( $defaultPaths[
'localBasePath'] ===
'' ) {
556 $defaultPaths[
'localBasePath'] = $dir;
558 $defaultPaths[
'localBasePath'] =
"$dir/{$defaultPaths['localBasePath']}";
562 foreach ( [
'ResourceModules',
'ResourceModuleSkinStyles',
'OOUIThemePaths' ] as $setting ) {
563 if ( isset( $info[$setting] ) ) {
564 foreach ( $info[$setting] as $name => $data ) {
565 if ( isset( $data[
'localBasePath'] ) ) {
566 if ( $data[
'localBasePath'] ===
'' ) {
568 $data[
'localBasePath'] = $dir;
570 $data[
'localBasePath'] =
"$dir/{$data['localBasePath']}";
573 if ( $defaultPaths ) {
574 $data += $defaultPaths;
576 $this->attributes[$setting][$name] = $data;
581 if ( isset( $info[
'QUnitTestModule'] ) ) {
582 $data = $info[
'QUnitTestModule'];
583 if ( isset( $data[
'localBasePath'] ) ) {
584 if ( $data[
'localBasePath'] ===
'' ) {
586 $data[
'localBasePath'] = $dir;
588 $data[
'localBasePath'] =
"$dir/{$data['localBasePath']}";
591 $this->attributes[
'QUnitTestModules'][
"test.{$info['name']}"] = $data;
594 if ( isset( $info[
'MessagePosterModule'] ) ) {
595 $data = $info[
'MessagePosterModule'];
596 $basePath = $data[
'localBasePath'] ??
'';
597 $baseDir = $basePath ===
'' ? $dir :
"$dir/$basePath";
598 foreach ( $data[
'scripts'] ?? [] as $scripts ) {
599 $this->attributes[
'MessagePosterModule'][
'scripts'][] =
602 foreach ( $data[
'dependencies'] ?? [] as $dependency ) {
603 $this->attributes[
'MessagePosterModule'][
'dependencies'][] = $dependency;
609 if ( isset( $info[
'ExtensionMessagesFiles'] ) ) {
610 foreach ( $info[
'ExtensionMessagesFiles'] as &
$file ) {
611 $file =
"$dir/$file";
613 $this->globals[
"wgExtensionMessagesFiles"] += $info[
'ExtensionMessagesFiles'];
625 if ( isset( $info[
'MessagesDirs'] ) ) {
626 foreach ( $info[
'MessagesDirs'] as $name => $files ) {
627 foreach ( (array)$files as
$file ) {
628 $this->globals[
"wgMessagesDirs"][$name][] =
"$dir/$file";
641 if ( isset( $info[
'ValidSkinNames'] ) ) {
642 foreach ( $info[
'ValidSkinNames'] as $skinKey => $data ) {
643 if ( isset( $data[
'args'][0][
'templateDirectory'] ) ) {
644 $templateDirectory = $data[
'args'][0][
'templateDirectory'];
645 $correctedPath = $dir .
'/' . $templateDirectory;
651 if ( is_dir( $correctedPath ) ) {
652 $data[
'args'][0][
'templateDirectory'] = $correctedPath;
654 $data[
'args'][0][
'templateDirectory'] = $templateDirectory;
656 'Template directory should be relative to skin or omitted for skin ' . $skinKey,
660 } elseif ( isset( $data[
'args'][0] ) ) {
662 $data[
'args'][0][
'templateDirectory'] = $dir .
'/templates';
664 $this->globals[
'wgValidSkinNames'][$skinKey] = $data;
674 if ( isset( $info[
'SkinLessImportPaths'] ) ) {
675 foreach ( $info[
'SkinLessImportPaths'] as $skin => $subpath ) {
676 $this->attributes[
'SkinLessImportPaths'][$skin] =
"$dir/$subpath";
692 foreach ( self::CREDIT_ATTRIBS as $attr ) {
693 if ( isset( $info[$attr] ) ) {
702 if ( isset( $this->credits[$name] ) ) {
703 $firstPath = $this->credits[$name][
'path'];
705 throw new Exception(
"It was attempted to load $name twice, from $firstPath and $secondPath." );
720 if ( isset( $info[
'config'] ) ) {
721 if ( isset( $info[
'config'][
'_prefix'] ) ) {
722 $prefix = $info[
'config'][
'_prefix'];
723 unset( $info[
'config'][
'_prefix'] );
727 foreach ( $info[
'config'] as $key => $val ) {
728 if ( $key[0] !==
'@' ) {
743 $prefix = $info[
'config_prefix'] ??
'wg';
744 if ( isset( $info[
'config'] ) ) {
745 foreach ( $info[
'config'] as $key => $data ) {
746 if ( !array_key_exists(
'value', $data ) ) {
747 throw new UnexpectedValueException(
"Missing value for config $key" );
750 $value = $data[
'value'];
751 if ( isset( $data[
'path'] ) && $data[
'path'] ) {
752 $callback =
static function ( $value ) use ( $dir ) {
753 return "$dir/$value";
755 if ( is_array( $value ) ) {
756 $value = array_map( $callback, $value );
758 $value = $callback( $value );
761 if ( isset( $data[
'merge_strategy'] ) ) {
765 $data[
'providedby'] = $info[
'name'];
766 if ( isset( $info[
'ConfigRegistry'][0] ) ) {
767 $data[
'configregistry'] = array_keys( $info[
'ConfigRegistry'] )[0];
781 if ( array_key_exists( $key, $this->globals ) ) {
782 throw new RuntimeException(
783 "The configuration setting '$key' was already set by MediaWiki core or"
784 .
" another extension, and cannot be set again by $extName." );
786 $this->globals[$key] = $value;
790 foreach ( $paths as
$path ) {
791 $this->globals[$global][] =
"$dir/$path";
805 if ( !is_array( $value ) ) {
806 throw new InvalidArgumentException(
"The value for '$name' should be an array (from $path)" );
808 if ( isset( $array[$name] ) ) {
809 $array[$name] = array_merge_recursive( $array[$name], $value );
811 $array[$name] = $value;
825 if ( !is_array( $value ) ) {
826 throw new InvalidArgumentException(
"The value for '$name' should be an array (from $path)" );
828 if ( isset( $array[$name] ) ) {
829 $array[$name] = array_merge( $array[$name], $value );
831 $array[$name] = $value;
837 if ( isset( $info[
'load_composer_autoloader'] ) && $info[
'load_composer_autoloader'] ===
true ) {
838 $paths[] =
"$dir/vendor/autoload.php";
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
extractHooks(array $info, string $path)
Extract hook information from Hooks and HookHandler attributes.
extractNamespaces(array $info)
Register namespaces with the appropriate global settings.
extractCredits( $path, array $info)
array $attributes
Any thing else in the $info that hasn't already been processed.
addConfigGlobal( $key, $value, $extName)
Helper function to set a value to a specific global, if it isn't set already.
callable[] $callbacks
Things to be called once registration of these extensions are done keyed by the name of the extension...
array $defines
Things that should be define()'d.
extractExtensionMessagesFiles( $dir, array $info)
extractConfig1(array $info)
Set configuration settings for manifest_version == 1.
array $globals
Stuff that is going to be set to $GLOBALS.
extractMessagesDirs( $dir, array $info)
Set message-related settings, which need to be expanded to use absolute paths.
extractConfig2(array $info, $dir)
Set configuration settings for manifest_version == 2.
extractResourceLoaderModules( $dir, array $info)
array $extAttributes
Extension attributes, keyed by name => settings.
extractSkins( $dir, array $info)
Extract skins and handle path correction for templateDirectory.
getExtraAutoloaderPaths( $dir, array $info)
Get the path for additional autoloaders, e.g.
extractAttributes( $path, array $info)
getRequirements(array $info, $includeDev)
Get the requirements for the provided info.
extractSkinImportPaths( $dir, array $info)
extractInfo( $path, array $info, $version)
storeToArray( $path, $name, $value, &$array)
Stores $value to $array; using array_merge() if $array already contains $name.
setStringHookHandler(string $callback, array $hookHandlersAttr, string $name, string $path)
When handler value is a string, set $wgHooks or Hooks attribute.
extractPathBasedGlobal( $global, $dir, $paths)
setArrayHookHandler(array $callback, array $hookHandlersAttr, string $name, string $path)
When handler value is an array, set $wgHooks or Hooks attribute Could be legacy hook e....
storeToArrayRecursive( $path, $name, $value, &$array)
Stores $value to $array; using array_merge_recursive() if $array already contains $name.
static array $globalSettings
Keys that should be set to $GLOBALS.
const MERGE_STRATEGY
Special key that defines the merge strategy.
A class containing constants representing the names of configuration variables.
Processors read associated arrays and register whatever is required.
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.