MediaWiki REL1_37
ExtensionProcessor.php
Go to the documentation of this file.
1<?php
2
3class ExtensionProcessor implements Processor {
4
10 protected static $globalSettings = [
11 'ActionFilteredLogs',
12 'Actions',
13 'AddGroups',
14 'APIFormatModules',
15 'APIListModules',
16 'APIMetaModules',
17 'APIModules',
18 'APIPropModules',
19 'AuthManagerAutoConfig',
20 'AvailableRights',
21 'CentralIdLookupProviders',
22 'ChangeCredentialsBlacklist',
23 'ConfigRegistry',
24 'ContentHandlers',
25 'DefaultUserOptions',
26 'ExtensionEntryPointListFiles',
27 'ExtensionFunctions',
28 'FeedClasses',
29 'FileExtensions',
30 'FilterLogTypes',
31 'GrantPermissionGroups',
32 'GrantPermissions',
33 'GroupPermissions',
34 'GroupsAddToSelf',
35 'GroupsRemoveFromSelf',
36 'HiddenPrefs',
37 'ImplicitGroups',
38 'JobClasses',
39 'LogActions',
40 'LogActionsHandlers',
41 'LogHeaders',
42 'LogNames',
43 'LogRestrictions',
44 'LogTypes',
45 'MediaHandlers',
46 'PasswordPolicy',
47 'RateLimits',
48 'RawHtmlMessages',
49 'ReauthenticateTime',
50 'RecentChangesFlags',
51 'RemoveCredentialsBlacklist',
52 'RemoveGroups',
53 'ResourceLoaderSources',
54 'RevokePermissions',
55 'SessionProviders',
56 'SpecialPages'
57 ];
58
64 protected const CORE_ATTRIBS = [
65 'ParsoidModules',
66 'RestRoutes',
67 'SkinOOUIThemes',
68 'SearchMappings',
69 'TrackingCategories',
70 ];
71
79 protected const MERGE_STRATEGIES = [
80 'wgAuthManagerAutoConfig' => 'array_plus_2d',
81 'wgCapitalLinkOverrides' => 'array_plus',
82 'wgExtraGenderNamespaces' => 'array_plus',
83 'wgGrantPermissions' => 'array_plus_2d',
84 'wgGroupPermissions' => 'array_plus_2d',
85 'wgHooks' => 'array_merge_recursive',
86 'wgNamespaceContentModels' => 'array_plus',
87 'wgNamespaceProtection' => 'array_plus',
88 'wgNamespacesWithSubpages' => 'array_plus',
89 'wgPasswordPolicy' => 'array_merge_recursive',
90 'wgRateLimits' => 'array_plus_2d',
91 'wgRevokePermissions' => 'array_plus_2d',
92 ];
93
99 protected const CREDIT_ATTRIBS = [
100 'type',
101 'author',
102 'description',
103 'descriptionmsg',
104 'license-name',
105 'name',
106 'namemsg',
107 'url',
108 'version',
109 ];
110
117 protected const NOT_ATTRIBS = [
118 'callback',
119 'config',
120 'config_prefix',
121 'load_composer_autoloader',
122 'manifest_version',
123 'namespaces',
124 'requires',
125 'AutoloadClasses',
126 'ExtensionMessagesFiles',
127 'Hooks',
128 'MessagePosterModule',
129 'MessagesDirs',
130 'OOUIThemePaths',
131 'ParserTestFiles',
132 'QUnitTestModule',
133 'ResourceFileModulePaths',
134 'ResourceModuleSkinStyles',
135 'ResourceModules',
136 'ServiceWiringFiles',
137 ];
138
146 protected $globals = [
147 'wgExtensionMessagesFiles' => [],
148 'wgMessagesDirs' => [],
149 ];
150
156 protected $defines = [];
157
164 protected $callbacks = [];
165
169 protected $credits = [];
170
177 protected $attributes = [];
178
185 protected $extAttributes = [];
186
192 public function extractInfo( $path, array $info, $version ) {
193 $dir = dirname( $path );
194 $this->extractHooks( $info, $path );
195 $this->extractExtensionMessagesFiles( $dir, $info );
196 $this->extractMessagesDirs( $dir, $info );
197 $this->extractSkins( $dir, $info );
198 $this->extractSkinImportPaths( $dir, $info );
199 $this->extractNamespaces( $info );
200 $this->extractResourceLoaderModules( $dir, $info );
201 if ( isset( $info['ServiceWiringFiles'] ) ) {
203 'wgServiceWiringFiles',
204 $dir,
205 $info['ServiceWiringFiles']
206 );
207 }
208 if ( isset( $info['ParserTestFiles'] ) ) {
210 'wgParserTestFiles',
211 $dir,
212 $info['ParserTestFiles']
213 );
214 }
215 $name = $this->extractCredits( $path, $info );
216 if ( isset( $info['callback'] ) ) {
217 $this->callbacks[$name] = $info['callback'];
218 }
219
220 // config should be after all core globals are extracted,
221 // so duplicate setting detection will work fully
222 if ( $version >= 2 ) {
223 $this->extractConfig2( $info, $dir );
224 } else {
225 // $version === 1
226 $this->extractConfig1( $info );
227 }
228
229 // Record the extension name in the ParsoidModules property
230 if ( isset( $info['ParsoidModules'] ) ) {
231 foreach ( $info['ParsoidModules'] as &$module ) {
232 if ( is_string( $module ) ) {
233 $className = $module;
234 $module = [
235 'class' => $className,
236 ];
237 }
238 $module['name'] = $name;
239 }
240 }
241
242 if ( $version >= 2 ) {
243 $this->extractAttributes( $path, $info );
244 }
245
246 foreach ( $info as $key => $val ) {
247 // If it's a global setting,
248 if ( in_array( $key, self::$globalSettings ) ) {
249 $this->storeToArrayRecursive( $path, "wg$key", $val, $this->globals );
250 continue;
251 }
252 // Ignore anything that starts with a @
253 if ( $key[0] === '@' ) {
254 continue;
255 }
256
257 if ( $version >= 2 ) {
258 // Only allowed attributes are set
259 if ( in_array( $key, self::CORE_ATTRIBS ) ) {
260 $this->storeToArray( $path, $key, $val, $this->attributes );
261 }
262 } else {
263 // version === 1
264 if ( !in_array( $key, self::NOT_ATTRIBS )
265 && !in_array( $key, self::CREDIT_ATTRIBS )
266 ) {
267 // If it's not disallowed, it's an attribute
268 $this->storeToArrayRecursive( $path, $key, $val, $this->attributes );
269 }
270 }
271 }
272 }
273
278 protected function extractAttributes( $path, array $info ) {
279 if ( isset( $info['attributes'] ) ) {
280 foreach ( $info['attributes'] as $extName => $value ) {
281 $this->storeToArrayRecursive( $path, $extName, $value, $this->extAttributes );
282 }
283 }
284 }
285
286 public function getExtractedInfo() {
287 // Make sure the merge strategies are set
288 foreach ( $this->globals as $key => $val ) {
289 if ( isset( self::MERGE_STRATEGIES[$key] ) ) {
290 $this->globals[$key][ExtensionRegistry::MERGE_STRATEGY] = self::MERGE_STRATEGIES[$key];
291 }
292 }
293
294 // Merge $this->extAttributes into $this->attributes depending on what is loaded
295 foreach ( $this->extAttributes as $extName => $value ) {
296 // Only set the attribute if $extName is loaded (and hence present in credits)
297 if ( isset( $this->credits[$extName] ) ) {
298 foreach ( $value as $attrName => $attrValue ) {
300 '', // Don't provide a path since it's impossible to generate an error here
301 $extName . $attrName,
302 $attrValue,
303 $this->attributes
304 );
305 }
306 unset( $this->extAttributes[$extName] );
307 }
308 }
309
310 return [
311 'globals' => $this->globals,
312 'defines' => $this->defines,
313 'callbacks' => $this->callbacks,
314 'credits' => $this->credits,
315 'attributes' => $this->attributes,
316 ];
317 }
318
319 public function getRequirements( array $info, $includeDev ) {
320 // Quick shortcuts
321 if ( !$includeDev || !isset( $info['dev-requires'] ) ) {
322 return $info['requires'] ?? [];
323 }
324
325 if ( !isset( $info['requires'] ) ) {
326 return $info['dev-requires'] ?? [];
327 }
328
329 // OK, we actually have to merge everything
330 $merged = [];
331
332 // Helper that combines version requirements by
333 // picking the non-null if one is, or combines
334 // the two. Note that it is not possible for
335 // both inputs to be null.
336 $pick = static function ( $a, $b ) {
337 if ( $a === null ) {
338 return $b;
339 } elseif ( $b === null ) {
340 return $a;
341 } else {
342 return "$a $b";
343 }
344 };
345
346 $req = $info['requires'];
347 $dev = $info['dev-requires'];
348 if ( isset( $req['MediaWiki'] ) || isset( $dev['MediaWiki'] ) ) {
349 $merged['MediaWiki'] = $pick(
350 $req['MediaWiki'] ?? null,
351 $dev['MediaWiki'] ?? null
352 );
353 }
354
355 $platform = array_merge(
356 array_keys( $req['platform'] ?? [] ),
357 array_keys( $dev['platform'] ?? [] )
358 );
359 if ( $platform ) {
360 foreach ( $platform as $pkey ) {
361 if ( $pkey === 'php' ) {
362 $value = $pick(
363 $req['platform']['php'] ?? null,
364 $dev['platform']['php'] ?? null
365 );
366 } else {
367 // Prefer dev value, but these should be constant
368 // anyways (ext-* and ability-*)
369 $value = $dev['platform'][$pkey] ?? $req['platform'][$pkey];
370 }
371 $merged['platform'][$pkey] = $value;
372 }
373 }
374
375 foreach ( [ 'extensions', 'skins' ] as $thing ) {
376 $things = array_merge(
377 array_keys( $req[$thing] ?? [] ),
378 array_keys( $dev[$thing] ?? [] )
379 );
380 foreach ( $things as $name ) {
381 $merged[$thing][$name] = $pick(
382 $req[$thing][$name] ?? null,
383 $dev[$thing][$name] ?? null
384 );
385 }
386 }
387 return $merged;
388 }
389
401 private function setArrayHookHandler(
402 array $callback,
403 array $hookHandlersAttr,
404 string $name,
405 string $path
406 ) {
407 if ( isset( $callback['handler'] ) ) {
408 $handlerName = $callback['handler'];
409 $handlerDefinition = $hookHandlersAttr[$handlerName] ?? false;
410 if ( !$handlerDefinition ) {
411 throw new UnexpectedValueException(
412 "Missing handler definition for $name in HookHandlers attribute in $path"
413 );
414 }
415 $callback['handler'] = $handlerDefinition;
416 $callback['extensionPath'] = $path;
417 $this->attributes['Hooks'][$name][] = $callback;
418 } else {
419 foreach ( $callback as $callable ) {
420 if ( is_array( $callable ) ) {
421 if ( isset( $callable['handler'] ) ) { // Non-legacy style handler
422 $this->setArrayHookHandler( $callable, $hookHandlersAttr, $name, $path );
423 } else { // Legacy style handler array
424 $this->globals['wgHooks'][$name][] = $callable;
425 }
426 } elseif ( is_string( $callable ) ) {
427 $this->setStringHookHandler( $callable, $hookHandlersAttr, $name, $path );
428 }
429 }
430 }
431 }
432
443 private function setStringHookHandler(
444 string $callback,
445 array $hookHandlersAttr,
446 string $name,
447 string $path
448 ) {
449 if ( isset( $hookHandlersAttr[$callback] ) ) {
450 $handler = [
451 'handler' => $hookHandlersAttr[$callback],
452 'extensionPath' => $path
453 ];
454 $this->attributes['Hooks'][$name][] = $handler;
455 } else { // legacy style handler
456 $this->globals['wgHooks'][$name][] = $callback;
457 }
458 }
459
468 protected function extractHooks( array $info, string $path ) {
469 $extName = $info['name'];
470 if ( isset( $info['Hooks'] ) ) {
471 $hookHandlersAttr = [];
472 foreach ( $info['HookHandlers'] ?? [] as $name => $def ) {
473 $hookHandlersAttr[$name] = [ 'name' => "$extName-$name" ] + $def;
474 }
475 foreach ( $info['Hooks'] as $name => $callback ) {
476 if ( is_string( $callback ) ) {
477 $this->setStringHookHandler( $callback, $hookHandlersAttr, $name, $path );
478 } elseif ( is_array( $callback ) ) {
479 $this->setArrayHookHandler( $callback, $hookHandlersAttr, $name, $path );
480 }
481 }
482 }
483 if ( isset( $info['DeprecatedHooks'] ) ) {
484 $deprecatedHooks = [];
485 foreach ( $info['DeprecatedHooks'] as $name => $deprecatedHookInfo ) {
486 $deprecatedHookInfo += [ 'component' => $extName ];
487 $deprecatedHooks[$name] = $deprecatedHookInfo;
488 }
489 if ( isset( $this->attributes['DeprecatedHooks'] ) ) {
490 $this->attributes['DeprecatedHooks'] += $deprecatedHooks;
491 } else {
492 $this->attributes['DeprecatedHooks'] = $deprecatedHooks;
493 }
494 }
495 }
496
502 protected function extractNamespaces( array $info ) {
503 if ( isset( $info['namespaces'] ) ) {
504 foreach ( $info['namespaces'] as $ns ) {
505 if ( defined( $ns['constant'] ) ) {
506 // If the namespace constant is already defined, use it.
507 // This allows namespace IDs to be overwritten locally.
508 $id = constant( $ns['constant'] );
509 } else {
510 $id = $ns['id'];
511 }
512 $this->defines[ $ns['constant'] ] = $id;
513
514 if ( !( isset( $ns['conditional'] ) && $ns['conditional'] ) ) {
515 // If it is not conditional, register it
516 $this->attributes['ExtensionNamespaces'][$id] = $ns['name'];
517 }
518 if ( isset( $ns['movable'] ) && !$ns['movable'] ) {
519 $this->attributes['ImmovableNamespaces'][] = $id;
520 }
521 if ( isset( $ns['gender'] ) ) {
522 $this->globals['wgExtraGenderNamespaces'][$id] = $ns['gender'];
523 }
524 if ( isset( $ns['subpages'] ) && $ns['subpages'] ) {
525 $this->globals['wgNamespacesWithSubpages'][$id] = true;
526 }
527 if ( isset( $ns['content'] ) && $ns['content'] ) {
528 $this->globals['wgContentNamespaces'][] = $id;
529 }
530 if ( isset( $ns['defaultcontentmodel'] ) ) {
531 $this->globals['wgNamespaceContentModels'][$id] = $ns['defaultcontentmodel'];
532 }
533 if ( isset( $ns['protection'] ) ) {
534 $this->globals['wgNamespaceProtection'][$id] = $ns['protection'];
535 }
536 if ( isset( $ns['capitallinkoverride'] ) ) {
537 $this->globals['wgCapitalLinkOverrides'][$id] = $ns['capitallinkoverride'];
538 }
539
540 }
541 }
542 }
543
544 protected function extractResourceLoaderModules( $dir, array $info ) {
545 $defaultPaths = $info['ResourceFileModulePaths'] ?? false;
546 if ( isset( $defaultPaths['localBasePath'] ) ) {
547 if ( $defaultPaths['localBasePath'] === '' ) {
548 // Avoid double slashes (e.g. /extensions/Example//path)
549 $defaultPaths['localBasePath'] = $dir;
550 } else {
551 $defaultPaths['localBasePath'] = "$dir/{$defaultPaths['localBasePath']}";
552 }
553 }
554
555 foreach ( [ 'ResourceModules', 'ResourceModuleSkinStyles', 'OOUIThemePaths' ] as $setting ) {
556 if ( isset( $info[$setting] ) ) {
557 foreach ( $info[$setting] as $name => $data ) {
558 if ( isset( $data['localBasePath'] ) ) {
559 if ( $data['localBasePath'] === '' ) {
560 // Avoid double slashes (e.g. /extensions/Example//path)
561 $data['localBasePath'] = $dir;
562 } else {
563 $data['localBasePath'] = "$dir/{$data['localBasePath']}";
564 }
565 }
566 if ( $defaultPaths ) {
567 $data += $defaultPaths;
568 }
569 $this->attributes[$setting][$name] = $data;
570 }
571 }
572 }
573
574 if ( isset( $info['QUnitTestModule'] ) ) {
575 $data = $info['QUnitTestModule'];
576 if ( isset( $data['localBasePath'] ) ) {
577 if ( $data['localBasePath'] === '' ) {
578 // Avoid double slashes (e.g. /extensions/Example//path)
579 $data['localBasePath'] = $dir;
580 } else {
581 $data['localBasePath'] = "$dir/{$data['localBasePath']}";
582 }
583 }
584 $this->attributes['QUnitTestModules']["test.{$info['name']}"] = $data;
585 }
586
587 if ( isset( $info['MessagePosterModule'] ) ) {
588 $data = $info['MessagePosterModule'];
589 $basePath = $data['localBasePath'] ?? '';
590 $baseDir = $basePath === '' ? $dir : "$dir/$basePath";
591 foreach ( $data['scripts'] ?? [] as $scripts ) {
592 $this->attributes['MessagePosterModule']['scripts'][] =
593 new ResourceLoaderFilePath( $scripts, $baseDir );
594 }
595 foreach ( $data['dependencies'] ?? [] as $dependency ) {
596 $this->attributes['MessagePosterModule']['dependencies'][] = $dependency;
597 }
598 }
599 }
600
601 protected function extractExtensionMessagesFiles( $dir, array $info ) {
602 if ( isset( $info['ExtensionMessagesFiles'] ) ) {
603 foreach ( $info['ExtensionMessagesFiles'] as &$file ) {
604 $file = "$dir/$file";
605 }
606 $this->globals["wgExtensionMessagesFiles"] += $info['ExtensionMessagesFiles'];
607 }
608 }
609
617 protected function extractMessagesDirs( $dir, array $info ) {
618 if ( isset( $info['MessagesDirs'] ) ) {
619 foreach ( $info['MessagesDirs'] as $name => $files ) {
620 foreach ( (array)$files as $file ) {
621 $this->globals["wgMessagesDirs"][$name][] = "$dir/$file";
622 }
623 }
624 }
625 }
626
633 protected function extractSkins( $dir, array $info ) {
634 if ( isset( $info['ValidSkinNames'] ) ) {
635 foreach ( $info['ValidSkinNames'] as $skinKey => $data ) {
636 if ( isset( $data['args'][0]['templateDirectory'] ) ) {
637 $templateDirectory = $data['args'][0]['templateDirectory'];
638 $correctedPath = $dir . '/' . $templateDirectory;
639 // Historically the template directory was relative to core
640 // but it really should've been relative to the skin directory.
641 // If the path exists relative to the skin directory, assume that
642 // is what was intended. Otherwise fall back on the previous behavior
643 // of having it relative to core.
644 if ( is_dir( $correctedPath ) ) {
645 $data['args'][0]['templateDirectory'] = $correctedPath;
646 } else {
647 $data['args'][0]['templateDirectory'] = $templateDirectory;
649 'Template directory should be relative to skin or omitted.',
650 '1.37'
651 );
652 }
653 } elseif ( isset( $data['args'][0] ) ) {
654 // If not set, we set a sensible default.
655 $data['args'][0]['templateDirectory'] = $dir . '/templates';
656 }
657 $this->globals['wgValidSkinNames'][$skinKey] = $data;
658 }
659 }
660 }
661
666 protected function extractSkinImportPaths( $dir, array $info ) {
667 if ( isset( $info['SkinLessImportPaths'] ) ) {
668 foreach ( $info['SkinLessImportPaths'] as $skin => $subpath ) {
669 $this->attributes['SkinLessImportPaths'][$skin] = "$dir/$subpath";
670 }
671 }
672 }
673
680 protected function extractCredits( $path, array $info ) {
681 $credits = [
682 'path' => $path,
683 'type' => 'other',
684 ];
685 foreach ( self::CREDIT_ATTRIBS as $attr ) {
686 if ( isset( $info[$attr] ) ) {
687 $credits[$attr] = $info[$attr];
688 }
689 }
690
691 $name = $credits['name'];
692
693 // If someone is loading the same thing twice, throw
694 // a nice error (T121493)
695 if ( isset( $this->credits[$name] ) ) {
696 $firstPath = $this->credits[$name]['path'];
697 $secondPath = $credits['path'];
698 throw new Exception( "It was attempted to load $name twice, from $firstPath and $secondPath." );
699 }
700
701 $this->credits[$name] = $credits;
702
703 return $name;
704 }
705
712 protected function extractConfig1( array $info ) {
713 if ( isset( $info['config'] ) ) {
714 if ( isset( $info['config']['_prefix'] ) ) {
715 $prefix = $info['config']['_prefix'];
716 unset( $info['config']['_prefix'] );
717 } else {
718 $prefix = 'wg';
719 }
720 foreach ( $info['config'] as $key => $val ) {
721 if ( $key[0] !== '@' ) {
722 $this->addConfigGlobal( "$prefix$key", $val, $info['name'] );
723 }
724 }
725 }
726 }
727
735 protected function extractConfig2( array $info, $dir ) {
736 $prefix = $info['config_prefix'] ?? 'wg';
737 if ( isset( $info['config'] ) ) {
738 foreach ( $info['config'] as $key => $data ) {
739 if ( !array_key_exists( 'value', $data ) ) {
740 throw new UnexpectedValueException( "Missing value for config $key" );
741 }
742
743 $value = $data['value'];
744 if ( isset( $data['path'] ) && $data['path'] ) {
745 $callback = static function ( $value ) use ( $dir ) {
746 return "$dir/$value";
747 };
748 if ( is_array( $value ) ) {
749 $value = array_map( $callback, $value );
750 } else {
751 $value = $callback( $value );
752 }
753 }
754 if ( isset( $data['merge_strategy'] ) ) {
755 $value[ExtensionRegistry::MERGE_STRATEGY] = $data['merge_strategy'];
756 }
757 $this->addConfigGlobal( "$prefix$key", $value, $info['name'] );
758 $data['providedby'] = $info['name'];
759 if ( isset( $info['ConfigRegistry'][0] ) ) {
760 $data['configregistry'] = array_keys( $info['ConfigRegistry'] )[0];
761 }
762 }
763 }
764 }
765
773 private function addConfigGlobal( $key, $value, $extName ) {
774 if ( array_key_exists( $key, $this->globals ) ) {
775 throw new RuntimeException(
776 "The configuration setting '$key' was already set by MediaWiki core or"
777 . " another extension, and cannot be set again by $extName." );
778 }
779 $this->globals[$key] = $value;
780 }
781
782 protected function extractPathBasedGlobal( $global, $dir, $paths ) {
783 foreach ( $paths as $path ) {
784 $this->globals[$global][] = "$dir/$path";
785 }
786 }
787
797 protected function storeToArrayRecursive( $path, $name, $value, &$array ) {
798 if ( !is_array( $value ) ) {
799 throw new InvalidArgumentException( "The value for '$name' should be an array (from $path)" );
800 }
801 if ( isset( $array[$name] ) ) {
802 $array[$name] = array_merge_recursive( $array[$name], $value );
803 } else {
804 $array[$name] = $value;
805 }
806 }
807
817 protected function storeToArray( $path, $name, $value, &$array ) {
818 if ( !is_array( $value ) ) {
819 throw new InvalidArgumentException( "The value for '$name' should be an array (from $path)" );
820 }
821 if ( isset( $array[$name] ) ) {
822 $array[$name] = array_merge( $array[$name], $value );
823 } else {
824 $array[$name] = $value;
825 }
826 }
827
828 public function getExtraAutoloaderPaths( $dir, array $info ) {
829 $paths = [];
830 if ( isset( $info['load_composer_autoloader'] ) && $info['load_composer_autoloader'] === true ) {
831 $paths[] = "$dir/vendor/autoload.php";
832 }
833 return $paths;
834 }
835}
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.
An object to represent a path to a JavaScript/CSS file, along with a remote and local base path,...
Processors read associated arrays and register whatever is required.
Definition Processor.php:9
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition router.php:42