diff --git a/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/core/lib/Drupal/Core/Extension/ModuleInstaller.php index 5246946e09..b95d3365f8 100644 --- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php @@ -2,6 +2,7 @@ namespace Drupal\Core\Extension; +use Drupal\Component\Version\DrupalSemver; use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\DrupalKernelInterface; @@ -81,11 +82,18 @@ public function addUninstallValidator(ModuleUninstallValidatorInterface $uninsta */ public function install(array $module_list, $enable_dependencies = TRUE) { $extension_config = \Drupal::configFactory()->getEditable('core.extension'); + // Get all module data so we can find dependencies and sort and find the + // core requirements. The module list needs to be reset so that it can + // re-scan and include any new modules that may have been added directly + // into the filesystem. + $module_data = \Drupal::service('extension.list.module')->reset()->getList(); + foreach ($module_list as $module) { + if (!DrupalSemver::satisfies(\Drupal::VERSION, $module_data[$module]->info['core'])) { + throw new MissingDependencyException("Unable to install modules: module '$module' is incompatible with this version of Drupal core."); + } + } if ($enable_dependencies) { - // Get all module data so we can find dependencies and sort. - // The module list needs to be reset so that it can re-scan and include - // any new modules that may have been added directly into the filesystem. - $module_data = \Drupal::service('extension.list.module')->reset()->getList(); + $module_list = $module_list ? array_combine($module_list, $module_list) : []; if ($missing_modules = array_diff_key($module_list, $module_data)) { // One or more of the given modules doesn't exist. @@ -110,6 +118,9 @@ public function install(array $module_list, $enable_dependencies = TRUE) { // Skip already installed modules. if (!isset($module_list[$dependency]) && !isset($installed_modules[$dependency])) { + if (!DrupalSemver::satisfies(\Drupal::VERSION, $module_data[$dependency]->info['core'])) { + throw new MissingDependencyException("Unable to install modules: module '$module'. Its dependency module '$dependency' is incompatible with this version of Drupal core."); + } $module_list[$dependency] = $dependency; } } diff --git a/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php b/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php index ff87c32760..490301a0ae 100644 --- a/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php +++ b/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php @@ -3,6 +3,7 @@ namespace Drupal\KernelTests\Core\Extension; use Drupal\Core\Database\Database; +use Drupal\Core\Extension\MissingDependencyException; use Drupal\KernelTests\KernelTestBase; use Symfony\Component\Routing\Exception\RouteNotFoundException; @@ -85,4 +86,43 @@ public function testKernelRebuildDuringHookInstall() { $this->assertTrue($module_installer->install(['module_test'])); } + /** + * Tests install with a module with an invalid core version. + * + * @dataProvider providerTestInvalidCoreInstall + * @covers ::install + */ + public function testInvalidCoreInstall($install_dependencies) { + $this->expectException(MissingDependencyException::class); + $this->expectExceptionMessage("Unable to install modules: module 'system_incompatible_core_version_test_99x' is incompatible with this version of Drupal core."); + $this->container->get('module_installer')->install(['system_incompatible_core_version_test_99x'], $install_dependencies); + } + + /** + * Tests install with a dependency with invalid core. + * + * @covers ::install + */ + public function testDependencyInvalidCoreInstall() { + $this->expectException(MissingDependencyException::class); + $this->expectExceptionMessage("Unable to install modules: module 'system_incompatible_core_version_dependencies_test'. Its dependency module 'system_incompatible_core_version_test' is incompatible with this version of Drupal core."); + $this->container->get('module_installer')->install(['system_incompatible_core_version_dependencies_test']); + } + + /** + * Tests no dependencies install with a dependency with invalid core. + * + * @covers ::install + */ + public function testDependencyInvalidCoreInstallNoDependencies() { + $this->assertTrue($this->container->get('module_installer')->install(['system_incompatible_core_version_dependencies_test'], FALSE)); + } + + public function providerTestInvalidCoreInstall() { + return [ + 'no dependencies' => [FALSE], + 'install_dependencies' => [TRUE], + ]; + } + }