Problem/Motivation

Core provides two built-in directories for extension-provided configuration: config/install and config/optional. While both hold configuration that is installed onto the site, the conditions for installation differ in ways that have implications for other modules interacting with the directories. For example, while it may be appropriate to consider all configuration in config/install as available for install, only certain items in config/optional can be installed.

In addition to these two core use cases, contrib modules map also have a need for extension-provided configuration to serve distinct use cases. At least two such contrib modules have been drafted:

Modules that work with extension-provided configuration, like Features and Configuration Update Manager, will by default not be aware of all such configuration sources. Also, they will lack the ability to handle these directories distinctly as needed.

Currently, following core, the default approach - with clear shortcomings - is to hard-code support for specific directories.

In Features we have the beginning of a wrapper class in FeaturesExtensionStorages that provides support for the two core extension configuration directories and could be extended to support more. However:

  • It lacks support for registering new extension storage directories, short of directly calling FeaturesExtensionStorages::addStorage().
  • It lacks support for distinct handling for different configuration directories.

Proposed resolution

  • Model configuration directories as a plugin type.
  • Implement plugins for core's config/install and config/optional.

Possible methods:

/**
 * Lists configuration items currently available for installation.
 *
 * @return array
 *   A list of configuration item names.
 */
public function listInstallable();

This would likely need to be done outside Features.

Remaining tasks

User interface changes

API changes

Data model changes

Comments

nedjo created an issue. See original summary.

jhodgdon’s picture

Interesting! I think that Config Update Manager could help support this in the following ways:

ConfigListInterface/ConfigLister :: listConfig() method -- currently this makes lists of config that are in active, extension, optional. We could add a new method that would take as input a \Drupal\Core\Config\ExtensionInstallStorage object, and given that, would list the config of the given list_type/name that it contains.

ConfigRevertInterface/ConfigReverter :: import(), revert(), and getFromExtension() methods -- we could also add methods here that would take a \Drupal\Core\Config\ExtensionInstallStorage object, and would import/revert/get using that storage.

Since I think this is probably an "advanced" use case, I'm not sure that it's appropriate for the UI reports from Config Update Manager to change based on this... but at least that would provide some building blocks.

Thoughts? Perhaps we should file a separate issue in Config Update Manager about this...

nedjo’s picture

@jhodgdon: Thanks for looking into this :)

Your idea about accepting an \Drupal\Core\Config\ExtensionInstallStorage object as an argument sounds right and a separate issue on Config Update Manager makes sense.

I started to sketch in a sandbox project that would try the idea of config provision directory plugins, but haven't found time to finish and post it.

jhodgdon’s picture

Added issue in Config Update project

nedjo’s picture

I ended up implementing something along these lines in the Configuration Packager module.

jhodgdon’s picture

Do you think we should still consider adding something to the Config Update Manager base module to handle this type of thing (on the linked issue in #4)?

mpotter’s picture

I've still love to see this in Config Update since Features already depends on that. I'm not sure if nedjo made a typo in #5 since I thought Configuration Packager was merged into Features already.

How does Core handle this (with config/install and config/optional). Does it already have an API for adding different config storage? If it doesn't have the listing services that we need to support that then it seems like something we'd want in core. Although starting with it in config_update would be good because there are parts of that which I think could eventually be in core as well.

jhodgdon’s picture

So, let's see...

What happens now in the Config Update base module is that to access config/install, you instantiate a core ExtensionInstallStorage object, passing in as the first argument in ExtensionInstallStorage::_construct() the core config.storage service. To access config/optional, you instantiate passing in "config/optional" as the second argument, to indicate a different directory to check.

These are both services in Config Update base module (service config_update.extension_storage and config_update.extension_optional_storage). Creating them as services is 3 lines each in config_update.services.yml, with no additional code needed at all.

Then these two services are used as arguments to the config_update.config_list and config_update.config_update services, which allow users of those services to (a) list config from install/optional directories and (b) update/revert the current config to the stuff in install/optional. I hope/expect that Features uses the config_update.config_list service? Not sure, but it probably should. ;)

