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 a simple 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, but would typically provide the   and   settings.

If this variable is set, 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, 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 as 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.

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.

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.

MainConfigSchema replaces DefaultSettings.php
One major change in 1.38 is that we replace the file. initializes one global variable for each of the over 700 configuration variables that MediaWiki supports. It used to serve as the "source of truth" for the list of supported configuration variables, and as the cononical location for documentation about these settings.

Starting from 1.38, each configuration variable is defiend by a schema that is defined as a class 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:


 * is now derived from . It exists primary so that code editors know where to find documentation about   variables, and as a way for developers to discuver the new location of the default value and documentation.
 * 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.

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.

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:
 * Per default load LocalSettings.php in an isolated scope, as described above.
 * 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.
 * Stop exporting configuration settings to global variables. The  variables will still work in LocalSettings.php, but not in application code or extensions.
 * 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.