Khanh Hoang - Kenn
Kenn is a user experience designer and front end developer who enjoys creating beautiful and usable web and mobile experiences.
In an earlier post, Kyle wrote a great introduction to the new configuration management system in Drupal 8. He demonstrated how end users can leverage this new system to easily migrate site configuration between environment, which helps eliminate the "did you remember to check the boxes in the right order?" problem for site builders everywhere. In this post, I take a look at configuration management from the perspective of a module developer. What do we need to write in our custom code to ensure that our configuration settings are easy to deploy?
Configuration is any setting that changes the way an instance of Drupal behaves. For example, the toggle which turns on and off the JavaScript aggregator. Some sites need JavaScript aggregation, some do not. Configuration allows us to use the same code base to serve multiple sites without modifying any code. When you build a view or create an image style, that's configuration.
The converse of configuration is user generated content; nodes, comments, uploaded files, etc. The image someone uploads to a blog post is user generated content, while the image style we're utilizing to scale that image is configuration.
Drupal 8 has two distinct types of configuration. These are Simple configuration—like on/off toggles and the settings required by modules—and configuration entities, which are used to store complex instance configuration (e.g., views). Configuration entities are an extension of the core entity system. They provide a full suite of CRUD (Create/Read/Update/Delete) hooks that fire when configurations are modified, like when someone edits a node.
As an example, let's pretend we're building a module that interfaces with a remote video encoding service. In order for our module to do anything, it's going to need to know the API id and key to communicate with the external API. The module might need also to know the URL it should access and, perhaps, the maximum number of encoding jobs it should run at any given time. These are examples of simple configuration; a few string and integer values that must be present for our module to work.
But our module might provide also a user interface that enables administrators to create new encoding profiles and specify different parameters for encoding videos. For example, what bit-rate? What audio format? Do we even want audio? This type of configuration isn't required for our module to operate. We may have zero or tens of instances of this configuration entity, depending on our specific use case. Some sites only need one video format; some need dozens.
In addition to providing a user interface (UI) for creating new instances of this configuration, we might want also to provide a set of hooks. Other developers could implement these hooks then, so their modules could provide configuration for our module or even alter any user created configuration. This sounds a bit like handling user generated content, right? Well by leveraging the core entity system to create configuration entities, Drupal 8 provides this functionality with minimal code duplication.
The rest of this post and video focus on working with simple configuration. The more complex configuration entities are a topic for another day.
Goodbye {variables}
table and variable_get/set/delete()
. Hello YAML files and $config objects. If you read Kyle's post and watched his video, you already know that configuration in Drupal 8 is stored in YAML files instead of the database. This makes it super easy to commit the value of a settings form to version control and deploy it across multiple environments.
As a module developer, I need to be able to read data from and write data to these YAML files. Instead of just reading and writing from the files directly, however, in Drupal 8 we use a Config object that handles basic CRUD for these YAML files on our behalf. This ensures a simple and consistent API for accessing data. As a module developer, I no longer have to worry about Drupal Core storing data in XML or changing the location of files. I can just rely on the Config object to handle everything while I happily make use of simple ::get()
, ::set(),
and ::save()
methods.
Configuration is stored in a YAML file named after the corresponding module. In the video, we're working with a module named chad, so our configuration is stored in a file named chad.settings.yml
. The settings
portion of this filename is somewhat arbitrary; it can be whatever we want. In fact, a single module can have multiple configuration files just by changing this portion of the filename. The system module in Drupal Core, which has a huge number of configuration settings, is a great example. It uses a few dozen files to group related configuration settings together. If you're only using a single configuration file, however, convention is to name it {MY_MODULE}.settings.yml
.
The Drupal Core ConfigFactory class is a module developer's gateway to reading and writing configuration data, and it is used to instantiate a Config object based on the contents of a specified configuration file. The new Config object can then be used to perform CRUD operations on that data. But we don't call ConfigFactory directly. Instead we rely on the Drupal services container to do so on our behalf. This extra layer of abstraction makes our code more robust, and it allows us to change how Config objects are made without breaking our code.
Here's a quick example of creating a new Config object based on chad.settings.yml
using the services container and reading a value from that config object. (If you need a refresher or want to refer back, here's a post I wrote on Getting Started with Forms in Drupal 8.)
// Load the content of chad.settings.yml into a Config object. $config = \Drupal::config('chad.settings'); // Read a value from the YAML file. $last_name = $config->get('name.last');
Assuming a file with the following data in it, we can expect that the variable $last_name
is now equal to IsAwesome.
chad.settings.yml name: first: Chad last: IsAwesome
We can update also the configuration data by setting a new value using the Config object and then calling its save method. This effectively tells it to write its content to the associated YAML file.
$config->set('name.last', 'Smith'); $config->save();
If you want to know more about how this system works, the documentation on drupal.org is a great place to start. Once you're done reading that, I suggest digging into the system module and seeing how it deals with all its various settings.