Issue #2460847 by alexpott: Allow optional configuration to be installed when its dependencies are met
parent
8fcce5b381
commit
ccfaa23e0a
|
@ -9,6 +9,7 @@ namespace Drupal\Core\Config;
|
||||||
|
|
||||||
use Drupal\Component\Utility\Unicode;
|
use Drupal\Component\Utility\Unicode;
|
||||||
use Drupal\Core\Config\Entity\ConfigDependencyManager;
|
use Drupal\Core\Config\Entity\ConfigDependencyManager;
|
||||||
|
use Drupal\Core\Config\Entity\ConfigEntityDependency;
|
||||||
use Drupal\Core\Entity\EntityTypeInterface;
|
use Drupal\Core\Entity\EntityTypeInterface;
|
||||||
use Drupal\Core\Site\Settings;
|
use Drupal\Core\Site\Settings;
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
|
@ -141,16 +142,11 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
$storage = new FileStorage($optional_install_path, StorageInterface::DEFAULT_COLLECTION);
|
$storage = new FileStorage($optional_install_path, StorageInterface::DEFAULT_COLLECTION);
|
||||||
$this->installOptionalConfig($storage, '');
|
$this->installOptionalConfig($storage, '');
|
||||||
}
|
}
|
||||||
// Install any optional configuration entities whose type this extension
|
// Install any optional configuration entities whose dependencies can now
|
||||||
// provides. This searches all the installed modules config/optional
|
// be met. This searches all the installed modules config/optional
|
||||||
// directories.
|
// directories.
|
||||||
$provides_config_entity_type = array_reduce($this->configManager->getEntityManager()->getDefinitions(), function ($return, EntityTypeInterface $entity_type) use ($name) {
|
$storage = new ExtensionInstallStorage($this->getActiveStorages(StorageInterface::DEFAULT_COLLECTION), InstallStorage::CONFIG_OPTIONAL_DIRECTORY, StorageInterface::DEFAULT_COLLECTION, FALSE);
|
||||||
return $return ?: $entity_type->getProvider() && $entity_type->getConfigPrefix();
|
$this->installOptionalConfig($storage, [$type => $name]);
|
||||||
}, FALSE);
|
|
||||||
if ($provides_config_entity_type) {
|
|
||||||
$storage = new ExtensionInstallStorage($this->getActiveStorages(StorageInterface::DEFAULT_COLLECTION), InstallStorage::CONFIG_OPTIONAL_DIRECTORY, StorageInterface::DEFAULT_COLLECTION, FALSE);
|
|
||||||
$this->installOptionalConfig($storage, $name . '.');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset all the static caches and list caches.
|
// Reset all the static caches and list caches.
|
||||||
|
@ -160,7 +156,7 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function installOptionalConfig(StorageInterface $storage = NULL, $prefix = '') {
|
public function installOptionalConfig(StorageInterface $storage = NULL, $dependency = []) {
|
||||||
if (!$storage) {
|
if (!$storage) {
|
||||||
// Search the install profile's optional configuration too.
|
// Search the install profile's optional configuration too.
|
||||||
$storage = new ExtensionInstallStorage($this->getActiveStorages(StorageInterface::DEFAULT_COLLECTION), InstallStorage::CONFIG_OPTIONAL_DIRECTORY, StorageInterface::DEFAULT_COLLECTION, TRUE);
|
$storage = new ExtensionInstallStorage($this->getActiveStorages(StorageInterface::DEFAULT_COLLECTION), InstallStorage::CONFIG_OPTIONAL_DIRECTORY, StorageInterface::DEFAULT_COLLECTION, TRUE);
|
||||||
|
@ -180,19 +176,38 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
if (!$this->configManager->supportsConfigurationEntities($collection)) {
|
if (!$this->configManager->supportsConfigurationEntities($collection)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$existing_config = $this->getActiveStorages($collection)->listAll($prefix);
|
$existing_config = $this->getActiveStorages($collection)->listAll();
|
||||||
$config_to_create = $this->getConfigToCreate($storage, $collection, $prefix, $profile_storage);
|
|
||||||
$all_config = array_merge($existing_config, array_keys($config_to_create));
|
$list = array_filter($storage->listAll(), function($config_name) use ($existing_config) {
|
||||||
|
// Only list configuration that:
|
||||||
|
// - does not already exist
|
||||||
|
// - is a configuration entity (this also excludes config that has an
|
||||||
|
// implicit dependency on modules that are not yet installed)
|
||||||
|
return !in_array($config_name, $existing_config) && $this->configManager->getEntityTypeIdByName($config_name);
|
||||||
|
});
|
||||||
|
|
||||||
|
$all_config = array_merge($existing_config, $list);
|
||||||
|
$config_to_create = $storage->readMultiple($list);
|
||||||
|
// Check to see if the corresponding override storage has any overrides.
|
||||||
|
if ($profile_storage) {
|
||||||
|
if ($profile_storage->getCollectionName() != $collection) {
|
||||||
|
$profile_storage = $profile_storage->createCollection($collection);
|
||||||
|
}
|
||||||
|
$config_to_create = $profile_storage->readMultiple($list) + $config_to_create;
|
||||||
|
}
|
||||||
foreach ($config_to_create as $config_name => $data) {
|
foreach ($config_to_create as $config_name => $data) {
|
||||||
// Exclude configuration that:
|
// Exclude configuration where its dependencies cannot be met.
|
||||||
// - already exists
|
if (!$this->validateDependencies($config_name, $data, $enabled_extensions, $all_config)) {
|
||||||
// - is a not configuration entity
|
|
||||||
// - or its dependencies cannot be met.
|
|
||||||
if (in_array($config_name, $existing_config) ||
|
|
||||||
!$this->configManager->getEntityTypeIdByName($config_name) ||
|
|
||||||
!$this->validateDependencies($config_name, $data, $enabled_extensions, $all_config)) {
|
|
||||||
unset($config_to_create[$config_name]);
|
unset($config_to_create[$config_name]);
|
||||||
}
|
}
|
||||||
|
// Exclude configuration that does not have a matching dependency.
|
||||||
|
elseif (!empty($dependency)) {
|
||||||
|
// Create a light weight dependency object to check dependencies.
|
||||||
|
$config_entity = new ConfigEntityDependency($config_name, $data);
|
||||||
|
if (!$config_entity->hasDependency(key($dependency), reset($dependency))) {
|
||||||
|
unset($config_to_create[$config_name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!empty($config_to_create)) {
|
if (!empty($config_to_create)) {
|
||||||
$this->createConfiguration($collection, $config_to_create, TRUE);
|
$this->createConfiguration($collection, $config_to_create, TRUE);
|
||||||
|
|
|
@ -49,11 +49,13 @@ interface ConfigInstallerInterface {
|
||||||
* (optional) The configuration storage to search for optional
|
* (optional) The configuration storage to search for optional
|
||||||
* configuration. If not provided, all enabled extension's optional
|
* configuration. If not provided, all enabled extension's optional
|
||||||
* configuration directories will be searched.
|
* configuration directories will be searched.
|
||||||
* @param string $prefix
|
* @param array $dependency
|
||||||
* (optional) If set, limits the installed configuration to only
|
* (optional) If set, ensures that the configuration being installed has
|
||||||
* configuration beginning with the provided value.
|
* this dependency. The format is dependency type as the key ('module',
|
||||||
|
* 'theme', or 'config') and the dependency name as the value
|
||||||
|
* ('book', 'bartik', 'views.view.frontpage').
|
||||||
*/
|
*/
|
||||||
public function installOptionalConfig(StorageInterface $storage = NULL, $prefix = '');
|
public function installOptionalConfig(StorageInterface $storage = NULL, $dependency = []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs all default configuration in the specified collection.
|
* Installs all default configuration in the specified collection.
|
||||||
|
|
|
@ -106,15 +106,10 @@ class ConfigInstallProfileOverrideTest extends WebTestBase {
|
||||||
// dependency does not get created.
|
// dependency does not get created.
|
||||||
$this->assertNull($config_test_storage->load('override_unmet'), 'The optional config_test entity with unmet dependencies is not created.');
|
$this->assertNull($config_test_storage->load('override_unmet'), 'The optional config_test entity with unmet dependencies is not created.');
|
||||||
|
|
||||||
|
// Installing dblog creates the optional configuration.
|
||||||
$this->container->get('module_installer')->install(['dblog']);
|
$this->container->get('module_installer')->install(['dblog']);
|
||||||
$this->rebuildContainer();
|
$this->rebuildContainer();
|
||||||
// Just installing db_log does not create the optional configuration.
|
$this->assertEqual($config_test_storage->load('override_unmet')->label(), 'Override', 'The optional config_test entity is overridden by the profile optional configuration and is installed when its dependencies are met.');
|
||||||
$this->assertNull($config_test_storage->load('override_unmet'), 'The optional config_test entity with unmet dependencies is not created.');
|
|
||||||
// Install all available optional configuration.
|
|
||||||
$this->container->get('config.installer')->installOptionalConfig();
|
|
||||||
$this->assertEqual($config_test_storage->load('override_unmet')->label(), 'Override', 'The optional config_test entity is overridden by the profile optional configuration.');
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,12 @@ class ConfigOtherModuleTest extends WebTestBase {
|
||||||
// not throw an error.
|
// not throw an error.
|
||||||
$this->installModule('config_other_module_config_test');
|
$this->installModule('config_other_module_config_test');
|
||||||
$this->assertTrue(\Drupal::moduleHandler()->moduleExists('config_other_module_config_test'), 'The config_other_module_config_test module is installed.');
|
$this->assertTrue(\Drupal::moduleHandler()->moduleExists('config_other_module_config_test'), 'The config_other_module_config_test module is installed.');
|
||||||
|
|
||||||
|
// Ensure that optional configuration with unmet dependencies is only
|
||||||
|
// installed once all the dependencies are met.
|
||||||
|
$this->assertNull(entity_load('config_test', 'other_module_test_unmet', TRUE), 'The optional configuration whose dependencies are met is not created.');
|
||||||
|
$this->installModule('config_install_dependency_test');
|
||||||
|
$this->assertTrue(entity_load('config_test', 'other_module_test_unmet', TRUE), 'The optional configuration whose dependencies are met is now created.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
id: other_module_test_unmet
|
||||||
|
label: 'Other module test to test optional config installation'
|
||||||
|
weight: 0
|
||||||
|
style: ''
|
||||||
|
status: true
|
||||||
|
langcode: en
|
||||||
|
protected_property: Default
|
||||||
|
dependencies:
|
||||||
|
module:
|
||||||
|
- config_install_dependency_test
|
||||||
|
enforced:
|
||||||
|
module:
|
||||||
|
- config_install_dependency_test
|
Loading…
Reference in New Issue