Drupal 8 Configuration - Module developers and the API
This is the final installment of a five-part series of articles exploring the Drupal 8 Configuration API, how it enables functionality to be migrated between multiple environments, and ways of using the Configuration API with contributed modules to effectively manage the configuration of a project.
We live in an age of Drupal complexity. In the early days of Drupal, many developers would have a single Drupal instance/environment (aka copy) that was their production site, where they would test out new modules and develop new functionality. Developing on the live website however sometimes met with disastrous consequences when things went wrong! Over time, technology on the web grew, and nowadays it's fairly standard to have a Drupal project running on multiple environments to allow site development to be run in parallel to a live website without causing disruptions. New functionality is developed first in isolated private copies of the website, put into a testing environment where it is approved by clients, and eventually merged into the live production site.
While multiple environments allow for site development without causing disruptions on the live production website, it introduces a new problem; how to ensure consistency between site copies so that they are all working with the correct code.
This series of articles will explore the Configuration API, how it enables functionality to be migrated between multiple environments (sites), and ways of using the Configuration API with contributed modules to effectively manage the configuration of a project. This series will consist of the following posts:
- Part 1: The Configuration API
- Part 2: How the API works
- Part 3: Using the API
- Part 4: Extending the API with contributed modules
- Part 5: Module developers and the API
This article will focus specifically on how developers can manage, declare, and debug configuration in their custom modules.
Configuration schema describes the type of configuration a module introduces into the system. Schema definitions are used for things like translating configuration and its values, for typecasting configuration values into their correct data types, and for migrating configuration between systems. Having configuration in the system is not as helpful without metadata that describes what the configuration is. Configuration schemas define the configuration items.
Any module that introduces any configuration into the system MUST define the schema for the configuration the module introduces.
Configuration schema definitions are declared in
[MODULE ROOT]/config/schema/[MODULE NAME].schema.yml, where
[MODULE NAME] is the machine name of the module. Schema definitions may define one or multiple configuration objects. Let's look at the configuration schema for the Restrict IP module for an example. This module defines a single configuration object,
label: 'Restrict IP settings'
label: 'Enable module'
label: 'Contact mail address to show to blocked users'
label: 'Log blocked access attempts'
label: 'Allow IP blocking to be bypassed by roles'
label: 'Action to perform for blocked users when bypassing by role is enabled'
label: 'Whether to use a path whitelist, blacklist, or check all pages'
label: 'Whether to use a whitelist, blacklist, or neither for countries'
label: 'A colon separated list of countries that should be white/black listed'
The above schema defines the config object restrict_ip.settings which is of type config_object (defined in core.data_types.schema.yml).
When this module is enabled, and the configuration is exported, the filename of the configuration will be
restrict_ip.settings.yml. This object has the keys
dblog etc. The schema tells what type of value is to be stored for each of these keys, as well as the label of each key. Note that this label is automatically provided to Drupal for translation.
The values can be retrieved from the
restrict_ip.settings object as follows:
$enable_module = \Drupal::config('restrict_ip.settings')->get('enable');
$mail_address = \Drupal::config('restrict_ip.settings')->get('mail_address');
$log = \Drupal::config('restrict_ip.settings')->get('dblog');
Note that modules defining custom fields, widgets, and/or formatters must define the schema for those plugins. See this page to understand how the schema definitions for these various plugins should be defined.
Default configuration values
If configuration needs to have default values, the default values can be defined in
[MODULE ROOT]/config/install/[CONFIG KEY].yml where
[CONFIG KEY] is the configuration object name. Each item of configuration defined in the module schema requires its own YML file to set defaults. In the case of the Restrict IP module, there is only one config key,
restrict_ip.settings, so there can only be one file to define the default configuration,
restrict_ip/config/install/restrict_ip.settings.yml. This file will then list the keys of the configuration object, and the default values. In the case of the Restrict IP module, the default values look like this:
As can be seen, each of the mapped keys of the
restrict_ip.settings config_object in the schema definition are added to this file, with the default values provided for each key. If a key does not have a default value, it can be left out of this file. When the module is enabled, these are the values that will be imported into active configuration as defaults.
When developing a module, it is important to ensure that the configuration schema accurately describes the configuration used in the module. Configuration can be inspected using the Configuration Inspector module. After enabling your custom module, visit the reports page for the Configuration Inspector at /admin/reports/config-inspector, and it will list any errors in configuration.
Clicking on 'List' for items with errors will give more details as to the error.
Using the Configuration Inspector module, you can find where you have errors in your configuration schema definitions. Cleaning up these errors will correctly integrate your module with the Configuration API. In the above screenshot, then type of data in the active schema is a boolean, yet the configuration schema defines it as a string. The solution is to change the schema definition to be a boolean.
In this final article of this series on the Drupal 8 Configuration API, we looked at configuration schema, how developers can define this schema in their modules and provide defaults, as well as how to debug configuration schema errors. Hopefully this series will give you a fuller understanding of what the Configuration API is, how it can be managed, and how you can use it effectively in your Drupal projects. Happy Drupaling!