Core doesn't have services for these (or I could have used them in Config Update). When Core needs these listings, it just instantiates the ExtensionInstallStorage class (or related classes, such as InstallStorage) directly.

Anyway. If you want to list configuration from another directory, the easiest thing is to do what Config Update does, and make a service for it out of the ExtensionInstallStorage class, like this in a services.yml file:

  mymodule.my_type_of_config_storage:
    class: Drupal\Core\Config\ExtensionInstallStorage
    arguments: ['@config.storage', 'config/my_subdirectory']

The question is what to do with that. the Config Update module's classes expect to have specifically config/install and config/optional directories to work with, and treat them differently. I'm not sure what types of operations people would want to do with these other directories?

nedjo’s picture

I'm not sure if nedjo made a typo in #5 since I thought Configuration Packager was merged into Features already.

Yes, thanks for catching that. The new module is Configuration Provider.

I'm not sure what types of operations people would want to do with these other directories?

First off I have to admit that "people" so far pretty much means "me" ;)

The Configuration Provider project page gives details on use cases.

jhodgdon’s picture

OK... So, do you think we should do anything regarding this in either Features or Config Update Manager module? If not, we should close this issue and the related one in config_update.

psiegel’s picture

Hello,

I am not sure this is fully related but in seems to be.

Is there a way to have the config directory outside of the module directory, for example in sites/default/files or any other directory even outside of Drupal root?

The reason behind this is to be able to have a multi-site installation with the module symlinked to each site. which doesn't work when the config directory is in the module site, all sites would share the same config directory.
So far I have solved this by creating the below structure with symlinkss, it is working but is not a clean way of doing it:

/data/www/d8/DEV/mu824v01/sites/ws01.opwebs.comdev/modules# ll
lrwxrwxrwx 1 root root 62 Dec 19 13:45 admin_toolbar -> ../../../../SHARED/CORE/modules/contrib/admin_toolbar-8.x-1.18/
drwxr-xr-x 3 psiegel www-data 4096 Dec 19 13:45 config_update/
lrwxrwxrwx 1 root root 64 Dec 19 13:45 masquerade -> ../../../../SHARED/CORE/modules/contrib/masquerade-8.x-2.0-beta1/

and then the config_update directory:
ll config_update/
drwxr-xr-x 2 psiegel www-data 4096 Dec 19 13:45 config/
lrwxrwxrwx 1 root root 82 Dec 19 13:45 config_update.info.yml -> ../../../../../SHARED/modules/contrib/config_update-8.x-1.2/config_update.info.yml
lrwxrwxrwx 1 root root 80 Dec 19 13:45 config_update.module -> ../../../../../SHARED/modules/contrib/config_update-8.x-1.2/config_update.module
lrwxrwxrwx 1 root root 86 Dec 19 13:45 config_update.services.yml -> ../../../../../SHARED/modules/contrib/config_update-8.x-1.2/config_update.services.yml
lrwxrwxrwx 1 root root 76 Dec 19 13:45 config_update_ui -> ../../../../../SHARED/modules/contrib/config_update-8.x-1.2/config_update_ui/
lrwxrwxrwx 1 root root 71 Dec 19 13:45 LICENSE.txt -> ../../../../../SHARED/modules/contrib/config_update-8.x-1.2/LICENSE.txt
lrwxrwxrwx 1 root root 70 Dec 19 13:45 README.txt -> ../../../../../SHARED/modules/contrib/config_update-8.x-1.2/README.txt
lrwxrwxrwx 1 root root 63 Dec 19 13:45 src -> ../../../../../SHARED/modules/contrib/config_update-8.x-1.2/src/

If not doable, can this be a feature request?

Best,
Pascal

nedjo’s picture

@psiegel:

While tangentially related, that's a separate question. Please file a new issue. Thanks!

nedjo’s picture

Status: Active » Postponed

Postponing on this issue in Configuration Update Manager: #2633480: Add functionality for external storage. If that goes in, we could relatively easily build on it in Features.