Optional configuration is imported even when module dependencies aren't there.

Created on 10 October 2023, 11 months ago
Updated 30 July 2024, about 1 month ago

After applying a recipe that used config: import > module_name: '*', the following modules errored out.

search_api_solr

In RecipeConfigInstaller.php line 53:
The configuration 'search_api_solr.solr_field_type.text_ar_6_0_0' has unmet dependencies
dependencies:
  module:
    - search_api_solr
    - language
  config:
    - language.entity.ar

I did not have the language installed in my recipe.

Scheduler module also.
The configuration 'views.view.scheduler_scheduled_commerce_product' has unmet dependencies

Taxonomy module also.

The configuration 'views.view.taxonomy_term' has unmet dependencies

I didn't have the node module installed.

Temporary workaround is specifying the specific configuration needed in the config: import section.

πŸ› Bug report
Status

Needs review

Version

11.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States thejimbirch Cape Cod, Massachusetts

Live updates comments and jobs are added and updated live.
  • Needs subsystem maintainer review

    It is used to alert the maintainer(s) of a particular core subsystem that an issue significantly impacts their subsystem, and their signoff is needed (see the governance policy draft for more information). Also, if you use this tag, make sure the issue component is set to the correct subsystem. If an issue significantly impacts more than one subsystem, use needs framework manager review instead.

Sign in to follow issues

Comments & Activities

  • Issue created by @thejimbirch
  • πŸ‡ΊπŸ‡ΈUnited States thejimbirch Cape Cod, Massachusetts
  • πŸ‡ΊπŸ‡ΈUnited States thejimbirch Cape Cod, Massachusetts
  • πŸ‡ΊπŸ‡ΈUnited States thejimbirch Cape Cod, Massachusetts

    Importing all configuration from the sitemap module also has this behavior.

    The configuration 'tour.tour.sitemap' has unmet dependencies

    Sitemap module has the following config:

    install/sitemap.setting.yml
    optional/tour.tour.sitemap.yml
    

    This can be remedied in the recipe creation from changing:

    config:
      import:
        sitemap: '*'

    to

    config:
      import:
        sitemap:
          - sitemap.setting.yml

    But ultimately, shouldn't recipe's config import have the same behavior as installing a module and only import config if all dependencies are met?

  • πŸ‡ΊπŸ‡ΈUnited States aangel

    I'm seeing the same thing with Redirect on a Standard install:

    The configuration 'language.content_settings.redirect.redirect' has unmet dependencies
    

    From Redirect:

    dependencies:
     - drupal:path_alias
     - drupal:link
     - drupal:views
  • πŸ‡ΊπŸ‡ΈUnited States phenaproxima Massachusetts

    My knee-jerk reaction here is to think that, if your recipe has a line like this:

    config:
      import:
        taxonomy: '*'
    

    ...then all of Taxonomy's config should be imported, the same way it would be if you installed it as a regular module (i.e., where optional config is only installed if the dependencies are there).

  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    Still wondering how this may or may not mess up the deterministic intent β€” I’ll need to dig in to how optional config works exactly today first though.

    Looking at \Drupal\Core\Config\ConfigInstaller::installDefaultConfig(), this is the relevant section:

        // During a drupal installation optional configuration is installed at the
        // end of the installation process. Once the install profile is installed
        // optional configuration should be installed as usual.
        // @see install_install_profile()
        $profile_installed = in_array($this->drupalGetProfile(), $this->getEnabledExtensions(), TRUE);
        if (!$this->isSyncing() && (!InstallerKernel::installationAttempted() || $profile_installed)) {
          $optional_install_path = $extension_path . '/' . InstallStorage::CONFIG_OPTIONAL_DIRECTORY;
          if (is_dir($optional_install_path)) {
            // Install any optional config the module provides.
            $storage = new FileStorage($optional_install_path, StorageInterface::DEFAULT_COLLECTION);
            $this->installOptionalConfig($storage, '');
          }
          // Install any optional configuration entities whose dependencies can now
          // be met. This searches all the installed modules config/optional
          // directories.
          $storage = new ExtensionInstallStorage($this->getActiveStorages(StorageInterface::DEFAULT_COLLECTION), InstallStorage::CONFIG_OPTIONAL_DIRECTORY, StorageInterface::DEFAULT_COLLECTION, FALSE, $this->installProfile);
          $this->installOptionalConfig($storage, [$type => $name]);
        }
    

    AFAICT that:

    • installs ALL optional config
    • of ALL installed extensions
    • after ANY extension is installed
    • at ANY time.

    I wonder if this still makes sense in a Recipes world πŸ€” Because what if some contrib module that you installed eons ago gains additional optional config in some new version along the way? Then applying a Recipe would install that new optional config too, which AFAICT would be an unwanted side effect? πŸ€”

  • πŸ‡ΊπŸ‡ΈUnited States phenaproxima Massachusetts

    My feeling is that optional config, as we currently understand it, starts breaking down in the context of recipes.

    What I'm leaning towards here is "recipes must be absolutely explicit about everything" -- in other words, in the config:import section of recipe.yml, they can specify any config from a given extension, regardless of whether it's part of the extension's optional config. If a recipe says something like taxonomy: '*', it does not import optional config.

    In other words: if you want to bring in an extension's optional config, you need to explicitly ask for it by name.

  • Status changed to Needs review 8 months ago
  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    I'm not sure if #8 is realistically achievable. Curious what Alex thinks.

  • πŸ‡ΊπŸ‡ΈUnited States konfuzed Atlanta, GA

    Having now run into this conflict while testing a new recipe-based installation, there really seem to be 4 types of configuration imports that are targeted and we should help make it explicit what group of configuration will be brought in:

    1. none -- just activate the module, whether to avoid conflicts or because it's not needed due to nature of the module
    2. required / basic install config files -- could be handled by a keyword of 'default' or 'required' to just get the files in the config/install directory
    3. all aka "*" -- that pulls in config/install and config/optional
    4. explicit selection of files for any reason

    I think common usage makes "*" much easier to read as a "yes I really mean everything in all of the module's config directories" easier on the mental processing and expected outcome.

  • πŸ‡ΊπŸ‡ΈUnited States thejimbirch Cape Cod, Massachusetts
  • πŸ‡¨πŸ‡¦Canada b_sharpe

    @konfuzed I think that's over-complicating it.

    1. NULL: Import none of the config
    2. *: import all the module's config, exactly like would happen if you installed the module through the UI. (optional if dependencies are met)
    3. Explicitly listed (see note below)

    The part in #8 I don't agree with, is installing optional config if asked for by name regardless if dependencies are met or not. There is not a single use-case I can think of to install some config that is dependant on another module without installing the module itself, otherwise it wouldn't have the dependency...

    See #3454444: Document the reason why recipes don’t import a module’s config entities by default β†’

Production build 0.71.5 2024