Issue #2655104 by dawehner, jhedstrom, gclicon, chr.fritsch, smk-ka, phenaproxima: List unmet configuration dependencies instead of just failing
parent
1fdf088bfa
commit
efcf5218c9
|
@ -455,9 +455,9 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
|||
$profile_storages = $this->getProfileStorages($name);
|
||||
|
||||
// Check the dependencies of configuration provided by the module.
|
||||
$invalid_default_config = $this->findDefaultConfigWithUnmetDependencies($storage, $enabled_extensions, $profile_storages);
|
||||
list($invalid_default_config, $missing_dependencies) = $this->findDefaultConfigWithUnmetDependencies($storage, $enabled_extensions, $profile_storages);
|
||||
if (!empty($invalid_default_config)) {
|
||||
throw UnmetDependenciesException::create($name, $invalid_default_config);
|
||||
throw UnmetDependenciesException::create($name, array_unique($missing_dependencies));
|
||||
}
|
||||
|
||||
// Install profiles can not have config clashes. Configuration that
|
||||
|
@ -485,14 +485,24 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
|||
* for overrides.
|
||||
*
|
||||
* @return array
|
||||
* List of configuration that has unmet dependencies
|
||||
* An array containing:
|
||||
* - A list of configuration that has unmet dependencies.
|
||||
* - An array that will be filled with the missing dependency names, keyed
|
||||
* by the dependents' names.
|
||||
*/
|
||||
protected function findDefaultConfigWithUnmetDependencies(StorageInterface $storage, array $enabled_extensions, array $profile_storages = []) {
|
||||
$missing_dependencies = [];
|
||||
$config_to_create = $this->getConfigToCreate($storage, StorageInterface::DEFAULT_COLLECTION, '', $profile_storages);
|
||||
$all_config = array_merge($this->configFactory->listAll(), array_keys($config_to_create));
|
||||
return array_filter(array_keys($config_to_create), function($config_name) use ($enabled_extensions, $all_config, $config_to_create) {
|
||||
return !$this->validateDependencies($config_name, $config_to_create[$config_name], $enabled_extensions, $all_config);
|
||||
});
|
||||
foreach ($config_to_create as $config_name => $config) {
|
||||
if ($missing = $this->getMissingDependencies($config_name, $config, $enabled_extensions, $all_config)) {
|
||||
$missing_dependencies[$config_name] = $missing;
|
||||
}
|
||||
}
|
||||
return [
|
||||
array_intersect_key($config_to_create, $missing_dependencies),
|
||||
$missing_dependencies,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -508,11 +518,37 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
|||
* A list of all the active configuration names.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the dependencies are met, FALSE if not.
|
||||
* TRUE if all dependencies are present, FALSE otherwise.
|
||||
*/
|
||||
protected function validateDependencies($config_name, array $data, array $enabled_extensions, array $all_config) {
|
||||
list($provider) = explode('.', $config_name, 2);
|
||||
if (!isset($data['dependencies'])) {
|
||||
// Simple config or a config entity without dependencies.
|
||||
list($provider) = explode('.', $config_name, 2);
|
||||
return in_array($provider, $enabled_extensions, TRUE);
|
||||
}
|
||||
|
||||
$missing = $this->getMissingDependencies($config_name, $data, $enabled_extensions, $all_config);
|
||||
return empty($missing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of missing dependencies for a config object.
|
||||
*
|
||||
* @param string $config_name
|
||||
* The name of the configuration object that is being validated.
|
||||
* @param array $data
|
||||
* Configuration data.
|
||||
* @param array $enabled_extensions
|
||||
* A list of all the currently enabled modules and themes.
|
||||
* @param array $all_config
|
||||
* A list of all the active configuration names.
|
||||
*
|
||||
* @return array
|
||||
* A list of missing config dependencies.
|
||||
*/
|
||||
protected function getMissingDependencies($config_name, array $data, array $enabled_extensions, array $all_config) {
|
||||
if (isset($data['dependencies'])) {
|
||||
list($provider) = explode('.', $config_name, 2);
|
||||
$all_dependencies = $data['dependencies'];
|
||||
|
||||
// Ensure enforced dependencies are included.
|
||||
|
@ -541,18 +577,12 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
|||
break;
|
||||
}
|
||||
if (!empty($list_to_check)) {
|
||||
$missing = array_diff($dependencies, $list_to_check);
|
||||
if (!empty($missing)) {
|
||||
return FALSE;
|
||||
}
|
||||
return array_diff($dependencies, $list_to_check);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Simple config or a config entity without dependencies.
|
||||
return in_array($provider, $enabled_extensions, TRUE);
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Drupal\Core\Config;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
|
||||
/**
|
||||
|
@ -13,6 +13,20 @@ class UnmetDependenciesException extends ConfigException {
|
|||
/**
|
||||
* A list of configuration objects that have unmet dependencies.
|
||||
*
|
||||
* The list is keyed by the config object name, and the value is an array of
|
||||
* the missing dependencies:
|
||||
*
|
||||
* @code
|
||||
*
|
||||
* self::configObjects = [
|
||||
* config_object_name => [
|
||||
* 'missing_dependency_1',
|
||||
* 'missing_dependency_2',
|
||||
* ]
|
||||
* ];
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $configObjects = [];
|
||||
|
@ -28,7 +42,8 @@ class UnmetDependenciesException extends ConfigException {
|
|||
* Gets the list of configuration objects that have unmet dependencies.
|
||||
*
|
||||
* @return array
|
||||
* A list of configuration objects that have unmet dependencies.
|
||||
* A list of configuration objects that have unmet dependencies, keyed by
|
||||
* object name, with the value being a list of the unmet dependencies.
|
||||
*/
|
||||
public function getConfigObjects() {
|
||||
return $this->configObjects;
|
||||
|
@ -53,13 +68,11 @@ class UnmetDependenciesException extends ConfigException {
|
|||
* @return string
|
||||
*/
|
||||
public function getTranslatedMessage(TranslationInterface $string_translation, $extension) {
|
||||
return $string_translation->formatPlural(
|
||||
count($this->getConfigObjects()),
|
||||
'Unable to install @extension, %config_names has unmet dependencies.',
|
||||
'Unable to install @extension, %config_names have unmet dependencies.',
|
||||
return $string_translation->translate(
|
||||
'Unable to install %extension due to unmet dependencies: %config_names',
|
||||
[
|
||||
'%config_names' => implode(', ', $this->getConfigObjects()),
|
||||
'@extension' => $extension,
|
||||
'%config_names' => static::formatConfigObjectList($this->configObjects),
|
||||
'%extension' => $extension,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -70,15 +83,16 @@ class UnmetDependenciesException extends ConfigException {
|
|||
* @param $extension
|
||||
* The name of the extension that is being installed.
|
||||
* @param array $config_objects
|
||||
* A list of configuration object names that have unmet dependencies
|
||||
* A list of configuration keyed by configuration name, with unmet
|
||||
* dependencies as the value.
|
||||
*
|
||||
* @return \Drupal\Core\Config\PreExistingConfigException
|
||||
*/
|
||||
public static function create($extension, array $config_objects) {
|
||||
$message = SafeMarkup::format('Configuration objects (@config_names) provided by @extension have unmet dependencies',
|
||||
$message = new FormattableMarkup('Configuration objects provided by %extension have unmet dependencies: %config_names',
|
||||
array(
|
||||
'@config_names' => implode(', ', $config_objects),
|
||||
'@extension' => $extension
|
||||
'%config_names' => static::formatConfigObjectList($config_objects),
|
||||
'%extension' => $extension
|
||||
)
|
||||
);
|
||||
$e = new static($message);
|
||||
|
@ -87,4 +101,21 @@ class UnmetDependenciesException extends ConfigException {
|
|||
return $e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a list of configuration objects.
|
||||
*
|
||||
* @param array $config_objects
|
||||
* A list of configuration object names that have unmet dependencies.
|
||||
*
|
||||
* @return string
|
||||
* The imploded config_objects, formatted in an easy to read string.
|
||||
*/
|
||||
protected static function formatConfigObjectList(array $config_objects) {
|
||||
$list = [];
|
||||
foreach ($config_objects as $config_object => $missing_dependencies) {
|
||||
$list[] = $config_object . ' (' . implode(', ', $missing_dependencies) . ')';
|
||||
}
|
||||
return implode(', ', $list);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ class ConfigInstallProfileUnmetDependenciesTest extends InstallerTestBase {
|
|||
else {
|
||||
$this->fail('Expected Drupal\Core\Config\UnmetDependenciesException exception thrown');
|
||||
}
|
||||
$this->assertErrorLogged('Configuration objects (system.action.user_block_user_action) provided by user have unmet dependencies in');
|
||||
$this->assertErrorLogged('Configuration objects provided by <em class="placeholder">user</em> have unmet dependencies: <em class="placeholder">system.action.user_block_user_action (action)</em>');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -180,7 +180,7 @@ class ConfigInstallWebTest extends WebTestBase {
|
|||
// not depend on config_test and order is important.
|
||||
$this->drupalPostForm('admin/modules', array('modules[Testing][config_test][enable]' => TRUE), t('Install'));
|
||||
$this->drupalPostForm('admin/modules', array('modules[Testing][config_install_dependency_test][enable]' => TRUE), t('Install'));
|
||||
$this->assertRaw('Unable to install Config install dependency test, <em class="placeholder">config_other_module_config_test.weird_simple_config, config_test.dynamic.other_module_test_with_dependency</em> have unmet dependencies.');
|
||||
$this->assertRaw('Unable to install <em class="placeholder">Config install dependency test</em> due to unmet dependencies: <em class="placeholder">config_test.dynamic.other_module_test_with_dependency (config_other_module_config_test)</em>');
|
||||
|
||||
$this->drupalPostForm('admin/modules', array('modules[Testing][config_other_module_config_test][enable]' => TRUE), t('Install'));
|
||||
$this->drupalPostForm('admin/modules', array('modules[Testing][config_install_dependency_test][enable]' => TRUE), t('Install'));
|
||||
|
|
|
@ -199,8 +199,8 @@ class ConfigInstallTest extends KernelTestBase {
|
|||
}
|
||||
catch (UnmetDependenciesException $e) {
|
||||
$this->assertEqual($e->getExtension(), 'config_install_dependency_test');
|
||||
$this->assertEqual($e->getConfigObjects(), ['config_other_module_config_test.weird_simple_config', 'config_test.dynamic.other_module_test_with_dependency']);
|
||||
$this->assertEqual($e->getMessage(), 'Configuration objects (config_other_module_config_test.weird_simple_config, config_test.dynamic.other_module_test_with_dependency) provided by config_install_dependency_test have unmet dependencies');
|
||||
$this->assertEqual($e->getConfigObjects(), ['config_test.dynamic.other_module_test_with_dependency' => ['config_other_module_config_test']]);
|
||||
$this->assertEqual($e->getMessage(), 'Configuration objects provided by <em class="placeholder">config_install_dependency_test</em> have unmet dependencies: <em class="placeholder">config_test.dynamic.other_module_test_with_dependency (config_other_module_config_test)</em>');
|
||||
}
|
||||
$this->installModules(['config_other_module_config_test']);
|
||||
$this->installModules(['config_install_dependency_test']);
|
||||
|
|
Loading…
Reference in New Issue