This is the seventh and (promise!) penultimate installment in a series presenting work on shared configuration that comes out of the Drutopia initiative and related efforts, beginning with Part 1, Configuration Providers.
In this series we've covered how to create and update reusable packages of configuration in Drupal, otherwise known as features.
In Part 6, we saw how the Features module can be used to package configuration that will be used by multiple different features into a "core" feature. An example is when multiple fields use the same storage. A core feature might provide a
field_tags field storage, allowing multiple features to add a
field_tags field to different content types. All the features that provide a field would require the core feature.
This approach helps to manage dependencies among different features, but it has at least two major shortcomings.
- Any site that wants to install even a single feature that's dependent on the core feature will get all the core configuration--whether or not it's needed. For example, if the core feature provides five field storages but only one is required by the dependent feature, all five will still be created on the site.
Features from different sets or distributions will have conflicting dependencies. Say we have two different distributions, A and B. An event feature from distribution A requires the distribution A core feature, which provides the
field_tagsfield storage. An article feature from distribution B requires the distribution B core feature, which provides an identical
field_tagsfield storage. The event feature should theoretically be compatible with the article feature. But in practice they can't be installed on the same site, since an attempt to install both core features will raise an exception because configuration provided by the first-installed core feature will already exist on the site when the second is queued for installation.
In this installment we'll look at options for managing shared configuration that's required across multiple features--or multiple distributions.
One workaround that's sometimes taken to address the issues of core configuration is to ensure individual configuration items are unique by giving them a namespace prefix.
There are two ways this could go. The first keeps the concept of a core feature but namespaces everything in it by feature set or distribution. In this approach, the core feature from distribution A provides a field storage called
a_field_tags, while the B distribution's core feature provides
More radically, in the second approach it's every feature for itself. Even within the same feature set or distribution, there are shared configuration items shared between features. An event feature from distribution A would provide its own tags field storage, such as
a_event_field_tags, while the article feature from distribution B would provide
Either of these approaches would work to avoid conflicting dependencies. But they raise problems that are just as vexing as the ones they attempt to address.
On a given site, you don't really want eight field storages for tags, one per feature you've installed. Nor, of course, do you want eight different tags vocabuaries, each with its own set of tags. You want one that will work site-wide. To take just one example, say I want to ship my distribution with a sitewide content search feature that includes the ability to filter results by tags (a taxonomy). I need all features on the site to use the same tags field referencing the same taxonomy--not eight different versions. See this issue on the Search API module for further details.
Namespacing configuration entities is a workaround that avoids but doesn't successfully address the key challenges here.
The Configuration Share module is written to address the two big shortcomings of core features.
In Part 1 of this series we looked at the Configuration Provider module, which enables alternate configuration provision patterns beyond the required and optional directories supported by Drupal core.
Configuration Share provides an additional plugin,
shared. Commonly needed configuration items like user roles and field storages can be designated as shared by placing them in a module's
config/shared directory. Shared configuration works similarly to optional configuration as supported by Drupal core in that it's not necessarily installed when a module providing it is installed. But while optional configuration is installed after its dependencies have been met, shared configuration is installed only on demand--when another piece of configuration that requires it is about to be installed.
The basic logic:
- When any extension is installed, the configuration to be installed is passed to all configuration provider plugins.
sharedplugin has a high weight and so runs after other plugins, including the ones for required and optional config.
- The shared plugin analyzes all shared configuration with reference to the dependencies of the configuration queued for installation. If any shared configuration is required by queued configuration but is not yet installed, it is added to the list of configuration to be installed--along with any shared configuration it in turn requires.
In this way:
- A given site will have only the specific shared configuration that is required.
- Multiple features can share the same required configuration items without creating conflicting dependencies, since shared configuration is only queued for installation if it's not already on the site.
While Configuration Share is one potential approach to the challenges of base configuration, it's at best an enabler.
In theory, two different distributions could both provide, say, a
field_body storage and each add body fields to their respective features. But how do we know the two body fields will work together? One distribution might use Drupal core's
text_with_summary field type for a
field_body, while another might use Paragraphs for its body field, meaning that
field_body would be of type
entity_reference_revisions. A shared name - in this case,
field_body - is no guarantee of compatibility.
The real work of interoperable sets of features would require collaboration among the developers of multiple distributions to co-maintain one or more curated sets of standardized core configuration. The Compatible module is a preliminary - and thus far undeveloped - step in that direction. It's intended as a repository for a standard set of configuration that can be shared among multiple extensions or distributions.
Stay tuned for the last installment in this blog series: Summary and Future Directions.