Drupal 8 configuration management - Part 2
Remember how variable defaults were used in Drupal 7?
$value = variable_get('my_variable_name', 'my_default_value');
In Drupal 8, you don’t need your setting defaults to be scattered throughout the code. If you have a setting, set its default value during the module installation. There are two ways to do that:
the easiest and the simplest way is to place YAML files with your defaults in the config/install directory (example from core Comment module)
the second option is for cases when the setting default value should be calculated dynamically on the module/theme installation, use hook_install() to do that
An examples can be found in the core Comment module. In the contact.form.feedback.yml file, the recipients setting is set to an empty array. Then, in contact_install(), actual value is set to the recipients.
Exporting configuration into a module
There is one interesting fact about the config/install directory.
In Drupal 7, we can export various functionalities in our module’s code. The common example is a View for a module administrative UI. For this we would need a basic knowledge of views API, some hooks, and a bit of copy-pasting. The Features module also could help with that task.
With Drupal 8 things getting easier. An example for a view:
- build a view
- export site configuration
- find your view YAML file in the exported configuration (example: views.view.my_cool_view.yml)
- put that file under the config/install directory of your module
Voilà! Your view will be imported automatically on the module installation.
Configuration override system
One of the best things in Drupal is that we can alter (change) everything. Configuration is not an exception there.
There are two levels of configuration overrides.
The settings.php file could contain environment level overrides. Just remember how we disabled email sending on development servers in Drupal 7:
$conf['mail_system']['default-system'] = 'DevelMailLog';
That’s how it will look in Drupal 8:
$config['system.mail']['interface']['default'] = 'devel_mail_log';
Dynamic configuration overrides could be implemented in modules. Overrides are provided by services tagged as config.factory.override implementing ConfigFactoryOverrideInterface. An example can be found in the core Language module which translates strings coming from configuration (so when you call Drupal::config(...)->get(...), you actually get translated strings instead of original ones).
Getting raw (not overridden) data
Sometimes we need to get initial, not overridden configuration. Generally, this is required for configuration forms (for instance, to allow the user edit original strings instead of their translations). And this case is handled right in Drupal core: all we need is to use the ConfigFormBase class instead of the FormBase for our forms, and use it’s build-in ConfigFormBase::config() method instead of Drupal::config(). This will give us the raw data.
Another way is to call the Config::getRawData() method. And for more complex workflows, you may check the ConfigFormBaseTrait::config() method implementation.
Best practice tip
When you work from a class extending some base class, be sure to check all built-in methods you have, and use them in the first place. The example above demonstrates how to get the raw configuration data using the ::config() method when working from the ConfigFormBase subclass. Another one example: many classes have built-in ::t() method that should be used instead of global t() function. There is always a reason for that, check out an example.
Reacting on configuration changes
There are two ways to react on configuration changes:
- Subscribe to events listed in the ConfigEvents class (doc). An example could be found in Drupal\language\EventSubscriber\ConfigSubscriber class (doc).
- For complex workflows, the hook_config_import_steps_alter() could be implemented. An example could be found in the core Field module.
You can describe your configuration to Drupal with configuration schema. Let’s start from an example.
# file: core/modules/system/config/install/system.maintenance.yml message: '@site is currently under maintenance. We should be back shortly. Thank you for your patience.' langcode: en # file: core/modules/system/config/schema/system.schema.yml system.maintenance: type: mapping label: 'Maintenance mode' mapping: message: type: text label: 'Message to display when in maintenance mode' langcode: type: string label: 'Default language' # file: core/config/schema/core.data_types.schema.yml text: type: string label: 'Text' translatable: true # ... string: class: '\Drupal\Core\TypedData\Plugin\DataType\String' label: 'String'
From this data we can learn the purpose of settings stored in the system.maintenance configuration as well as their types:
- message is a translatable string displaying in the maintenance mode
- langcode is a string representing default language code for the maintenance mode
And what is more important, Drupal and other modules also can get this information.
There is a lot of core data types, and you can create your own types extending existing ones. Check out the Configuration schema/metadata section of the developer documentation to learn more.
Also, please note that it is highly recommended to use configuration schema for your configuration.
The translatable property indicates translatable string types that get processed automatically by the core Language module. There are two base translatable types in the core you might want use:
- label: human readable string that must be plain text and editable with a text field
- text: human readable string that can contain multiple lines of text or HTML
Simple definition: configuration entities are entities that are stored as configuration. Therefore, I would recommend to learn the Entity API documentation first. Then, the Creating a configuration entity type in Drupal 8 article from the developer documentation contains a simple example. And when you have some knowledge and want more, the ImageStyle entity from the core Image module can be a good starting example.
I’d like to give a big thanks to the people who started the Configuration Management Initiative and to all drupalists who worked hard to bring such a cool feature in Drupal 8. The result of their work is great!
P.S.: There are already ready to use modules that can help you work with configurations.
P.S.S.: Configuration management developer documentation is really helpful to get started. However, be careful because some parts may need to be updated Drupal 8 has a stable release.