Issue #2460847 by alexpott: Allow optional configuration to be installed when its dependencies are met

8.0.x
webchick 2015-04-02 10:54:57 -07:00
parent 8fcce5b381
commit ccfaa23e0a
5 changed files with 62 additions and 31 deletions

View File

@ -9,6 +9,7 @@ namespace Drupal\Core\Config;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Config\Entity\ConfigDependencyManager;
use Drupal\Core\Config\Entity\ConfigEntityDependency;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Site\Settings;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@ -141,16 +142,11 @@ class ConfigInstaller implements ConfigInstallerInterface {
$storage = new FileStorage($optional_install_path, StorageInterface::DEFAULT_COLLECTION);
$this->installOptionalConfig($storage, '');
}
// Install any optional configuration entities whose type this extension
// provides. This searches all the installed modules config/optional
// Install any optional configuration entities whose dependencies can now
// be met. This searches all the installed modules config/optional
// directories.
$provides_config_entity_type = array_reduce($this->configManager->getEntityManager()->getDefinitions(), function ($return, EntityTypeInterface $entity_type) use ($name) {
return $return ?: $entity_type->getProvider() && $entity_type->getConfigPrefix();
}, 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 . '.');
}
$storage = new ExtensionInstallStorage($this->getActiveStorages(StorageInterface::DEFAULT_COLLECTION), InstallStorage::CONFIG_OPTIONAL_DIRECTORY, StorageInterface::DEFAULT_COLLECTION, FALSE);
$this->installOptionalConfig($storage, [$type => $name]);
}
// Reset all the static caches and list caches.
@ -160,7 +156,7 @@ class ConfigInstaller implements ConfigInstallerInterface {
/**
* {@inheritdoc}
*/
public function installOptionalConfig(StorageInterface $storage = NULL, $prefix = '') {
public function installOptionalConfig(StorageInterface $storage = NULL, $dependency = []) {
if (!$storage) {
// Search the install profile's optional configuration too.
$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)) {
continue;
}
$existing_config = $this->getActiveStorages($collection)->listAll($prefix);
$config_to_create = $this->getConfigToCreate($storage, $collection, $prefix, $profile_storage);
$all_config = array_merge($existing_config, array_keys($config_to_create));
$existing_config = $this->getActiveStorages($collection)->listAll();
$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) {
// Exclude configuration that:
// - already exists
// - 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)) {
// Exclude configuration where its dependencies cannot be met.
if (!$this->validateDependencies($config_name, $data, $enabled_extensions, $all_config)) {
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)) {
$this->createConfiguration($collection, $config_to_create, TRUE);

View File

@ -49,11 +49,13 @@ interface ConfigInstallerInterface {
* (optional) The configuration storage to search for optional
* configuration. If not provided, all enabled extension's optional
* configuration directories will be searched.
* @param string $prefix
* (optional) If set, limits the installed configuration to only
* configuration beginning with the provided value.
* @param array $dependency
* (optional) If set, ensures that the configuration being installed has
* 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.

View File

@ -106,15 +106,10 @@ class ConfigInstallProfileOverrideTest extends WebTestBase {
// dependency does not get 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->rebuildContainer();
// Just installing db_log does not create the optional configuration.
$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.');
$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.');
}
}

View File

@ -61,6 +61,12 @@ class ConfigOtherModuleTest extends WebTestBase {
// not throw an error.
$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.');
// 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.');
}
/**

View File

@ -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