MediaWiki  master
ExtensionProcessor.php
Go to the documentation of this file.
1 <?php
2 
5 
6 class ExtensionProcessor implements Processor {
7 
13  protected static $globalSettings = [
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
60  ];
61 
67  protected const CORE_ATTRIBS = [
68  'ParsoidModules',
69  'RestRoutes',
70  'SkinOOUIThemes',
71  'SearchMappings',
72  'TrackingCategories',
73  'TempUserSerialProviders',
74  'TempUserSerialMappings',
75  ];
76 
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',
97  ];
98 
104  protected const CREDIT_ATTRIBS = [
105  'type',
106  'author',
107  'description',
108  'descriptionmsg',
109  'license-name',
110  'name',
111  'namemsg',
112  'url',
113  'version',
114  ];
115 
122  protected const NOT_ATTRIBS = [
123  'callback',
124  'config',
125  'config_prefix',
126  'load_composer_autoloader',
127  'manifest_version',
128  'namespaces',
129  'requires',
130  'AutoloadClasses',
131  'ExtensionMessagesFiles',
132  'Hooks',
133  'MessagePosterModule',
134  'MessagesDirs',
135  'OOUIThemePaths',
136  'ParserTestFiles',
137  'QUnitTestModule',
138  'ResourceFileModulePaths',
139  'ResourceModuleSkinStyles',
140  'ResourceModules',
141  'ServiceWiringFiles',
142  ];
143 
151  protected $globals = [
152  'wgExtensionMessagesFiles' => [],
153  'wgMessagesDirs' => [],
154  ];
155 
161  protected $defines = [];
162 
169  protected $callbacks = [];
170 
174  protected $credits = [];
175 
182  protected $attributes = [];
183 
190  protected $extAttributes = [];
191 
197  public function extractInfo( $path, array $info, $version ) {
198  $dir = dirname( $path );
199  $this->extractHooks( $info, $path );
200  $this->extractExtensionMessagesFiles( $dir, $info );
201  $this->extractMessagesDirs( $dir, $info );
202  $this->extractSkins( $dir, $info );
203  $this->extractSkinImportPaths( $dir, $info );
204  $this->extractNamespaces( $info );
205  $this->extractResourceLoaderModules( $dir, $info );
206  if ( isset( $info['ServiceWiringFiles'] ) ) {
207  $this->extractPathBasedGlobal(
208  'wgServiceWiringFiles',
209  $dir,
210  $info['ServiceWiringFiles']
211  );
212  }
213  if ( isset( $info['ParserTestFiles'] ) ) {
214  $this->extractPathBasedGlobal(
215  'wgParserTestFiles',
216  $dir,
217  $info['ParserTestFiles']
218  );
219  }
220  $name = $this->extractCredits( $path, $info );
221  if ( isset( $info['callback'] ) ) {
222  $this->callbacks[$name] = $info['callback'];
223  }
224 
225  // config should be after all core globals are extracted,
226  // so duplicate setting detection will work fully
227  if ( $version >= 2 ) {
228  $this->extractConfig2( $info, $dir );
229  } else {
230  // $version === 1
231  $this->extractConfig1( $info );
232  }
233 
234  // Record the extension name in the ParsoidModules property
235  if ( isset( $info['ParsoidModules'] ) ) {
236  foreach ( $info['ParsoidModules'] as &$module ) {
237  if ( is_string( $module ) ) {
238  $className = $module;
239  $module = [
240  'class' => $className,
241  ];
242  }
243  $module['name'] = $name;
244  }
245  }
246 
247  if ( $version >= 2 ) {
248  $this->extractAttributes( $path, $info );
249  }
250 
251  foreach ( $info as $key => $val ) {
252  // If it's a global setting,
253  if ( in_array( $key, self::$globalSettings ) ) {
254  $this->storeToArrayRecursive( $path, "wg$key", $val, $this->globals );
255  continue;
256  }
257  // Ignore anything that starts with a @
258  if ( $key[0] === '@' ) {
259  continue;
260  }
261 
262  if ( $version >= 2 ) {
263  // Only allowed attributes are set
264  if ( in_array( $key, self::CORE_ATTRIBS ) ) {
265  $this->storeToArray( $path, $key, $val, $this->attributes );
266  }
267  } else {
268  // version === 1
269  if ( !in_array( $key, self::NOT_ATTRIBS )
270  && !in_array( $key, self::CREDIT_ATTRIBS )
271  ) {
272  // If it's not disallowed, it's an attribute
273  $this->storeToArrayRecursive( $path, $key, $val, $this->attributes );
274  }
275  }
276  }
277  }
278 
283  protected function extractAttributes( $path, array $info ) {
284  if ( isset( $info['attributes'] ) ) {
285  foreach ( $info['attributes'] as $extName => $value ) {
286  $this->storeToArrayRecursive( $path, $extName, $value, $this->extAttributes );
287  }
288  }
289  }
290 
291  public function getExtractedInfo() {
292  // Make sure the merge strategies are set
293  foreach ( $this->globals as $key => $val ) {
294  if ( isset( self::MERGE_STRATEGIES[$key] ) ) {
295  $this->globals[$key][ExtensionRegistry::MERGE_STRATEGY] = self::MERGE_STRATEGIES[$key];
296  }
297  }
298 
299  // Merge $this->extAttributes into $this->attributes depending on what is loaded
300  foreach ( $this->extAttributes as $extName => $value ) {
301  // Only set the attribute if $extName is loaded (and hence present in credits)
302  if ( isset( $this->credits[$extName] ) ) {
303  foreach ( $value as $attrName => $attrValue ) {
304  $this->storeToArrayRecursive(
305  '', // Don't provide a path since it's impossible to generate an error here
306  $extName . $attrName,
307  $attrValue,
308  $this->attributes
309  );
310  }
311  unset( $this->extAttributes[$extName] );
312  }
313  }
314 
315  return [
316  'globals' => $this->globals,
317  'defines' => $this->defines,
318  'callbacks' => $this->callbacks,
319  'credits' => $this->credits,
320  'attributes' => $this->attributes,
321  ];
322  }
323 
324  public function getRequirements( array $info, $includeDev ) {
325  // Quick shortcuts
326  if ( !$includeDev || !isset( $info['dev-requires'] ) ) {
327  return $info['requires'] ?? [];
328  }
329 
330  if ( !isset( $info['requires'] ) ) {
331  return $info['dev-requires'] ?? [];
332  }
333 
334  // OK, we actually have to merge everything
335  $merged = [];
336 
337  // Helper that combines version requirements by
338  // picking the non-null if one is, or combines
339  // the two. Note that it is not possible for
340  // both inputs to be null.
341  $pick = static function ( $a, $b ) {
342  if ( $a === null ) {
343  return $b;
344  } elseif ( $b === null ) {
345  return $a;
346  } else {
347  return "$a $b";
348  }
349  };
350 
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
357  );
358  }
359 
360  $platform = array_merge(
361  array_keys( $req['platform'] ?? [] ),
362  array_keys( $dev['platform'] ?? [] )
363  );
364  if ( $platform ) {
365  foreach ( $platform as $pkey ) {
366  if ( $pkey === 'php' ) {
367  $value = $pick(
368  $req['platform']['php'] ?? null,
369  $dev['platform']['php'] ?? null
370  );
371  } else {
372  // Prefer dev value, but these should be constant
373  // anyways (ext-* and ability-*)
374  $value = $dev['platform'][$pkey] ?? $req['platform'][$pkey];
375  }
376  $merged['platform'][$pkey] = $value;
377  }
378  }
379 
380  foreach ( [ 'extensions', 'skins' ] as $thing ) {
381  $things = array_merge(
382  array_keys( $req[$thing] ?? [] ),
383  array_keys( $dev[$thing] ?? [] )
384  );
385  foreach ( $things as $name ) {
386  $merged[$thing][$name] = $pick(
387  $req[$thing][$name] ?? null,
388  $dev[$thing][$name] ?? null
389  );
390  }
391  }
392  return $merged;
393  }
394 
406  private function setArrayHookHandler(
407  array $callback,
408  array $hookHandlersAttr,
409  string $name,
410  string $path
411  ) {
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"
418  );
419  }
420  $callback['handler'] = $handlerDefinition;
421  $callback['extensionPath'] = $path;
422  $this->attributes['Hooks'][$name][] = $callback;
423  } else {
424  foreach ( $callback as $callable ) {
425  if ( is_array( $callable ) ) {
426  if ( isset( $callable['handler'] ) ) { // Non-legacy style handler
427  $this->setArrayHookHandler( $callable, $hookHandlersAttr, $name, $path );
428  } else { // Legacy style handler array
429  $this->globals['wgHooks'][$name][] = $callable;
430  }
431  } elseif ( is_string( $callable ) ) {
432  $this->setStringHookHandler( $callable, $hookHandlersAttr, $name, $path );
433  }
434  }
435  }
436  }
437 
448  private function setStringHookHandler(
449  string $callback,
450  array $hookHandlersAttr,
451  string $name,
452  string $path
453  ) {
454  if ( isset( $hookHandlersAttr[$callback] ) ) {
455  $handler = [
456  'handler' => $hookHandlersAttr[$callback],
457  'extensionPath' => $path
458  ];
459  $this->attributes['Hooks'][$name][] = $handler;
460  } else { // legacy style handler
461  $this->globals['wgHooks'][$name][] = $callback;
462  }
463  }
464 
473  protected function extractHooks( array $info, string $path ) {
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;
479  }
480  foreach ( $info['Hooks'] as $name => $callback ) {
481  if ( is_string( $callback ) ) {
482  $this->setStringHookHandler( $callback, $hookHandlersAttr, $name, $path );
483  } elseif ( is_array( $callback ) ) {
484  $this->setArrayHookHandler( $callback, $hookHandlersAttr, $name, $path );
485  }
486  }
487  }
488  if ( isset( $info['DeprecatedHooks'] ) ) {
489  $deprecatedHooks = [];
490  foreach ( $info['DeprecatedHooks'] as $name => $deprecatedHookInfo ) {
491  $deprecatedHookInfo += [ 'component' => $extName ];
492  $deprecatedHooks[$name] = $deprecatedHookInfo;
493  }
494  if ( isset( $this->attributes['DeprecatedHooks'] ) ) {
495  $this->attributes['DeprecatedHooks'] += $deprecatedHooks;
496  } else {
497  $this->attributes['DeprecatedHooks'] = $deprecatedHooks;
498  }
499  }
500  }
501 
507  protected function extractNamespaces( array $info ) {
508  if ( isset( $info['namespaces'] ) ) {
509  foreach ( $info['namespaces'] as $ns ) {
510  if ( defined( $ns['constant'] ) ) {
511  // If the namespace constant is already defined, use it.
512  // This allows namespace IDs to be overwritten locally.
513  $id = constant( $ns['constant'] );
514  } else {
515  $id = $ns['id'];
516  }
517  $this->defines[ $ns['constant'] ] = $id;
518 
519  if ( !( isset( $ns['conditional'] ) && $ns['conditional'] ) ) {
520  // If it is not conditional, register it
521  $this->attributes['ExtensionNamespaces'][$id] = $ns['name'];
522  }
523  if ( isset( $ns['movable'] ) && !$ns['movable'] ) {
524  $this->attributes['ImmovableNamespaces'][] = $id;
525  }
526  if ( isset( $ns['gender'] ) ) {
527  $this->globals['wgExtraGenderNamespaces'][$id] = $ns['gender'];
528  }
529  if ( isset( $ns['subpages'] ) && $ns['subpages'] ) {
530  $this->globals['wgNamespacesWithSubpages'][$id] = true;
531  }
532  if ( isset( $ns['content'] ) && $ns['content'] ) {
533  $this->globals['wgContentNamespaces'][] = $id;
534  }
535  if ( isset( $ns['defaultcontentmodel'] ) ) {
536  $this->globals['wgNamespaceContentModels'][$id] = $ns['defaultcontentmodel'];
537  }
538  if ( isset( $ns['protection'] ) ) {
539  $this->globals['wgNamespaceProtection'][$id] = $ns['protection'];
540  }
541  if ( isset( $ns['capitallinkoverride'] ) ) {
542  $this->globals['wgCapitalLinkOverrides'][$id] = $ns['capitallinkoverride'];
543  }
544  if ( isset( $ns['includable'] ) && !$ns['includable'] ) {
545  $this->globals['wgNonincludableNamespaces'][] = $id;
546  }
547  }
548  }
549  }
550 
551  protected function extractResourceLoaderModules( $dir, array $info ) {
552  $defaultPaths = $info['ResourceFileModulePaths'] ?? false;
553  if ( isset( $defaultPaths['localBasePath'] ) ) {
554  if ( $defaultPaths['localBasePath'] === '' ) {
555  // Avoid double slashes (e.g. /extensions/Example//path)
556  $defaultPaths['localBasePath'] = $dir;
557  } else {
558  $defaultPaths['localBasePath'] = "$dir/{$defaultPaths['localBasePath']}";
559  }
560  }
561 
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'] === '' ) {
567  // Avoid double slashes (e.g. /extensions/Example//path)
568  $data['localBasePath'] = $dir;
569  } else {
570  $data['localBasePath'] = "$dir/{$data['localBasePath']}";
571  }
572  }
573  if ( $defaultPaths ) {
574  $data += $defaultPaths;
575  }
576  $this->attributes[$setting][$name] = $data;
577  }
578  }
579  }
580 
581  if ( isset( $info['QUnitTestModule'] ) ) {
582  $data = $info['QUnitTestModule'];
583  if ( isset( $data['localBasePath'] ) ) {
584  if ( $data['localBasePath'] === '' ) {
585  // Avoid double slashes (e.g. /extensions/Example//path)
586  $data['localBasePath'] = $dir;
587  } else {
588  $data['localBasePath'] = "$dir/{$data['localBasePath']}";
589  }
590  }
591  $this->attributes['QUnitTestModules']["test.{$info['name']}"] = $data;
592  }
593 
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'][] =
600  new FilePath( $scripts, $baseDir );
601  }
602  foreach ( $data['dependencies'] ?? [] as $dependency ) {
603  $this->attributes['MessagePosterModule']['dependencies'][] = $dependency;
604  }
605  }
606  }
607 
608  protected function extractExtensionMessagesFiles( $dir, array $info ) {
609  if ( isset( $info['ExtensionMessagesFiles'] ) ) {
610  foreach ( $info['ExtensionMessagesFiles'] as &$file ) {
611  $file = "$dir/$file";
612  }
613  $this->globals["wgExtensionMessagesFiles"] += $info['ExtensionMessagesFiles'];
614  }
615  }
616 
624  protected function extractMessagesDirs( $dir, array $info ) {
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";
629  }
630  }
631  }
632  }
633 
640  protected function extractSkins( $dir, array $info ) {
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;
646  // Historically the template directory was relative to core
647  // but it really should've been relative to the skin directory.
648  // If the path exists relative to the skin directory, assume that
649  // is what was intended. Otherwise fall back on the previous behavior
650  // of having it relative to core.
651  if ( is_dir( $correctedPath ) ) {
652  $data['args'][0]['templateDirectory'] = $correctedPath;
653  } else {
654  $data['args'][0]['templateDirectory'] = $templateDirectory;
656  'Template directory should be relative to skin or omitted for skin ' . $skinKey,
657  '1.37'
658  );
659  }
660  } elseif ( isset( $data['args'][0] ) ) {
661  // If not set, we set a sensible default.
662  $data['args'][0]['templateDirectory'] = $dir . '/templates';
663  }
664  $this->globals['wgValidSkinNames'][$skinKey] = $data;
665  }
666  }
667  }
668 
673  protected function extractSkinImportPaths( $dir, array $info ) {
674  if ( isset( $info['SkinLessImportPaths'] ) ) {
675  foreach ( $info['SkinLessImportPaths'] as $skin => $subpath ) {
676  $this->attributes['SkinLessImportPaths'][$skin] = "$dir/$subpath";
677  }
678  }
679  }
680 
687  protected function extractCredits( $path, array $info ) {
688  $credits = [
689  'path' => $path,
690  'type' => 'other',
691  ];
692  foreach ( self::CREDIT_ATTRIBS as $attr ) {
693  if ( isset( $info[$attr] ) ) {
694  $credits[$attr] = $info[$attr];
695  }
696  }
697 
698  $name = $credits['name'];
699 
700  // If someone is loading the same thing twice, throw
701  // a nice error (T121493)
702  if ( isset( $this->credits[$name] ) ) {
703  $firstPath = $this->credits[$name]['path'];
704  $secondPath = $credits['path'];
705  throw new Exception( "It was attempted to load $name twice, from $firstPath and $secondPath." );
706  }
707 
708  $this->credits[$name] = $credits;
709 
710  return $name;
711  }
712 
719  protected function extractConfig1( array $info ) {
720  if ( isset( $info['config'] ) ) {
721  if ( isset( $info['config']['_prefix'] ) ) {
722  $prefix = $info['config']['_prefix'];
723  unset( $info['config']['_prefix'] );
724  } else {
725  $prefix = 'wg';
726  }
727  foreach ( $info['config'] as $key => $val ) {
728  if ( $key[0] !== '@' ) {
729  $this->addConfigGlobal( "$prefix$key", $val, $info['name'] );
730  }
731  }
732  }
733  }
734 
742  protected function extractConfig2( array $info, $dir ) {
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" );
748  }
749 
750  $value = $data['value'];
751  if ( isset( $data['path'] ) && $data['path'] ) {
752  $callback = static function ( $value ) use ( $dir ) {
753  return "$dir/$value";
754  };
755  if ( is_array( $value ) ) {
756  $value = array_map( $callback, $value );
757  } else {
758  $value = $callback( $value );
759  }
760  }
761  if ( isset( $data['merge_strategy'] ) ) {
762  $value[ExtensionRegistry::MERGE_STRATEGY] = $data['merge_strategy'];
763  }
764  $this->addConfigGlobal( "$prefix$key", $value, $info['name'] );
765  $data['providedby'] = $info['name'];
766  if ( isset( $info['ConfigRegistry'][0] ) ) {
767  $data['configregistry'] = array_keys( $info['ConfigRegistry'] )[0];
768  }
769  }
770  }
771  }
772 
780  private function addConfigGlobal( $key, $value, $extName ) {
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." );
785  }
786  $this->globals[$key] = $value;
787  }
788 
789  protected function extractPathBasedGlobal( $global, $dir, $paths ) {
790  foreach ( $paths as $path ) {
791  $this->globals[$global][] = "$dir/$path";
792  }
793  }
794 
804  protected function storeToArrayRecursive( $path, $name, $value, &$array ) {
805  if ( !is_array( $value ) ) {
806  throw new InvalidArgumentException( "The value for '$name' should be an array (from $path)" );
807  }
808  if ( isset( $array[$name] ) ) {
809  $array[$name] = array_merge_recursive( $array[$name], $value );
810  } else {
811  $array[$name] = $value;
812  }
813  }
814 
824  protected function storeToArray( $path, $name, $value, &$array ) {
825  if ( !is_array( $value ) ) {
826  throw new InvalidArgumentException( "The value for '$name' should be an array (from $path)" );
827  }
828  if ( isset( $array[$name] ) ) {
829  $array[$name] = array_merge( $array[$name], $value );
830  } else {
831  $array[$name] = $value;
832  }
833  }
834 
835  public function getExtraAutoloaderPaths( $dir, array $info ) {
836  $paths = [];
837  if ( isset( $info['load_composer_autoloader'] ) && $info['load_composer_autoloader'] === true ) {
838  $paths[] = "$dir/vendor/autoload.php";
839  }
840  return $paths;
841  }
842 }
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.
An object to represent a path to a JavaScript/CSS file, along with a remote and local base path,...
Definition: FilePath.php:30
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