Issue #2140511 by alexpott, Gábor Hojtsy, swentel, babruix, ohthehugemanatee, jessebeach, Berdir: Configuration file name collisions silently ignored for default configuration
parent
73069e05e8
commit
6efd90c8dc
|
@ -22,11 +22,11 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
protected $configFactory;
|
protected $configFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The active configuration storage.
|
* The active configuration storages, keyed by collection.
|
||||||
*
|
*
|
||||||
* @var \Drupal\Core\Config\StorageInterface
|
* @var \Drupal\Core\Config\StorageInterface[]
|
||||||
*/
|
*/
|
||||||
protected $activeStorage;
|
protected $activeStorages;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The typed configuration manager.
|
* The typed configuration manager.
|
||||||
|
@ -79,7 +79,7 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
*/
|
*/
|
||||||
public function __construct(ConfigFactoryInterface $config_factory, StorageInterface $active_storage, TypedConfigManagerInterface $typed_config, ConfigManagerInterface $config_manager, EventDispatcherInterface $event_dispatcher) {
|
public function __construct(ConfigFactoryInterface $config_factory, StorageInterface $active_storage, TypedConfigManagerInterface $typed_config, ConfigManagerInterface $config_manager, EventDispatcherInterface $event_dispatcher) {
|
||||||
$this->configFactory = $config_factory;
|
$this->configFactory = $config_factory;
|
||||||
$this->activeStorage = $active_storage;
|
$this->activeStorages[$active_storage->getCollectionName()] = $active_storage;
|
||||||
$this->typedConfig = $typed_config;
|
$this->typedConfig = $typed_config;
|
||||||
$this->configManager = $config_manager;
|
$this->configManager = $config_manager;
|
||||||
$this->eventDispatcher = $event_dispatcher;
|
$this->eventDispatcher = $event_dispatcher;
|
||||||
|
@ -119,7 +119,7 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
$enabled_extensions[] = 'core';
|
$enabled_extensions[] = 'core';
|
||||||
|
|
||||||
foreach ($collection_info->getCollectionNames(TRUE) as $collection) {
|
foreach ($collection_info->getCollectionNames(TRUE) as $collection) {
|
||||||
$config_to_install = $this->listDefaultConfigCollection($collection, $type, $name, $enabled_extensions);
|
$config_to_install = $this->listDefaultConfigToInstall($type, $name, $collection, $enabled_extensions);
|
||||||
if (!empty($config_to_install)) {
|
if (!empty($config_to_install)) {
|
||||||
$this->createConfiguration($collection, $config_to_install);
|
$this->createConfiguration($collection, $config_to_install);
|
||||||
}
|
}
|
||||||
|
@ -130,21 +130,25 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs default configuration for a particular collection.
|
* Lists default configuration for an extension that is available to install.
|
||||||
|
*
|
||||||
|
* This looks in the extension's config/install directory and all of the
|
||||||
|
* currently enabled extensions config/install directories for configuration
|
||||||
|
* that begins with the extension's name.
|
||||||
*
|
*
|
||||||
* @param string $collection
|
|
||||||
* The configuration collection to install.
|
|
||||||
* @param string $type
|
* @param string $type
|
||||||
* The extension type; e.g., 'module' or 'theme'.
|
* The extension type; e.g., 'module' or 'theme'.
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* The name of the module or theme to install default configuration for.
|
* The name of the module or theme to install default configuration for.
|
||||||
|
* @param string $collection
|
||||||
|
* The configuration collection to install.
|
||||||
* @param array $enabled_extensions
|
* @param array $enabled_extensions
|
||||||
* A list of all the currently enabled modules and themes.
|
* A list of all the currently enabled modules and themes.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
* The list of configuration objects to create.
|
* The list of configuration objects to create.
|
||||||
*/
|
*/
|
||||||
protected function listDefaultConfigCollection($collection, $type, $name, array $enabled_extensions) {
|
protected function listDefaultConfigToInstall($type, $name, $collection, array $enabled_extensions) {
|
||||||
// Get all default configuration owned by this extension.
|
// Get all default configuration owned by this extension.
|
||||||
$source_storage = $this->getSourceStorage($collection);
|
$source_storage = $this->getSourceStorage($collection);
|
||||||
$config_to_install = $source_storage->listAll($name . '.');
|
$config_to_install = $source_storage->listAll($name . '.');
|
||||||
|
@ -155,16 +159,17 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
$extension_path = drupal_get_path($type, $name);
|
$extension_path = drupal_get_path($type, $name);
|
||||||
if ($type !== 'core' && is_dir($extension_path . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY)) {
|
if ($type !== 'core' && is_dir($extension_path . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY)) {
|
||||||
$default_storage = new FileStorage($extension_path . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY, $collection);
|
$default_storage = new FileStorage($extension_path . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY, $collection);
|
||||||
$other_module_config = array_filter($default_storage->listAll(), function ($value) use ($name) {
|
$extension_provided_config = array_filter($default_storage->listAll(), function ($config_name) use ($config_to_install, $enabled_extensions) {
|
||||||
return !preg_match('/^' . $name . '\./', $value);
|
// Ensure that we have not already discovered the config to install.
|
||||||
});
|
if (in_array($config_name, $config_to_install)) {
|
||||||
|
return FALSE;
|
||||||
$other_module_config = array_filter($other_module_config, function ($config_name) use ($enabled_extensions) {
|
}
|
||||||
|
// Ensure the configuration is provided by an enabled module.
|
||||||
$provider = Unicode::substr($config_name, 0, strpos($config_name, '.'));
|
$provider = Unicode::substr($config_name, 0, strpos($config_name, '.'));
|
||||||
return in_array($provider, $enabled_extensions);
|
return in_array($provider, $enabled_extensions);
|
||||||
});
|
});
|
||||||
|
|
||||||
$config_to_install = array_merge($config_to_install, $other_module_config);
|
$config_to_install = array_merge($config_to_install, $extension_provided_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $config_to_install;
|
return $config_to_install;
|
||||||
|
@ -190,7 +195,7 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove configuration that already exists in the active storage.
|
// Remove configuration that already exists in the active storage.
|
||||||
$config_to_install = array_diff($config_to_install, $this->getActiveStorage($collection)->listAll());
|
$config_to_install = array_diff($config_to_install, $this->getActiveStorages($collection)->listAll());
|
||||||
|
|
||||||
foreach ($config_to_install as $name) {
|
foreach ($config_to_install as $name) {
|
||||||
// Allow config factory overriders to use a custom configuration object if
|
// Allow config factory overriders to use a custom configuration object if
|
||||||
|
@ -200,7 +205,7 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
$new_config = $overrider->createConfigObject($name, $collection);
|
$new_config = $overrider->createConfigObject($name, $collection);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$new_config = new Config($name, $this->getActiveStorage($collection), $this->eventDispatcher, $this->typedConfig);
|
$new_config = new Config($name, $this->getActiveStorages($collection), $this->eventDispatcher, $this->typedConfig);
|
||||||
}
|
}
|
||||||
if ($data[$name] !== FALSE) {
|
if ($data[$name] !== FALSE) {
|
||||||
$new_config->setData($data[$name]);
|
$new_config->setData($data[$name]);
|
||||||
|
@ -221,7 +226,7 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
->getStorage($entity_type);
|
->getStorage($entity_type);
|
||||||
// It is possible that secondary writes can occur during configuration
|
// It is possible that secondary writes can occur during configuration
|
||||||
// creation. Updates of such configuration are allowed.
|
// creation. Updates of such configuration are allowed.
|
||||||
if ($this->getActiveStorage($collection)->exists($name)) {
|
if ($this->getActiveStorages($collection)->exists($name)) {
|
||||||
$id = $entity_storage->getIDFromConfigName($name, $entity_storage->getEntityType()->getConfigPrefix());
|
$id = $entity_storage->getIDFromConfigName($name, $entity_storage->getEntityType()->getConfigPrefix());
|
||||||
$entity = $entity_storage->load($id);
|
$entity = $entity_storage->load($id);
|
||||||
$entity = $entity_storage->updateFromStorageRecord($entity, $new_config->get());
|
$entity = $entity_storage->updateFromStorageRecord($entity, $new_config->get());
|
||||||
|
@ -290,7 +295,7 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
// Default to using the ExtensionInstallStorage which searches extension's
|
// Default to using the ExtensionInstallStorage which searches extension's
|
||||||
// config directories for default configuration. Only include the profile
|
// config directories for default configuration. Only include the profile
|
||||||
// configuration during Drupal installation.
|
// configuration during Drupal installation.
|
||||||
$this->sourceStorage = new ExtensionInstallStorage($this->activeStorage, InstallStorage::CONFIG_INSTALL_DIRECTORY, $collection, drupal_installation_attempted());
|
$this->sourceStorage = new ExtensionInstallStorage($this->getActiveStorages(StorageInterface::DEFAULT_COLLECTION), InstallStorage::CONFIG_INSTALL_DIRECTORY, $collection, drupal_installation_attempted());
|
||||||
}
|
}
|
||||||
if ($this->sourceStorage->getCollectionName() != $collection) {
|
if ($this->sourceStorage->getCollectionName() != $collection) {
|
||||||
$this->sourceStorage = $this->sourceStorage->createCollection($collection);
|
$this->sourceStorage = $this->sourceStorage->createCollection($collection);
|
||||||
|
@ -308,11 +313,11 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
* @return \Drupal\Core\Config\StorageInterface
|
* @return \Drupal\Core\Config\StorageInterface
|
||||||
* The configuration storage that provides the default configuration.
|
* The configuration storage that provides the default configuration.
|
||||||
*/
|
*/
|
||||||
protected function getActiveStorage($collection = StorageInterface::DEFAULT_COLLECTION) {
|
protected function getActiveStorages($collection = StorageInterface::DEFAULT_COLLECTION) {
|
||||||
if ($this->activeStorage->getCollectionName() != $collection) {
|
if (!isset($this->activeStorages[$collection])) {
|
||||||
$this->activeStorage = $this->activeStorage->createCollection($collection);
|
$this->activeStorages[$collection] = reset($this->activeStorages)->createCollection($collection);
|
||||||
}
|
}
|
||||||
return $this->activeStorage;
|
return $this->activeStorages[$collection];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -329,4 +334,31 @@ class ConfigInstaller implements ConfigInstallerInterface {
|
||||||
public function isSyncing() {
|
public function isSyncing() {
|
||||||
return $this->isSyncing;
|
return $this->isSyncing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function findPreExistingConfiguration($type, $name) {
|
||||||
|
$existing_configuration = array();
|
||||||
|
// Gather information about all the supported collections.
|
||||||
|
$collection_info = $this->configManager->getConfigCollectionInfo();
|
||||||
|
|
||||||
|
// Read enabled extensions directly from configuration to avoid circular
|
||||||
|
// dependencies on ModuleHandler and ThemeHandler.
|
||||||
|
$extension_config = $this->configFactory->get('core.extension');
|
||||||
|
$enabled_extensions = array_keys((array) $extension_config->get('module'));
|
||||||
|
$enabled_extensions += array_keys((array) $extension_config->get('theme'));
|
||||||
|
// Add the extension that will be enabled to the list of enabled extensions.
|
||||||
|
$enabled_extensions[] = $name;
|
||||||
|
foreach ($collection_info->getCollectionNames(TRUE) as $collection) {
|
||||||
|
$config_to_install = $this->listDefaultConfigToInstall($type, $name, $collection, $enabled_extensions);
|
||||||
|
$active_storage = $this->getActiveStorages($collection);
|
||||||
|
foreach ($config_to_install as $config_name) {
|
||||||
|
if ($active_storage->exists($config_name)) {
|
||||||
|
$existing_configuration[$collection][] = $config_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $existing_configuration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,4 +84,26 @@ interface ConfigInstallerInterface {
|
||||||
*/
|
*/
|
||||||
public function isSyncing();
|
public function isSyncing();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds pre-existing configuration objects for the provided extension.
|
||||||
|
*
|
||||||
|
* Extensions can not be installed if configuration objects exist in the
|
||||||
|
* active storage with the same names. This can happen in a number of ways,
|
||||||
|
* commonly:
|
||||||
|
* - if a user has created configuration with the same name as that provided
|
||||||
|
* by the extension.
|
||||||
|
* - if the extension provides default configuration that does not depend on
|
||||||
|
* it and the extension has been uninstalled and is about to the
|
||||||
|
* reinstalled.
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* Type of extension to install.
|
||||||
|
* @param string $name
|
||||||
|
* Name of extension to install.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Array of configuration objects that already exist keyed by collection.
|
||||||
|
*/
|
||||||
|
public function findPreExistingConfiguration($type, $name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,19 @@ class ConfigManager implements ConfigManagerInterface {
|
||||||
return key($entities);
|
return key($entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function loadConfigEntityByName($name) {
|
||||||
|
$entity_type_id = $this->getEntityTypeIdByName($name);
|
||||||
|
if ($entity_type_id) {
|
||||||
|
$entity_type = $this->entityManager->getDefinition($entity_type_id);
|
||||||
|
$id = substr($name, strlen($entity_type->getConfigPrefix()) + 1);
|
||||||
|
return $this->entityManager->getStorage($entity_type_id)->load($id);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -23,6 +23,17 @@ interface ConfigManagerInterface {
|
||||||
*/
|
*/
|
||||||
public function getEntityTypeIdByName($name);
|
public function getEntityTypeIdByName($name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a configuration entity using the configuration name.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* The configuration object name.
|
||||||
|
*
|
||||||
|
* @return \Drupal\Core\Entity\EntityInterface|null
|
||||||
|
* The configuration entity or NULL if it does not exist.
|
||||||
|
*/
|
||||||
|
public function loadConfigEntityByName($name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the entity manager.
|
* Gets the entity manager.
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\Core\Config\PreExistingConfigException.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\Core\Config;
|
||||||
|
|
||||||
|
use Drupal\Component\Utility\String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception thrown if configuration with the same name already exists.
|
||||||
|
*/
|
||||||
|
class PreExistingConfigException extends ConfigException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of configuration objects that already exist in active configuration.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $configObjects = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the module that is being installed.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $extension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of configuration objects that already exist.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* A list of configuration objects that already exist in active
|
||||||
|
* configuration keyed by collection.
|
||||||
|
*/
|
||||||
|
public function getConfigObjects() {
|
||||||
|
return $this->configObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the extension that is being installed.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* The name of the extension that is being installed.
|
||||||
|
*/
|
||||||
|
public function getExtension() {
|
||||||
|
return $this->extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an exception for an extension and a list of configuration objects.
|
||||||
|
*
|
||||||
|
* @param $extension
|
||||||
|
* The name of the extension that is being installed.
|
||||||
|
* @param array $config_objects
|
||||||
|
* A list of configuration objects that already exist in active
|
||||||
|
* configuration, keyed by config collection.
|
||||||
|
*
|
||||||
|
* @return \Drupal\Core\Config\PreExistingConfigException
|
||||||
|
*/
|
||||||
|
public static function create($extension, array $config_objects) {
|
||||||
|
$message = String::format('Configuration objects (@config_names) provided by @extension already exist in active configuration',
|
||||||
|
array(
|
||||||
|
'@config_names' => implode(', ', static::flattenConfigObjects($config_objects)),
|
||||||
|
'@extension' => $extension
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$e = new static($message);
|
||||||
|
$e->configObjects = $config_objects;
|
||||||
|
$e->extension = $extension;
|
||||||
|
return $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flattens the config object array to a single dimensional list.
|
||||||
|
*
|
||||||
|
* @param array $config_objects
|
||||||
|
* A list of configuration objects that already exist in active
|
||||||
|
* configuration, keyed by config collection.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* A list of configuration objects that have been prefixed with their
|
||||||
|
* collection.
|
||||||
|
*/
|
||||||
|
public static function flattenConfigObjects(array $config_objects) {
|
||||||
|
$flat_config_objects = array();
|
||||||
|
foreach ($config_objects as $collection => $config_names) {
|
||||||
|
$config_names = array_map(function ($config_name) use ($collection) {
|
||||||
|
if ($collection != StorageInterface::DEFAULT_COLLECTION) {
|
||||||
|
$config_name = str_replace('.', DIRECTORY_SEPARATOR, $collection) . DIRECTORY_SEPARATOR . $config_name;
|
||||||
|
}
|
||||||
|
return $config_name;
|
||||||
|
}, $config_names);
|
||||||
|
$flat_config_objects = array_merge($flat_config_objects, $config_names);
|
||||||
|
}
|
||||||
|
return $flat_config_objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,6 +10,8 @@ namespace Drupal\Core\Extension;
|
||||||
use Drupal\Component\Serialization\Yaml;
|
use Drupal\Component\Serialization\Yaml;
|
||||||
use Drupal\Core\Cache\Cache;
|
use Drupal\Core\Cache\Cache;
|
||||||
use Drupal\Core\Cache\CacheBackendInterface;
|
use Drupal\Core\Cache\CacheBackendInterface;
|
||||||
|
use Drupal\Core\Config\PreExistingConfigException;
|
||||||
|
use Drupal\Core\Config\StorageInterface;
|
||||||
use Drupal\Core\DrupalKernelInterface;
|
use Drupal\Core\DrupalKernelInterface;
|
||||||
use Drupal\Component\Utility\String;
|
use Drupal\Component\Utility\String;
|
||||||
|
|
||||||
|
@ -149,6 +151,18 @@ class ModuleInstaller implements ModuleInstallerInterface {
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Install profiles can not have config clashes. Configuration that
|
||||||
|
// has the same name as a module's configuration will be used instead.
|
||||||
|
if ($module != drupal_get_profile()) {
|
||||||
|
// Validate default configuration of this module. Bail if unable to
|
||||||
|
// install. Should not continue installing more modules because those
|
||||||
|
// may depend on this one.
|
||||||
|
$existing_configuration = $config_installer->findPreExistingConfiguration('module', $module);
|
||||||
|
if (!empty($existing_configuration)) {
|
||||||
|
throw PreExistingConfigException::create($module, $existing_configuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$extension_config
|
$extension_config
|
||||||
->set("module.$module", 0)
|
->set("module.$module", 0)
|
||||||
->set('module', module_config_sort($extension_config->get('module')))
|
->set('module', module_config_sort($extension_config->get('module')))
|
||||||
|
|
|
@ -13,6 +13,7 @@ use Drupal\Core\Cache\Cache;
|
||||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||||
use Drupal\Core\Config\ConfigInstallerInterface;
|
use Drupal\Core\Config\ConfigInstallerInterface;
|
||||||
use Drupal\Core\Config\ConfigManagerInterface;
|
use Drupal\Core\Config\ConfigManagerInterface;
|
||||||
|
use Drupal\Core\Config\PreExistingConfigException;
|
||||||
use Drupal\Core\Routing\RouteBuilderIndicatorInterface;
|
use Drupal\Core\Routing\RouteBuilderIndicatorInterface;
|
||||||
use Drupal\Core\State\StateInterface;
|
use Drupal\Core\State\StateInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
@ -255,6 +256,13 @@ class ThemeHandler implements ThemeHandlerInterface {
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate default configuration of the theme. If there is existing
|
||||||
|
// configuration then stop installing.
|
||||||
|
$existing_configuration = $this->configInstaller->findPreExistingConfiguration('theme', $key);
|
||||||
|
if (!empty($existing_configuration)) {
|
||||||
|
throw PreExistingConfigException::create($key, $existing_configuration);
|
||||||
|
}
|
||||||
|
|
||||||
// The value is not used; the weight is ignored for themes currently.
|
// The value is not used; the weight is ignored for themes currently.
|
||||||
$extension_config
|
$extension_config
|
||||||
->set("theme.$key", 0)
|
->set("theme.$key", 0)
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
namespace Drupal\config\Tests;
|
namespace Drupal\config\Tests;
|
||||||
|
|
||||||
|
use Drupal\Core\Config\PreExistingConfigException;
|
||||||
|
use Drupal\Core\Config\StorageInterface;
|
||||||
use Drupal\simpletest\KernelTestBase;
|
use Drupal\simpletest\KernelTestBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,6 +117,21 @@ class ConfigInstallTest extends KernelTestBase {
|
||||||
$this->assertEqual($collection, $data['collection']);
|
$this->assertEqual($collection, $data['collection']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests that clashing configuration in collections is detected.
|
||||||
|
try {
|
||||||
|
\Drupal::service('module_installer')->install(['config_collection_clash_install_test']);
|
||||||
|
$this->fail('Expected PreExistingConfigException not thrown.');
|
||||||
|
}
|
||||||
|
catch (PreExistingConfigException $e) {
|
||||||
|
$this->assertEqual($e->getExtension(), 'config_collection_clash_install_test');
|
||||||
|
$this->assertEqual($e->getConfigObjects(), [
|
||||||
|
'another_collection' => ['config_collection_install_test.test'],
|
||||||
|
'collection.test1' => ['config_collection_install_test.test'],
|
||||||
|
'collection.test2' => ['config_collection_install_test.test'],
|
||||||
|
]);
|
||||||
|
$this->assertEqual($e->getMessage(), 'Configuration objects (another_collection/config_collection_install_test.test, collection/test1/config_collection_install_test.test, collection/test2/config_collection_install_test.test) provided by config_collection_clash_install_test already exist in active configuration');
|
||||||
|
}
|
||||||
|
|
||||||
// Test that the we can use the config installer to install all the
|
// Test that the we can use the config installer to install all the
|
||||||
// available default configuration in a particular collection for enabled
|
// available default configuration in a particular collection for enabled
|
||||||
// extensions.
|
// extensions.
|
||||||
|
|
|
@ -2,12 +2,15 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
* Definition of Drupal\config\Tests\ConfigInstallTest.
|
* Contains \Drupal\config\Tests\ConfigInstallWebTest.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Drupal\config\Tests;
|
namespace Drupal\config\Tests;
|
||||||
|
|
||||||
use Drupal\Core\Config\InstallStorage;
|
use Drupal\Core\Config\InstallStorage;
|
||||||
|
use Drupal\Core\Config\PreExistingConfigException;
|
||||||
|
use Drupal\Core\Config\StorageInterface;
|
||||||
|
use Drupal\language\Entity\ConfigurableLanguage;
|
||||||
use Drupal\simpletest\WebTestBase;
|
use Drupal\simpletest\WebTestBase;
|
||||||
use Drupal\Core\Config\FileStorage;
|
use Drupal\Core\Config\FileStorage;
|
||||||
|
|
||||||
|
@ -19,12 +22,19 @@ use Drupal\Core\Config\FileStorage;
|
||||||
*/
|
*/
|
||||||
class ConfigInstallWebTest extends WebTestBase {
|
class ConfigInstallWebTest extends WebTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The admin user used in this test.
|
||||||
|
*/
|
||||||
|
protected $adminUser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function setUp() {
|
protected function setUp() {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->adminUser = $this->drupalCreateUser(array('administer modules', 'administer themes'));
|
||||||
|
|
||||||
// Ensure the global variable being asserted by this test does not exist;
|
// Ensure the global variable being asserted by this test does not exist;
|
||||||
// a previous test executed in this request/process might have set it.
|
// a previous test executed in this request/process might have set it.
|
||||||
unset($GLOBALS['hook_config_test']);
|
unset($GLOBALS['hook_config_test']);
|
||||||
|
@ -82,6 +92,18 @@ class ConfigInstallWebTest extends WebTestBase {
|
||||||
$this->assertIdentical($config_entity->get('label'), 'Customized integration config label');
|
$this->assertIdentical($config_entity->get('label'), 'Customized integration config label');
|
||||||
|
|
||||||
// Reinstall the integration module.
|
// Reinstall the integration module.
|
||||||
|
try {
|
||||||
|
\Drupal::service('module_installer')->install(array('config_integration_test'));
|
||||||
|
$this->fail('Expected PreExistingConfigException not thrown.');
|
||||||
|
}
|
||||||
|
catch (PreExistingConfigException $e) {
|
||||||
|
$this->assertEqual($e->getExtension(), 'config_integration_test');
|
||||||
|
$this->assertEqual($e->getConfigObjects(), [StorageInterface::DEFAULT_COLLECTION => ['config_test.dynamic.config_integration_test']]);
|
||||||
|
$this->assertEqual($e->getMessage(), 'Configuration objects (config_test.dynamic.config_integration_test) provided by config_integration_test already exist in active configuration');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the configuration entity so that the install will work.
|
||||||
|
$config_entity->delete();
|
||||||
\Drupal::service('module_installer')->install(array('config_integration_test'));
|
\Drupal::service('module_installer')->install(array('config_integration_test'));
|
||||||
|
|
||||||
// Verify the integration module's config was re-installed.
|
// Verify the integration module's config was re-installed.
|
||||||
|
@ -91,10 +113,10 @@ class ConfigInstallWebTest extends WebTestBase {
|
||||||
$this->assertIdentical($config_static->isNew(), FALSE);
|
$this->assertIdentical($config_static->isNew(), FALSE);
|
||||||
$this->assertIdentical($config_static->get('foo'), 'default setting');
|
$this->assertIdentical($config_static->get('foo'), 'default setting');
|
||||||
|
|
||||||
// Verify the customized integration config still exists.
|
// Verify the integration config is using the default.
|
||||||
$config_entity = $this->config($default_configuration_entity);
|
$config_entity = \Drupal::config($default_configuration_entity);
|
||||||
$this->assertIdentical($config_entity->isNew(), FALSE);
|
$this->assertIdentical($config_entity->isNew(), FALSE);
|
||||||
$this->assertIdentical($config_entity->get('label'), 'Customized integration config label');
|
$this->assertIdentical($config_entity->get('label'), 'Default integration config label');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -132,21 +154,64 @@ class ConfigInstallWebTest extends WebTestBase {
|
||||||
// created from the testing install profile's system.cron.yml file.
|
// created from the testing install profile's system.cron.yml file.
|
||||||
$config = $this->config($config_name);
|
$config = $this->config($config_name);
|
||||||
$this->assertIdentical($config->get(), $expected_profile_data);
|
$this->assertIdentical($config->get(), $expected_profile_data);
|
||||||
|
}
|
||||||
|
|
||||||
// Turn on the test module, which will attempt to replace the
|
/**
|
||||||
// configuration data. This attempt to replace the active configuration
|
* Tests pre-existing configuration detection.
|
||||||
// should be ignored.
|
*/
|
||||||
\Drupal::service('module_installer')->install(array('config_existing_default_config_test'));
|
public function testPreExistingConfigInstall() {
|
||||||
|
$this->drupalLogin($this->adminUser);
|
||||||
|
|
||||||
// Verify that the test module has not been able to change the data.
|
// Try to install config_install_fail_test and config_test. Doing this
|
||||||
$config = $this->config($config_name);
|
// will install the config_test module first because it is a dependency of
|
||||||
$this->assertIdentical($config->get(), $expected_profile_data);
|
// config_install_fail_test.
|
||||||
|
// @see \Drupal\system\Form\ModulesListForm::submitForm()
|
||||||
|
$this->drupalPostForm('admin/modules', array('modules[Testing][config_test][enable]' => TRUE, 'modules[Testing][config_install_fail_test][enable]' => TRUE), t('Save configuration'));
|
||||||
|
$this->assertRaw('Unable to install Configuration install fail test, <em class="placeholder">config_test.dynamic.dotted.default</em> already exists in active configuration.');
|
||||||
|
|
||||||
// Disable and uninstall the test module.
|
// Uninstall the config_test module to test the confirm form.
|
||||||
\Drupal::service('module_installer')->uninstall(array('config_existing_default_config_test'));
|
$this->drupalPostForm('admin/modules/uninstall', array('uninstall[config_test]' => TRUE), t('Uninstall'));
|
||||||
|
$this->drupalPostForm(NULL, array(), t('Uninstall'));
|
||||||
|
|
||||||
// Verify that the data hasn't been altered by removing the test module.
|
// Try to install config_install_fail_test without selecting config_test.
|
||||||
$config = $this->config($config_name);
|
// The user is shown a confirm form because the config_test module is a
|
||||||
$this->assertIdentical($config->get(), $expected_profile_data);
|
// dependency.
|
||||||
|
// @see \Drupal\system\Form\ModulesListConfirmForm::submitForm()
|
||||||
|
$this->drupalPostForm('admin/modules', array('modules[Testing][config_install_fail_test][enable]' => TRUE), t('Save configuration'));
|
||||||
|
$this->drupalPostForm(NULL, array(), t('Continue'));
|
||||||
|
$this->assertRaw('Unable to install Configuration install fail test, <em class="placeholder">config_test.dynamic.dotted.default</em> already exists in active configuration.');
|
||||||
|
|
||||||
|
// Test that collection configuration clashes during a module install are
|
||||||
|
// reported correctly.
|
||||||
|
\Drupal::service('module_installer')->install(['language']);
|
||||||
|
$this->rebuildContainer();
|
||||||
|
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||||
|
\Drupal::languageManager()
|
||||||
|
->getLanguageConfigOverride('fr', 'config_test.dynamic.dotted.default')
|
||||||
|
->set('label', 'Je suis Charlie')
|
||||||
|
->save();
|
||||||
|
|
||||||
|
$this->drupalPostForm('admin/modules', array('modules[Testing][config_install_fail_test][enable]' => TRUE), t('Save configuration'));
|
||||||
|
$this->assertRaw('Unable to install Configuration install fail test, <em class="placeholder">config_test.dynamic.dotted.default, language/fr/config_test.dynamic.dotted.default</em> already exist in active configuration.');
|
||||||
|
|
||||||
|
// Test installing a theme through the UI that has existing configuration.
|
||||||
|
// This relies on the fact the config_test has been installed and created
|
||||||
|
// the config_test.dynamic.dotted.default configuration and the translation
|
||||||
|
// override created still exists.
|
||||||
|
$this->drupalGet('admin/appearance');
|
||||||
|
$url = $this->xpath("//a[contains(@href,'config_clash_test_theme') and contains(@href,'/install?')]/@href")[0];
|
||||||
|
$this->drupalGet($this->getAbsoluteUrl($url));
|
||||||
|
$this->assertRaw('Unable to install config_clash_test_theme, <em class="placeholder">config_test.dynamic.dotted.default, language/fr/config_test.dynamic.dotted.default</em> already exist in active configuration.');
|
||||||
|
|
||||||
|
// Test installing a theme through the API that has existing configuration.
|
||||||
|
try {
|
||||||
|
\Drupal::service('theme_handler')->install(['config_clash_test_theme']);
|
||||||
|
$this->fail('Expected PreExistingConfigException not thrown.');
|
||||||
|
}
|
||||||
|
catch (PreExistingConfigException $e) {
|
||||||
|
$this->assertEqual($e->getExtension(), 'config_clash_test_theme');
|
||||||
|
$this->assertEqual($e->getConfigObjects(), [StorageInterface::DEFAULT_COLLECTION => ['config_test.dynamic.dotted.default'], 'language.fr' => ['config_test.dynamic.dotted.default']]);
|
||||||
|
$this->assertEqual($e->getMessage(), 'Configuration objects (config_test.dynamic.dotted.default, language/fr/config_test.dynamic.dotted.default) provided by config_clash_test_theme already exist in active configuration');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
namespace Drupal\config\Tests;
|
namespace Drupal\config\Tests;
|
||||||
|
|
||||||
|
use Drupal\Core\Config\PreExistingConfigException;
|
||||||
|
use Drupal\Core\Config\StorageInterface;
|
||||||
use Drupal\simpletest\WebTestBase;
|
use Drupal\simpletest\WebTestBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,10 +59,18 @@ class ConfigOtherModuleTest extends WebTestBase {
|
||||||
// Default configuration provided by config_test should still exist.
|
// Default configuration provided by config_test should still exist.
|
||||||
$this->assertTrue(entity_load('config_test', 'dotted.default', TRUE), 'The configuration is not deleted.');
|
$this->assertTrue(entity_load('config_test', 'dotted.default', TRUE), 'The configuration is not deleted.');
|
||||||
|
|
||||||
// Re-enable module to test that default config is unchanged.
|
// Re-enable module to test that pre-existing default configuration throws
|
||||||
$this->installModule('config_other_module_config_test');
|
// an error.
|
||||||
$config_entity = entity_load('config_test', 'other_module_test', TRUE);
|
$msg = "The expected PreExistingConfigException is thrown by reinstalling config_other_module_config_test.";
|
||||||
$this->assertEqual($config_entity->get('style'), "The piano ain't got no wrong notes.", 'Re-enabling the module does not install default config over the existing config entity.');
|
try {
|
||||||
|
$this->installModule('config_other_module_config_test');
|
||||||
|
$this->fail($msg);
|
||||||
|
}
|
||||||
|
catch (PreExistingConfigException $e) {
|
||||||
|
$this->pass($msg);
|
||||||
|
$this->assertEqual($e->getExtension(), 'config_other_module_config_test');
|
||||||
|
$this->assertEqual($e->getConfigObjects(), [StorageInterface::DEFAULT_COLLECTION => ['config_test.dynamic.other_module_test']]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Clashes with default configuration provided by the config_test module.
|
||||||
|
id: dotted.default
|
||||||
|
label: 'Config install fail'
|
||||||
|
weight: 0
|
||||||
|
protected_property: Default
|
||||||
|
# Intentionally commented out to verify default status behavior.
|
||||||
|
# status: 1
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Clashes with default configuration provided by the config_test module.
|
||||||
|
label: 'Je suis'
|
|
@ -0,0 +1,10 @@
|
||||||
|
name: 'Test theme for configuration clash detection'
|
||||||
|
type: theme
|
||||||
|
description: 'Test theme for configuration clash detection'
|
||||||
|
version: VERSION
|
||||||
|
base theme: classy
|
||||||
|
core: 8.x
|
||||||
|
regions:
|
||||||
|
content: Content
|
||||||
|
left: Left
|
||||||
|
right: Right
|
|
@ -0,0 +1 @@
|
||||||
|
collection: another_collection
|
|
@ -0,0 +1 @@
|
||||||
|
collection: collection.test1
|
|
@ -0,0 +1 @@
|
||||||
|
collection: collection.test2
|
|
@ -0,0 +1 @@
|
||||||
|
label: entity
|
|
@ -0,0 +1,9 @@
|
||||||
|
# This should contain a copy of the configuration from the
|
||||||
|
# config_collection_install_test module.
|
||||||
|
name: 'Config collection clash test module'
|
||||||
|
type: module
|
||||||
|
package: Testing
|
||||||
|
version: VERSION
|
||||||
|
core: 8.x
|
||||||
|
dependencies:
|
||||||
|
- config_collection_install_test
|
|
@ -1,5 +0,0 @@
|
||||||
name: 'Configuration existing default config test'
|
|
||||||
type: module
|
|
||||||
package: Testing
|
|
||||||
version: VERSION
|
|
||||||
core: 8.x
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Clashes with default configuration provided by the config_test module.
|
||||||
|
id: dotted.default
|
||||||
|
label: 'Config install fail'
|
||||||
|
weight: 0
|
||||||
|
protected_property: Default
|
||||||
|
# Intentionally commented out to verify default status behavior.
|
||||||
|
# status: 1
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Clashes with default configuration provided by the config_test module.
|
||||||
|
label: 'Je suis'
|
|
@ -0,0 +1,7 @@
|
||||||
|
name: 'Configuration install fail test'
|
||||||
|
type: module
|
||||||
|
package: Testing
|
||||||
|
version: VERSION
|
||||||
|
core: 8.x
|
||||||
|
dependencies:
|
||||||
|
- config_test
|
|
@ -19,6 +19,10 @@ class FieldImportChangeTest extends FieldUnitTestBase {
|
||||||
/**
|
/**
|
||||||
* Modules to enable.
|
* Modules to enable.
|
||||||
*
|
*
|
||||||
|
* The default configuration provided by field_test_config is imported by
|
||||||
|
* \Drupal\field\Tests\FieldUnitTestBase::setUp() when it installs field
|
||||||
|
* configuration.
|
||||||
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public static $modules = array('field_test_config');
|
public static $modules = array('field_test_config');
|
||||||
|
@ -31,8 +35,6 @@ class FieldImportChangeTest extends FieldUnitTestBase {
|
||||||
$field_id = "entity_test.entity_test.$field_storage_id";
|
$field_id = "entity_test.entity_test.$field_storage_id";
|
||||||
$field_config_name = "field.field.$field_id";
|
$field_config_name = "field.field.$field_id";
|
||||||
|
|
||||||
// Import default config.
|
|
||||||
$this->installConfig(array('field_test_config'));
|
|
||||||
$active = $this->container->get('config.storage');
|
$active = $this->container->get('config.storage');
|
||||||
$staging = $this->container->get('config.storage.staging');
|
$staging = $this->container->get('config.storage.staging');
|
||||||
$this->copyConfig($active, $staging);
|
$this->copyConfig($active, $staging);
|
||||||
|
|
|
@ -21,6 +21,10 @@ class FieldImportDeleteTest extends FieldUnitTestBase {
|
||||||
/**
|
/**
|
||||||
* Modules to enable.
|
* Modules to enable.
|
||||||
*
|
*
|
||||||
|
* The default configuration provided by field_test_config is imported by
|
||||||
|
* \Drupal\field\Tests\FieldUnitTestBase::setUp() when it installs field
|
||||||
|
* configuration.
|
||||||
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public static $modules = array('field_test_config');
|
public static $modules = array('field_test_config');
|
||||||
|
@ -53,9 +57,6 @@ class FieldImportDeleteTest extends FieldUnitTestBase {
|
||||||
// Create a second bundle for the 'Entity test' entity type.
|
// Create a second bundle for the 'Entity test' entity type.
|
||||||
entity_test_create_bundle('test_bundle');
|
entity_test_create_bundle('test_bundle');
|
||||||
|
|
||||||
// Import default config.
|
|
||||||
$this->installConfig(array('field_test_config'));
|
|
||||||
|
|
||||||
// Get the uuid's for the field storages.
|
// Get the uuid's for the field storages.
|
||||||
$field_storage_uuid = FieldStorageConfig::load($field_storage_id)->uuid();
|
$field_storage_uuid = FieldStorageConfig::load($field_storage_id)->uuid();
|
||||||
$field_storage_uuid_2 = FieldStorageConfig::load($field_storage_id_2)->uuid();
|
$field_storage_uuid_2 = FieldStorageConfig::load($field_storage_id_2)->uuid();
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
langcode: en
|
langcode: en
|
||||||
status: true
|
status: true
|
||||||
dependencies: { }
|
dependencies:
|
||||||
|
enforced:
|
||||||
|
module:
|
||||||
|
- forum
|
||||||
name: Forums
|
name: Forums
|
||||||
vid: forums
|
vid: forums
|
||||||
description: 'Forum navigation vocabulary'
|
description: 'Forum navigation vocabulary'
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
namespace Drupal\system\Controller;
|
namespace Drupal\system\Controller;
|
||||||
|
|
||||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||||
|
use Drupal\Core\Config\PreExistingConfigException;
|
||||||
use Drupal\Core\Controller\ControllerBase;
|
use Drupal\Core\Controller\ControllerBase;
|
||||||
use Drupal\Core\Extension\ThemeHandlerInterface;
|
use Drupal\Core\Extension\ThemeHandlerInterface;
|
||||||
use Drupal\Core\Routing\RouteBuilderIndicatorInterface;
|
use Drupal\Core\Routing\RouteBuilderIndicatorInterface;
|
||||||
|
@ -120,12 +121,28 @@ class ThemeController extends ControllerBase {
|
||||||
$theme = $request->get('theme');
|
$theme = $request->get('theme');
|
||||||
|
|
||||||
if (isset($theme)) {
|
if (isset($theme)) {
|
||||||
if ($this->themeHandler->install(array($theme))) {
|
try {
|
||||||
$themes = $this->themeHandler->listInfo();
|
if ($this->themeHandler->install(array($theme))) {
|
||||||
drupal_set_message($this->t('The %theme theme has been installed.', array('%theme' => $themes[$theme]->info['name'])));
|
$themes = $this->themeHandler->listInfo();
|
||||||
|
drupal_set_message($this->t('The %theme theme has been installed.', array('%theme' => $themes[$theme]->info['name'])));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
drupal_set_message($this->t('The %theme theme was not found.', array('%theme' => $theme)), 'error');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
catch (PreExistingConfigException $e) {
|
||||||
drupal_set_message($this->t('The %theme theme was not found.', array('%theme' => $theme)), 'error');
|
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
|
||||||
|
drupal_set_message(
|
||||||
|
$this->formatPlural(
|
||||||
|
count($config_objects),
|
||||||
|
'Unable to install @extension, %config_names already exists in active configuration.',
|
||||||
|
'Unable to install @extension, %config_names already exist in active configuration.',
|
||||||
|
array(
|
||||||
|
'%config_names' => implode(', ', $config_objects),
|
||||||
|
'@extension' => $theme,
|
||||||
|
)),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->redirect('system.themes_page');
|
return $this->redirect('system.themes_page');
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
namespace Drupal\system\Form;
|
namespace Drupal\system\Form;
|
||||||
|
|
||||||
|
use Drupal\Core\Config\PreExistingConfigException;
|
||||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||||
use Drupal\Core\Extension\ModuleInstallerInterface;
|
use Drupal\Core\Extension\ModuleInstallerInterface;
|
||||||
use Drupal\Core\Form\ConfirmFormBase;
|
use Drupal\Core\Form\ConfirmFormBase;
|
||||||
|
@ -157,7 +158,24 @@ class ModulesListConfirmForm extends ConfirmFormBase {
|
||||||
// the form doesn't allow modules with unmet dependencies, so the only way
|
// the form doesn't allow modules with unmet dependencies, so the only way
|
||||||
// this can happen is if the filesystem changed between form display and
|
// this can happen is if the filesystem changed between form display and
|
||||||
// submit, in which case the user has bigger problems.
|
// submit, in which case the user has bigger problems.
|
||||||
$this->moduleInstaller->install(array_keys($this->modules['install']));
|
try {
|
||||||
|
$this->moduleInstaller->install(array_keys($this->modules['install']));
|
||||||
|
}
|
||||||
|
catch (PreExistingConfigException $e) {
|
||||||
|
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
|
||||||
|
drupal_set_message(
|
||||||
|
$this->formatPlural(
|
||||||
|
count($config_objects),
|
||||||
|
'Unable to install @extension, %config_names already exists in active configuration.',
|
||||||
|
'Unable to install @extension, %config_names already exist in active configuration.',
|
||||||
|
array(
|
||||||
|
'%config_names' => implode(', ', $config_objects),
|
||||||
|
'@extension' => $this->modules['install'][$e->getExtension()]
|
||||||
|
)),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets module list after install process, flushes caches and displays a
|
// Gets module list after install process, flushes caches and displays a
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace Drupal\system\Form;
|
||||||
|
|
||||||
use Drupal\Component\Utility\String;
|
use Drupal\Component\Utility\String;
|
||||||
use Drupal\Component\Utility\Unicode;
|
use Drupal\Component\Utility\Unicode;
|
||||||
|
use Drupal\Core\Config\PreExistingConfigException;
|
||||||
use Drupal\Core\Controller\TitleResolverInterface;
|
use Drupal\Core\Controller\TitleResolverInterface;
|
||||||
use Drupal\Core\Access\AccessManagerInterface;
|
use Drupal\Core\Access\AccessManagerInterface;
|
||||||
use Drupal\Core\Entity\EntityManagerInterface;
|
use Drupal\Core\Entity\EntityManagerInterface;
|
||||||
|
@ -517,7 +518,24 @@ class ModulesListForm extends FormBase {
|
||||||
|
|
||||||
// There seem to be no dependencies that would need approval.
|
// There seem to be no dependencies that would need approval.
|
||||||
if (!empty($modules['install'])) {
|
if (!empty($modules['install'])) {
|
||||||
$this->moduleInstaller->install(array_keys($modules['install']));
|
try {
|
||||||
|
$this->moduleInstaller->install(array_keys($modules['install']));
|
||||||
|
}
|
||||||
|
catch (PreExistingConfigException $e) {
|
||||||
|
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
|
||||||
|
drupal_set_message(
|
||||||
|
$this->formatPlural(
|
||||||
|
count($config_objects),
|
||||||
|
'Unable to install @extension, %config_names already exists in active configuration.',
|
||||||
|
'Unable to install @extension, %config_names already exist in active configuration.',
|
||||||
|
array(
|
||||||
|
'%config_names' => implode(', ', $config_objects),
|
||||||
|
'@extension' => $modules['install'][$e->getExtension()]
|
||||||
|
)),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets module list after install process, flushes caches and displays a
|
// Gets module list after install process, flushes caches and displays a
|
||||||
|
|
Loading…
Reference in New Issue