6use InvalidArgumentException;
10use UnexpectedValueException;
89 'LateJSConfigVarNames',
90 'TempUserSerialProviders',
91 'TempUserSerialMappings',
92 'DatabaseVirtualDomains',
93 'UserOptionsStoreProviders',
94 'NotificationHandlers',
95 'NotificationMiddleware',
96 'RecentChangeSources',
106 'wgAddGroups' =>
'array_merge_recursive',
107 'wgAuthManagerAutoConfig' =>
'array_plus_2d',
108 'wgCapitalLinkOverrides' =>
'array_plus',
109 'wgExtraGenderNamespaces' =>
'array_plus',
110 'wgGrantPermissions' =>
'array_plus_2d',
111 'wgGroupPermissions' =>
'array_plus_2d',
112 'wgHooks' =>
'array_merge_recursive',
113 'wgNamespaceContentModels' =>
'array_plus',
114 'wgNamespaceProtection' =>
'array_plus',
115 'wgNamespacesWithSubpages' =>
'array_plus',
116 'wgPasswordPolicy' =>
'array_merge_recursive',
117 'wgRateLimits' =>
'array_plus_2d',
118 'wgRemoveGroups' =>
'array_merge_recursive',
119 'wgRevokePermissions' =>
'array_plus_2d',
145 'load_composer_autoloader',
150 'AutoloadNamespaces',
151 'ExtensionMessagesFiles',
152 'TranslationAliasesDirs',
153 'ForeignResourcesDir',
155 'DomainEventIngresses',
156 'MessagePosterModule',
160 'ResourceFileModulePaths',
161 'ResourceModuleSkinStyles',
163 'ServiceWiringFiles',
174 'wgExtensionMessagesFiles' => [],
175 'wgRestAPIAdditionalRouteFiles' => [],
176 'wgMessagesDirs' => [],
177 'TranslationAliasesDirs' => [],
250 $json = file_get_contents(
$path );
251 $info = json_decode( $json,
true );
254 throw new RuntimeException(
"Failed to load JSON data from $path" );
257 $this->
extractInfo( $path, $info, $info[
'manifest_version'] );
266 $dir = dirname(
$path );
279 if ( isset( $info[
'ServiceWiringFiles'] ) ) {
281 'wgServiceWiringFiles',
283 $info[
'ServiceWiringFiles']
287 if ( isset( $info[
'callback'] ) ) {
288 $this->callbacks[$name] = $info[
'callback'];
291 $this->extractAutoload( $info, $dir );
295 if ( $version >= 2 ) {
303 if ( isset( $info[
'ParsoidModules'] ) ) {
304 foreach ( $info[
'ParsoidModules'] as &$module ) {
305 if ( is_string( $module ) ) {
306 $className = $module;
308 'class' => $className,
311 $module[
'name'] ??= $name;
312 $module[
'extension-name'] = $name;
318 if ( $version >= 2 ) {
322 foreach ( $info as $key => $val ) {
324 if ( in_array( $key, self::$globalSettings ) ) {
329 if ( $key[0] ===
'@' ) {
333 if ( $version >= 2 ) {
335 if ( in_array( $key, self::CORE_ATTRIBS ) ) {
336 $this->
storeToArray( $path, $key, $val, $this->attributes );
340 if ( !in_array( $key, self::NOT_ATTRIBS )
341 && !in_array( $key, self::CREDIT_ATTRIBS )
355 if ( isset( $info[
'attributes'] ) ) {
356 foreach ( $info[
'attributes'] as $extName => $value ) {
365 foreach ( $this->globals as $key => $val ) {
366 if ( isset( self::MERGE_STRATEGIES[$key] ) ) {
372 foreach ( $this->extAttributes as $extName => $value ) {
374 if ( isset( $this->credits[$extName] ) ) {
375 foreach ( $value as $attrName => $attrValue ) {
378 $extName . $attrName,
383 unset( $this->extAttributes[$extName] );
396 'autoloaderClasses' =>
$autoload[
'classes'],
397 'autoloaderNS' =>
$autoload[
'namespaces'],
404 if ( !$includeDev || !isset( $info[
'dev-requires'] ) ) {
405 return $info[
'requires'] ?? [];
408 if ( !isset( $info[
'requires'] ) ) {
409 return $info[
'dev-requires'] ?? [];
419 $pick =
static function ( $a, $b ) {
422 } elseif ( $b ===
null ) {
429 $req = $info[
'requires'];
430 $dev = $info[
'dev-requires'];
431 if ( isset( $req[
'MediaWiki'] ) || isset( $dev[
'MediaWiki'] ) ) {
432 $merged[
'MediaWiki'] = $pick(
433 $req[
'MediaWiki'] ??
null,
434 $dev[
'MediaWiki'] ??
null
438 $platform = array_merge(
439 array_keys( $req[
'platform'] ?? [] ),
440 array_keys( $dev[
'platform'] ?? [] )
443 foreach ( $platform as $pkey ) {
444 if ( $pkey ===
'php' ) {
446 $req[
'platform'][
'php'] ??
null,
447 $dev[
'platform'][
'php'] ??
null
452 $value = $dev[
'platform'][$pkey] ?? $req[
'platform'][$pkey];
454 $merged[
'platform'][$pkey] = $value;
458 foreach ( [
'extensions',
'skins' ] as $thing ) {
459 $things = array_merge(
460 array_keys( $req[$thing] ?? [] ),
461 array_keys( $dev[$thing] ?? [] )
463 foreach ( $things as $name ) {
464 $merged[$thing][$name] = $pick(
465 $req[$thing][$name] ??
null,
466 $dev[$thing][$name] ??
null
486 private function setArrayHookHandler(
488 array $hookHandlersAttr,
492 if ( isset( $callback[
'handler'] ) ) {
493 $handlerName = $callback[
'handler'];
494 $handlerDefinition = $hookHandlersAttr[$handlerName] ??
false;
495 if ( !$handlerDefinition ) {
496 throw new UnexpectedValueException(
497 "Missing handler definition for $name in HookHandlers attribute in $path"
500 $callback[
'handler'] = $handlerDefinition;
501 $callback[
'extensionPath'] =
$path;
502 $this->attributes[
'Hooks'][$name][] = $callback;
504 foreach ( $callback as $callable ) {
505 if ( is_array( $callable ) ) {
506 if ( isset( $callable[
'handler'] ) ) {
507 $this->setArrayHookHandler( $callable, $hookHandlersAttr, $name,
$path );
509 $this->globals[
'wgHooks'][$name][] = $callable;
511 } elseif ( is_string( $callable ) ) {
512 $this->setStringHookHandler( $callable, $hookHandlersAttr, $name,
$path );
528 private function setStringHookHandler(
530 array $hookHandlersAttr,
534 if ( isset( $hookHandlersAttr[$callback] ) ) {
536 'handler' => $hookHandlersAttr[$callback],
537 'extensionPath' =>
$path
539 $this->attributes[
'Hooks'][$name][] = $handler;
541 $this->globals[
'wgHooks'][$name][] = $callback;
554 $extName = $info[
'name'];
555 if ( isset( $info[
'Hooks'] ) ) {
556 $hookHandlersAttr = [];
557 foreach ( $info[
'HookHandlers'] ?? [] as $name => $def ) {
558 $hookHandlersAttr[$name] = [
'name' =>
"$extName-$name" ] + $def;
560 foreach ( $info[
'Hooks'] as $name => $callback ) {
561 if ( is_string( $callback ) ) {
562 $this->setStringHookHandler( $callback, $hookHandlersAttr, $name,
$path );
563 } elseif ( is_array( $callback ) ) {
564 $this->setArrayHookHandler( $callback, $hookHandlersAttr, $name,
$path );
568 if ( isset( $info[
'DeprecatedHooks'] ) ) {
569 $deprecatedHooks = [];
570 foreach ( $info[
'DeprecatedHooks'] as $name => $deprecatedHookInfo ) {
571 $deprecatedHookInfo += [
'component' => $extName ];
572 $deprecatedHooks[$name] = $deprecatedHookInfo;
574 if ( isset( $this->attributes[
'DeprecatedHooks'] ) ) {
575 $this->attributes[
'DeprecatedHooks'] += $deprecatedHooks;
577 $this->attributes[
'DeprecatedHooks'] = $deprecatedHooks;
589 $this->attributes[
'DomainEventIngresses'] ??= [];
590 foreach ( $info[
'DomainEventIngresses'] ?? [] as $subscriber ) {
591 $subscriber[
'extensionPath'] =
$path;
592 $this->attributes[
'DomainEventIngresses'][] = $subscriber;
600 if ( isset( $info[
'namespaces'] ) ) {
601 foreach ( $info[
'namespaces'] as $ns ) {
602 if ( defined( $ns[
'constant'] ) ) {
605 $id = constant( $ns[
'constant'] );
609 $this->defines[ $ns[
'constant'] ] = $id;
611 if ( !( isset( $ns[
'conditional'] ) && $ns[
'conditional'] ) ) {
613 $this->attributes[
'ExtensionNamespaces'][$id] = $ns[
'name'];
615 if ( isset( $ns[
'movable'] ) && !$ns[
'movable'] ) {
616 $this->attributes[
'ImmovableNamespaces'][] = $id;
618 if ( isset( $ns[
'gender'] ) ) {
619 $this->globals[
'wgExtraGenderNamespaces'][$id] = $ns[
'gender'];
621 if ( isset( $ns[
'subpages'] ) && $ns[
'subpages'] ) {
622 $this->globals[
'wgNamespacesWithSubpages'][$id] =
true;
624 if ( isset( $ns[
'content'] ) && $ns[
'content'] ) {
625 $this->globals[
'wgContentNamespaces'][] = $id;
627 if ( isset( $ns[
'defaultcontentmodel'] ) ) {
628 $this->globals[
'wgNamespaceContentModels'][$id] = $ns[
'defaultcontentmodel'];
630 if ( isset( $ns[
'protection'] ) ) {
631 $this->globals[
'wgNamespaceProtection'][$id] = $ns[
'protection'];
633 if ( isset( $ns[
'capitallinkoverride'] ) ) {
634 $this->globals[
'wgCapitalLinkOverrides'][$id] = $ns[
'capitallinkoverride'];
636 if ( isset( $ns[
'includable'] ) && !$ns[
'includable'] ) {
637 $this->globals[
'wgNonincludableNamespaces'][] = $id;
644 $defaultPaths = $info[
'ResourceFileModulePaths'] ??
false;
645 if ( isset( $defaultPaths[
'localBasePath'] ) ) {
646 if ( $defaultPaths[
'localBasePath'] ===
'' ) {
648 $defaultPaths[
'localBasePath'] = $dir;
650 $defaultPaths[
'localBasePath'] =
"$dir/{$defaultPaths['localBasePath']}";
654 foreach ( [
'ResourceModules',
'ResourceModuleSkinStyles',
'OOUIThemePaths' ] as $setting ) {
655 if ( isset( $info[$setting] ) ) {
656 foreach ( $info[$setting] as $name => $data ) {
657 if ( isset( $data[
'localBasePath'] ) ) {
658 if ( $data[
'localBasePath'] ===
'' ) {
660 $data[
'localBasePath'] = $dir;
662 $data[
'localBasePath'] =
"$dir/{$data['localBasePath']}";
665 if ( $defaultPaths ) {
666 $data += $defaultPaths;
668 $this->attributes[$setting][$name] = $data;
673 if ( isset( $info[
'QUnitTestModule'] ) ) {
674 $data = $info[
'QUnitTestModule'];
675 if ( isset( $data[
'localBasePath'] ) ) {
676 if ( $data[
'localBasePath'] ===
'' ) {
678 $data[
'localBasePath'] = $dir;
680 $data[
'localBasePath'] =
"$dir/{$data['localBasePath']}";
683 $this->attributes[
'QUnitTestModule'][
"test.{$info['name']}"] = $data;
686 if ( isset( $info[
'MessagePosterModule'] ) ) {
687 $data = $info[
'MessagePosterModule'];
688 $basePath = $data[
'localBasePath'] ??
'';
689 $baseDir = $basePath ===
'' ? $dir :
"$dir/$basePath";
690 foreach ( $data[
'scripts'] ?? [] as $scripts ) {
691 $this->attributes[
'MessagePosterModule'][
'scripts'][] =
694 foreach ( $data[
'dependencies'] ?? [] as $dependency ) {
695 $this->attributes[
'MessagePosterModule'][
'dependencies'][] = $dependency;
701 if ( isset( $info[
'ExtensionMessagesFiles'] ) ) {
702 foreach ( $info[
'ExtensionMessagesFiles'] as &$file ) {
703 $file =
"$dir/$file";
705 $this->globals[
"wgExtensionMessagesFiles"] += $info[
'ExtensionMessagesFiles'];
711 if ( isset( $info[
'RestModuleFiles'] ) ) {
712 foreach ( $info[
'RestModuleFiles'] as &$file ) {
713 $this->globals[
"wg$var"][] =
"$dir/$file";
726 if ( isset( $info[
'MessagesDirs'] ) ) {
727 foreach ( $info[
'MessagesDirs'] as $name => $files ) {
728 foreach ( (array)$files as $file ) {
729 $this->globals[
"wgMessagesDirs"][$name][] =
"$dir/$file";
743 foreach ( $info[
'TranslationAliasesDirs'] ?? [] as $name => $files ) {
744 foreach ( (array)$files as $file ) {
745 $this->globals[
'wgTranslationAliasesDirs'][$name][] =
"$dir/$file";
757 if ( isset( $info[
'ValidSkinNames'] ) ) {
758 foreach ( $info[
'ValidSkinNames'] as $skinKey => $data ) {
759 if ( isset( $data[
'args'][0] ) ) {
760 $templateDirectory = $data[
'args'][0][
'templateDirectory'] ??
'templates';
761 $data[
'args'][0][
'templateDirectory'] = $dir .
'/' . $templateDirectory;
763 $this->globals[
'wgValidSkinNames'][$skinKey] = $data;
776 if ( isset( $info[
'RateLimits'] ) ) {
777 $rights = array_keys( $info[
'RateLimits'] );
779 if ( isset( $info[
'AvailableRights'] ) ) {
780 $rights = array_diff( $rights, $info[
'AvailableRights'] );
783 $this->globals[
'wgImplicitRights'] = array_merge(
784 $this->globals[
'wgImplicitRights'] ?? [],
795 if ( isset( $info[
'SkinLessImportPaths'] ) ) {
796 foreach ( $info[
'SkinLessImportPaths'] as $skin => $subpath ) {
797 $this->attributes[
'SkinLessImportPaths'][$skin] =
"$dir/$subpath";
814 foreach ( self::CREDIT_ATTRIBS as $attr ) {
815 if ( isset( $info[$attr] ) ) {
824 if ( isset( $this->credits[$name] ) ) {
825 $firstPath = $this->credits[$name][
'path'];
827 throw new InvalidArgumentException(
828 "It was attempted to load $name twice, from $firstPath and $secondPath."
838 if ( array_key_exists(
'ForeignResourcesDir', $info ) ) {
839 if ( !is_string( $info[
'ForeignResourcesDir'] ) ) {
840 throw new InvalidArgumentException(
"Incorrect ForeignResourcesDir type, must be a string (in $name)" );
842 $this->attributes[
'ForeignResourcesDir'][$name] =
"{$dir}/{$info['ForeignResourcesDir']}";
847 if ( isset( $info[
'InstallerTasks'] ) ) {
850 $schemaBasePath =
$path .
'/sql';
851 foreach ( $info[
'InstallerTasks'] as $taskSpec ) {
852 $this->attributes[
'InstallerTasks'][]
853 = $taskSpec + [
'schemaBasePath' => $schemaBasePath ];
866 if ( isset( $info[
'config'] ) ) {
867 if ( isset( $info[
'config'][
'_prefix'] ) ) {
868 $prefix = $info[
'config'][
'_prefix'];
869 unset( $info[
'config'][
'_prefix'] );
873 foreach ( $info[
'config'] as $key => $val ) {
874 if ( $key[0] !==
'@' ) {
875 $this->addConfigGlobal(
"$prefix$key", $val, $info[
'name'] );
890 private function applyPath( array $value,
string $dir,
bool $ensurePathSuffix =
false ): array {
893 foreach ( $value as $k => $v ) {
894 if ( $ensurePathSuffix && !str_ends_with( $v,
'/' ) ) {
897 $result[$k] = $dir .
'/' . $v;
912 $prefix = $info[
'config_prefix'] ??
'wg';
913 if ( isset( $info[
'config'] ) ) {
914 foreach ( $info[
'config'] as $key => $data ) {
915 if ( !array_key_exists(
'value', $data ) ) {
916 throw new UnexpectedValueException(
"Missing value for config $key" );
919 $value = $data[
'value'];
920 if ( isset( $data[
'path'] ) && $data[
'path'] ) {
921 if ( is_array( $value ) ) {
922 $value = $this->applyPath( $value, $dir );
924 $value =
"$dir/$value";
927 if ( isset( $data[
'merge_strategy'] ) ) {
928 $value[ExtensionRegistry::MERGE_STRATEGY] = $data[
'merge_strategy'];
930 $this->addConfigGlobal(
"$prefix$key", $value, $info[
'name'] );
931 $data[
'providedby'] = $info[
'name'];
932 if ( isset( $info[
'ConfigRegistry'][0] ) ) {
933 $data[
'configregistry'] = array_keys( $info[
'ConfigRegistry'] )[0];
946 private function addConfigGlobal( $key, $value, $extName ) {
947 if ( array_key_exists( $key, $this->globals ) ) {
948 throw new RuntimeException(
949 "The configuration setting '$key' was already set by MediaWiki core or"
950 .
" another extension, and cannot be set again by $extName." );
952 if ( isset( $value[ExtensionRegistry::MERGE_STRATEGY] ) &&
953 $value[ExtensionRegistry::MERGE_STRATEGY] ===
'array_merge_recursive' ) {
955 "Using the array_merge_recursive merge strategy in extension.json and skin.json" .
956 " was deprecated in MediaWiki 1.42",
960 $this->globals[$key] = $value;
964 foreach ( $paths as
$path ) {
965 $this->globals[$global][] =
"$dir/$path";
978 if ( !is_array( $value ) ) {
979 throw new InvalidArgumentException(
"The value for '$name' should be an array (from $path)" );
981 if ( isset( $array[$name] ) ) {
982 $array[$name] = array_merge_recursive( $array[$name], $value );
984 $array[$name] = $value;
999 if ( !is_array( $value ) ) {
1000 throw new InvalidArgumentException(
"The value for '$name' should be an array (from $path)" );
1002 if ( isset( $array[$name] ) ) {
1003 $array[$name] = array_merge( $array[$name], $value );
1005 $array[$name] = $value;
1024 $autoload = $this->autoload;
1026 if ( $includeDev ) {
1027 $autoload[
'classes'] += $this->autoloadDev[
'classes'];
1028 $autoload[
'namespaces'] += $this->autoloadDev[
'namespaces'];
1033 if ( !empty( $this->autoloadDev[
'files'] ) ) {
1036 $autoload[
'files'] = array_merge(
1038 $this->autoloadDev[
'files']
1046 private function extractAutoload( array $info,
string $dir ) {
1047 if ( isset( $info[
'load_composer_autoloader'] ) && $info[
'load_composer_autoloader'] ===
true ) {
1048 $file =
"$dir/vendor/autoload.php";
1049 if ( file_exists( $file ) ) {
1050 $this->autoload[
'files'][] = $file;
1054 if ( isset( $info[
'AutoloadClasses'] ) ) {
1055 $paths = $this->applyPath( $info[
'AutoloadClasses'], $dir );
1056 $this->autoload[
'classes'] += $paths;
1059 if ( isset( $info[
'AutoloadNamespaces'] ) ) {
1060 $paths = $this->applyPath( $info[
'AutoloadNamespaces'], $dir,
true );
1061 $this->autoload[
'namespaces'] += $paths;
1064 if ( isset( $info[
'TestAutoloadClasses'] ) ) {
1065 $paths = $this->applyPath( $info[
'TestAutoloadClasses'], $dir );
1066 $this->autoloadDev[
'classes'] += $paths;
1069 if ( isset( $info[
'TestAutoloadNamespaces'] ) ) {
1070 $paths = $this->applyPath( $info[
'TestAutoloadNamespaces'], $dir,
true );
1071 $this->autoloadDev[
'namespaces'] += $paths;
1077class_alias( ExtensionProcessor::class,
'ExtensionProcessor' );
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
if(!defined('MW_SETUP_CALLBACK'))
A class containing constants representing the names of configuration variables.
const HiddenPrefs
Name constant for the HiddenPrefs setting, for use with Config::get()
const DefaultUserOptions
Name constant for the DefaultUserOptions setting, for use with Config::get()
const FeedClasses
Name constant for the FeedClasses setting, for use with Config::get()
const AvailableRights
Name constant for the AvailableRights setting, for use with Config::get()
const APIListModules
Name constant for the APIListModules setting, for use with Config::get()
const APIFormatModules
Name constant for the APIFormatModules setting, for use with Config::get()
const ImplicitGroups
Name constant for the ImplicitGroups setting, for use with Config::get()
const RemoveCredentialsBlacklist
Name constant for the RemoveCredentialsBlacklist setting, for use with Config::get()
const LogRestrictions
Name constant for the LogRestrictions setting, for use with Config::get()
const ExtensionFunctions
Name constant for the ExtensionFunctions setting, for use with Config::get()
const ActionFilteredLogs
Name constant for the ActionFilteredLogs setting, for use with Config::get()
const RevokePermissions
Name constant for the RevokePermissions setting, for use with Config::get()
const RecentChangesFlags
Name constant for the RecentChangesFlags setting, for use with Config::get()
const GroupsRemoveFromSelf
Name constant for the GroupsRemoveFromSelf setting, for use with Config::get()
const Actions
Name constant for the Actions setting, for use with Config::get()
const CentralIdLookupProviders
Name constant for the CentralIdLookupProviders setting, for use with Config::get()
const ExtensionEntryPointListFiles
Name constant for the ExtensionEntryPointListFiles setting, for use with Config::get()
const APIModules
Name constant for the APIModules setting, for use with Config::get()
const LogNames
Name constant for the LogNames setting, for use with Config::get()
const SpecialPages
Name constant for the SpecialPages setting, for use with Config::get()
const UserRegistrationProviders
Name constant for the UserRegistrationProviders setting, for use with Config::get()
const AuthManagerAutoConfig
Name constant for the AuthManagerAutoConfig setting, for use with Config::get()
const FilterLogTypes
Name constant for the FilterLogTypes setting, for use with Config::get()
const LogTypes
Name constant for the LogTypes setting, for use with Config::get()
const ResourceLoaderSources
Name constant for the ResourceLoaderSources setting, for use with Config::get()
const LogHeaders
Name constant for the LogHeaders setting, for use with Config::get()
const JobClasses
Name constant for the JobClasses setting, for use with Config::get()
const RateLimits
Name constant for the RateLimits setting, for use with Config::get()
const MediaHandlers
Name constant for the MediaHandlers setting, for use with Config::get()
const OutputPipelineStages
Name constant for the OutputPipelineStages setting, for use with Config::get()
const GrantRiskGroups
Name constant for the GrantRiskGroups setting, for use with Config::get()
const GrantPermissionGroups
Name constant for the GrantPermissionGroups setting, for use with Config::get()
const GroupPermissions
Name constant for the GroupPermissions setting, for use with Config::get()
const AddGroups
Name constant for the AddGroups setting, for use with Config::get()
const ConfigRegistry
Name constant for the ConfigRegistry setting, for use with Config::get()
const FileExtensions
Name constant for the FileExtensions setting, for use with Config::get()
const SessionProviders
Name constant for the SessionProviders setting, for use with Config::get()
const RawHtmlMessages
Name constant for the RawHtmlMessages setting, for use with Config::get()
const LogActionsHandlers
Name constant for the LogActionsHandlers setting, for use with Config::get()
const LogActions
Name constant for the LogActions setting, for use with Config::get()
const APIPropModules
Name constant for the APIPropModules setting, for use with Config::get()
const PrivilegedGroups
Name constant for the PrivilegedGroups setting, for use with Config::get()
const APIMetaModules
Name constant for the APIMetaModules setting, for use with Config::get()
const GroupsAddToSelf
Name constant for the GroupsAddToSelf setting, for use with Config::get()
const ContentHandlers
Name constant for the ContentHandlers setting, for use with Config::get()
const GrantPermissions
Name constant for the GrantPermissions setting, for use with Config::get()
const ChangeCredentialsBlacklist
Name constant for the ChangeCredentialsBlacklist setting, for use with Config::get()
const ReauthenticateTime
Name constant for the ReauthenticateTime setting, for use with Config::get()
const RemoveGroups
Name constant for the RemoveGroups setting, for use with Config::get()
const PasswordPolicy
Name constant for the PasswordPolicy setting, for use with Config::get()
const ConditionalUserOptions
Name constant for the ConditionalUserOptions setting, for use with Config::get()
const RestAPIAdditionalRouteFiles
Name constant for the RestAPIAdditionalRouteFiles setting, for use with Config::get()