MediaWiki 1.38/New configuration system

In MediaWiki 1.38, we are introducing a new system for loading configuration into MediaWiki. For now, much of that system is still experimental, but some parts can already be tried out. Below is a brief overview of what's new.

Treat Config as Data, not Code
The motivation behind creating a new sysem of configuration is to make it easier to manage different sets of config for different purpose and environments. This could be a wiki farm, or runnign in multiple data centers, or managic testing scenarios and setting up development environments.

Two ideas lie at the foundation of the new design: It should be easy to combine configuration from multiple sources in a predictable way. And configuration should be data, not code.

This means we are moving away from managing configuration settings as global variables. For several years now, the preferred way to get the value of configuration settings has been via a Config object. Now we also want to make it so configuration can be defined and loaded without the need of global variables.

Of course, MediaWiki will stay backwards compatibility with the old way of doing things for some time to come. Also, complex setups will always need to be able to determine configuration dynamically, by running code. That will not go away, but it will hopefully become nicer.

Wiki Farms
With MediaWiki 1.38, we are introducing an experimental mechanism for multitenancy, which should make it much simpler to build wiki farms. To enable it, just set the  configuration setting to a directory containing one settings file for each site. These files can override any configruations, and should typically provide at least the   and   settings.

With this setting enabled, MediaWiki will determin the name of the file to load from this directory by looking at information provided by the web server: if the WIKI_NAME variable is set in the environment (e.g. via Apache's SetEnv directive), this will be used as the file name. Otherwise, the file name will be the host name as reported by the web server. Any dots in the name are subsituted by dashes, and the file extension is determined by the setting.

So, in the simplest case, if your wiki is accessible from  and , and  is set to be  , then the settings files for the two wikis would be foo-example-com.yaml and bar-example-com.yaml in that directory.

Note that this feature is experimental and may change or be removed in the next release. We would be greatful to hear from you whether this seems useful.

Experimental mode for loading LocalSettings.php
In the spirit of getting away from using global variables, we plan to in the future load LocalSettings.php not in the top level file scope, where every variable is atomatically a global variable. Inseatd, we plan to load LocalSettings.php in a separate scope, and provide the $wgXyz variables to it explicitly. Similarly, any variables set in LocalSettings.php will be detected and applied to the configuration.

In most cases, this will be entirely transparent, except for the small performance hit caused by copying around 700 variables. To try whether it works for you, set the  environment variable. Here are some things to watch out for: Please test this feature to make sure you will not have any difficulties when we switch to it per default. The more feedback we get on it now, the better!
 * When reading from a config variable, don't use the  keyword to access it. Config variables will be available in the file scope of LocalSettings.php, but not in the global scope. They will still be made available as global variables at the end of the initialization sequence, for backwards compatibility with any code that still reads from globals, but that only happens after all config has already been loaded.
 * Similarly, don't use the  keyword to define and write configuration variables. This is especially improtant if you define any closures or functions in your configuration. wither use the   keyword to import the variable into the closer's scope, or use a Config object to read configuration.
 * This only works for configuration variabls that start with "wg". Consequently, this doesn't work at all if you need any extensions that use a  other than "wg"!

Experimental support for LocalSettings.yaml
Instead of defining your wiki's configuration by setting variables in LocalSettings.php, you can now load a YAML (or JSON) file using the new YAML settings file format. To do this, set the  environment variable to the location of the configuration file you want to load.

Note that this is an experimental feature. We would love to hear how it works for you, but you should be aware that it is incomplete to a degree, and that some bits like exact structure of the settings file may still change without much warning.

One thing we have not quite figured out yet is how to make use of PHP constants for things like namespaces inside the YAML file. Simfony has a magic syntax for that, but we have not yet decided whether we want to use that. So for now, if you want to refer e.g. to the user namespace in a YAML file, you would have to use the number 2.

In any case, please try this out and report any issues you encounter. The more feedback we get, the better this feature will be once it becomes stable!

A word of caution though: do not put the YAML file in a location that is accessible from the web! in contrast to PHP files, YAML files can typically just be loaded as plain files from any browser. If you put the file in a place that is accessible from the web, like the one that contains LocalSettings.php, anyone who knows where to look will be able to see all secrets contained in that file, which may allow them to comprimize your wiki.

Using SettingsBuilder in LocalSettings.php
Configuration loading and merging in MediaWiki is now managed by the  class. The variable  can be used inside   to access the default instance of SettingsBuilder. However, beware that the interface of SettingsBuilder is still unstable and may change without notice.

The SettingsBuilder class offers the following methods for use in LocalSettings.php: Again, please keep in mind that this interface is experimental and subject to change without notice.
 * to load settings from a YAML or JSON file. Note that configuration loaded into the SettingsBuilder will generally not become available in the file scope of . However, you should not rely on this, as it depends on interactions with global variables in the background which is subject to change.
 * to update a single config setting. $value will be combined with any pre-existing value according to the merge strategy applicable to this variable.
 * to set a single config setting, overriding any previous values.
 * to get a Config object containing any configuration loaded so far.

How we Load Default Settings
The file currently sets a global variable for each of the over 700 configuration settings that MediaWiki supports. To get away from managing configuration as global variables, we are replacinging with a schema from which we then generate files for use at runtime. Defining a schema rather than just default values gives us a way to define a merge strategy for each setting, so we know how to combine arrays when combining configuration from multiple files.

On each request, the default values of the configuration settings are now read from, which contains a generated array that can be read quickly, making use of PHP's opcode cache. The default values are loaded into the SettingsBuilder (see above), though they are still being made available as global variables for now.

A backwards compatibility mode is available, incase this change causes any issues:  still exists, and MediaWiki can be told to load it as before by setting   as  an environment variable (e.g. using a  directive in  ) or as a PHP constant (e.g. via   in  ).

In 1.38, the configuration schema is defined in. From this schema we generate  as well as.

In 1.39 however, this will change again. Maintaining the configuration schema as YAML proved inconvenient, so we moved it into a PHP class called MainConfigSchema.

Merge Strategies
The idea of merge strategies that already existed for extension configuration has been extended to apply to all settings files. This is necessary when loading configuration from multiple sources, so we know how to combine array structures: in some should be replaced, or need to be merged as associative maps, while others have to be concatenated as lists. Having a configuration schema

Outlook
In the coming releases of MediaWiki, we plan to forther move away from relying on manipulating global variables for configuration. For example, we plan to: There are some upcoming changes that deserve acloser look:
 * Per default load LocalSettings.php in an isolated scope, as described above.
 * Consolidating the extension loading mechanism with settings loading.

MainConfigSchema
As described above, we have been working to move away from defining configuration defaults as global variables. After we found that maitaining the schema in is inconvenient, we are now defining the schema for each setting as a constant on the   class. Each schema is an associative array that follows the JSON Schema structure. It provides a default value, and optionally some additional information about the configuration variable. One important reasons for having schemas instead of just default values is the fact that we need to know how to combine array values, and PHP doesn't make this easy for us. Some arrays behave like lists, some are associative and behave like maps. Some need shallow mergig, some need deep merging. Having this information declared in a schea allows us to correctly combine configuration loaded from different sources.

However, while  is convenient for maintaining information about configuration variables, it is not ideal for using that information. For this reason, we created a set of maintenance scripts that will generate specialized files from the schema information in MainConfigSchema:

The  file continues to exist as a deprecated stub that puts the defaults defined by   into the local scope. It should however no longer be used, and will be removed in an upcoming release.
 * contains the schema information in a form optimized for fast loading. It is intended for internal use by MediaWiki core only.
 * contains a class that defines a constant for each configuration variable, similar to what MainConfigSchema. However, the value of the constant is just the name of the config variable. The idea is that these constants can be used with Config::get and with ServiceOptions, to provide a safe way to refer to config settings. They also provide a way to discover the location of the schema and primary documentation.
 * is a JSON Schema file that can be used to validate config files written in JSON or YAML. This is considered documentation and is not used by MediaWiki itself.

Config Presets for End-To-End Testing
Introduce config "presets" for testing environments. Presets are settings files that can be activated using an HTTP header, to allow end-to-end tests to run against specific setups.

TBD!

Further Ideas

 * Stop exporting configuration settings to global variables. The  variables will still work in LocalSettings.php, but not in application code or extensions. Of course, we will be done carefully, to avoid unnecessary disruption.
 * Replace ConfigRegistry and config prefixes with the more flexible concept of nested configuration nodes.
 * Add support for some parts of the configuration to be loaded from a database table.