diff --git a/core/core.services.yml b/core/core.services.yml index 8fe29d2..1608ce0 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1076,7 +1076,7 @@ services: class: Drupal\Core\EventSubscriber\ConfigImportSubscriber tags: - { name: event_subscriber } - arguments: ['@theme_handler'] + arguments: ['@theme_handler', '@module_installer'] config_snapshot_subscriber: class: Drupal\Core\EventSubscriber\ConfigSnapshotSubscriber tags: diff --git a/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php index 6a69082..cd4d989 100644 --- a/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php @@ -12,6 +12,7 @@ use Drupal\Core\Config\ConfigImporterEvent; use Drupal\Core\Config\ConfigImportValidateEventSubscriberBase; use Drupal\Core\Config\ConfigNameException; +use Drupal\Core\Extension\ModuleInstallerInterface; use Drupal\Core\Extension\ThemeHandlerInterface; use Drupal\Core\Site\Settings; @@ -42,13 +43,23 @@ class ConfigImportSubscriber extends ConfigImportValidateEventSubscriberBase { protected $themeHandler; /** + * The theme handler. + * + * @var \Drupal\Core\Extension\ThemeHandlerInterface + */ + protected $moduleInstaller; + + /** * Constructs the ConfigImportSubscriber. * * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler * The theme handler. + * @param \Drupal\Core\Extension\ModuleInstallerInterface $module_installer + * The module installer. */ - public function __construct(ThemeHandlerInterface $theme_handler) { + public function __construct(ThemeHandlerInterface $theme_handler, ModuleInstallerInterface $module_installer) { $this->themeHandler = $theme_handler; + $this->moduleInstaller = $module_installer; } /** @@ -133,6 +144,14 @@ protected function validateModules(ConfigImporter $config_importer) { } } + // Ensure that modules can be uninstalled. + if ($reasons = $this->moduleInstaller->validateUninstall($uninstalls)) { + foreach ($reasons as $module => $reason) { + $module_name = $module_data[$module]->info['name']; + $config_importer->logError($this->t('Unable to uninstall the %module module because: !reason.', array('%module' => $module_name, '!reason' => implode(', ', $reason)))); + } + } + // Ensure that the install profile is not being uninstalled. if (in_array($install_profile, $uninstalls)) { $profile_name = $module_data[$install_profile]->info['name']; diff --git a/core/modules/config/src/Tests/ConfigImporterTest.php b/core/modules/config/src/Tests/ConfigImporterTest.php index e39baf6..89c7a6c 100644 --- a/core/modules/config/src/Tests/ConfigImporterTest.php +++ b/core/modules/config/src/Tests/ConfigImporterTest.php @@ -649,6 +649,29 @@ public function testMissingCoreExtension() { } /** + * Tests uninstall validators being called during synchronisation. + * + * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber + */ + public function testMissingExtensionValidation() { + $staging = $this->container->get('config.storage.staging'); + $extensions = $staging->read('core.extension'); + // Remove the config_test module. + unset($extensions['module']['system']); + $staging->write('core.extension', $extensions); + + try { + $this->configImporter->reset()->import(); + $this->fail('ConfigImporterException not thrown, invalid import was not stopped due to missing dependencies.'); + } + catch (ConfigImporterException $e) { + $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.'); + $error_log = $this->configImporter->getErrors(); + $this->assertEqual(['Unable to uninstall the System module because: The System module is required.'], $error_log); + } + } + + /** * Tests install profile validation during configuration import. * * @see \Drupal\Core\EventSubscriber\ConfigImportSubscriber