diff --git a/core/lib/Drupal/Core/Extension/ModuleRequiredByThemesUninstallValidator.php b/core/lib/Drupal/Core/Extension/ModuleRequiredByThemesUninstallValidator.php index 6433348e40..23ae25f76f 100644 --- a/core/lib/Drupal/Core/Extension/ModuleRequiredByThemesUninstallValidator.php +++ b/core/lib/Drupal/Core/Extension/ModuleRequiredByThemesUninstallValidator.php @@ -48,11 +48,11 @@ public function __construct(TranslationInterface $string_translation, ModuleExte public function validate($module) { $reasons = []; - $modules_themes_depend_on = $this->getModulesThemesDependOn(); - if (isset($modules_themes_depend_on[$module])) { + $themes_depending_on_module = $this->getThemesDependingOnModule($module); + if (!empty($themes_depending_on_module)) { $module_name = $this->getModuleName($module); - $theme_names = implode(", ", $modules_themes_depend_on[$module]); - $reasons[] = $this->formatPlural(count($modules_themes_depend_on[$module]), + $theme_names = implode(", ", $themes_depending_on_module); + $reasons[] = $this->formatPlural(count($themes_depending_on_module), 'The @module_name module is required by the theme @theme_names', 'The @module_name module is required by the themes @theme_names', ['@module_name' => $module_name, '@theme_names' => $theme_names]); @@ -75,20 +75,23 @@ protected function getModuleName($module) { } /** - * Populate $this->modulesThemesDependOn with modules themes depend on. + * Returns themes that depend on a module. + * + * @param string $module + * The module machine name. + * + * @return string[] + * An array of the names of themes that depend on $module. */ - protected function getModulesThemesDependOn() { - $modules_themes_depend_on = []; + protected function getThemesDependingOnModule($module) { $installed_themes = $this->themeExtensionList->getAllInstalledInfo(); - foreach ($installed_themes as $theme) { - foreach ($theme['dependencies'] as $dependency) { - if (!isset($installed_themes[$dependency])) { - $modules_themes_depend_on[$dependency][] = $theme['name']; - } + $themes_depending_on_module = array_map(function ($theme) use ($module) { + if (in_array($module, $theme['dependencies'])) { + return $theme['name']; } - } + }, $installed_themes); - return $modules_themes_depend_on; + return array_filter($themes_depending_on_module); } } diff --git a/core/lib/Drupal/Core/Extension/ThemeInstaller.php b/core/lib/Drupal/Core/Extension/ThemeInstaller.php index daf2e65a36..9c86e01ac3 100644 --- a/core/lib/Drupal/Core/Extension/ThemeInstaller.php +++ b/core/lib/Drupal/Core/Extension/ThemeInstaller.php @@ -103,6 +103,8 @@ public function __construct(ThemeHandlerInterface $theme_handler, ConfigFactoryI * {@inheritdoc} */ public function install(array $theme_list, $install_dependencies = TRUE) { + $extension_config = $this->configFactory->getEditable('core.extension'); + $theme_data = $this->themeHandler->rebuildThemeData(); $installed_themes = $this->configFactory->get('core.extension')->get('theme') ?: []; @@ -150,7 +152,6 @@ public function install(array $theme_list, $install_dependencies = TRUE) { } $themes_installed = []; - $extension_config = $this->configFactory->getEditable('core.extension'); foreach ($theme_list as $key) { // Only process themes that are not already installed. $installed = $extension_config->get("theme.$key") !== NULL; diff --git a/core/modules/path_alias/path_alias.info.yml b/core/modules/path_alias/path_alias.info.yml index 2a3ded6abc..76bdd35a48 100644 --- a/core/modules/path_alias/path_alias.info.yml +++ b/core/modules/path_alias/path_alias.info.yml @@ -3,6 +3,5 @@ type: module description: 'Provides the API allowing to rename URLs.' package: Core version: VERSION -core: 8.x required: true hidden: true diff --git a/core/modules/system/src/ModuleDependencyMessageTrait.php b/core/modules/system/src/ModuleDependencyMessageTrait.php index 2cb88d242b..3a55356a56 100644 --- a/core/modules/system/src/ModuleDependencyMessageTrait.php +++ b/core/modules/system/src/ModuleDependencyMessageTrait.php @@ -40,8 +40,9 @@ public function checkDependencyMessage(array $modules, $dependency, Dependency $ '@version' => $modules[$dependency]->info['version'], ]); } + // Check if the module is compatible with the installed version of core. - if (!isset($modules[$dependency]->info['core']) || $modules[$dependency]->info['core'] != \Drupal::CORE_COMPATIBILITY) { + if ($modules[$dependency]->info['core_incompatible']) { return $this->t('@module_name (incompatible with this version of Drupal core)', [ '@module_name' => $module_name, ]); diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index ac08488d4f..ea33414fe9 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -124,7 +124,7 @@ function template_preprocess_system_admin_index(&$variables) { * - version: The version of the module. * - links: Administration links provided by the module. * - #requires: A list of modules that the project requires. - * - #required_by: A list of modules that require the project. + * - #required_by: A list of modules and themes that require the project. * - #attributes: A list of attributes for the module wrapper. * * @see \Drupal\system\Form\ModulesListForm @@ -133,14 +133,13 @@ function template_preprocess_system_modules_details(&$variables) { $form = $variables['form']; // Identify modules that are depended on by themes. + // Added here instead of ModuleHandler to avoid recursion. $themes = \Drupal::service('extension.list.theme')->getList(); foreach ($themes as $theme) { - if (!empty($theme->info['dependencies'])) { - foreach ($theme->info['dependencies'] as $dependency) { - if (isset($form[$dependency])) { - // Add themes to the module's required by list. - $form[$dependency]['#required_by'][] = $theme->info['name'] . ' (' . t('Theme') . ')' . (!empty($theme->experimental) ? ' (' . t('Experimental') . ')' : '') . (!$theme->status ? ' (' . t('Disabled') . ')' : ''); - } + foreach ($theme->info['dependencies'] as $dependency) { + if (isset($form[$dependency])) { + // Add themes to the module's required by list. + $form[$dependency]['#required_by'][] = $theme->info['name'] . ' (' . t('Theme') . ')' . (!$theme->status ? ' (' . t('Disabled') . ')' : ''); } } } diff --git a/core/modules/system/tests/src/Functional/Theme/ThemeUiTest.php b/core/modules/system/tests/src/Functional/Theme/ThemeUiTest.php index 53536d3ab3..0e98d2b011 100644 --- a/core/modules/system/tests/src/Functional/Theme/ThemeUiTest.php +++ b/core/modules/system/tests/src/Functional/Theme/ThemeUiTest.php @@ -11,11 +11,6 @@ */ class ThemeUiTest extends BrowserTestBase { - /** - * {@inheritdoc} - */ - public static $modules = ['node', 'block', 'file']; - /** * {@inheritdoc} */ @@ -28,11 +23,7 @@ protected function setUp() { parent::setUp(); $this->drupalLogin($this->adminUser = $this->drupalCreateUser([ - 'access administration pages', - 'view the administration theme', 'administer themes', - 'bypass node access', - 'administer blocks', 'administer modules', ])); } @@ -43,11 +34,7 @@ protected function setUp() { public function testModulePermissions() { // Log in as a user without permission to enable modules. $this->drupalLogin($this->drupalCreateUser([ - 'access administration pages', - 'view the administration theme', 'administer themes', - 'bypass node access', - 'administer blocks', ])); $this->drupalGet('admin/appearance'); @@ -55,20 +42,12 @@ public function testModulePermissions() { // by this message. $this->assertSession()->pageTextContains('This theme requires the listed modules to operate correctly. They must first be enabled by a user with permissions to do so.'); - // The confirmation page should not be reachable. - $this->drupalGet('admin/appearance/install/confirm?theme=test_theme_depending_on_modules&modules%5B0%5D=test_module_required_by_theme&modules%5B1%5D=test_another_module_required_by_theme'); - $this->assertSession()->statusCodeEquals(404); - // The install page should not be reachable. $this->drupalGet('admin/appearance/install?theme=test_theme_depending_on_modules'); $this->assertSession()->statusCodeEquals(404); $this->drupalLogin($this->drupalCreateUser([ - 'access administration pages', - 'view the administration theme', 'administer themes', - 'bypass node access', - 'administer blocks', 'administer modules', ])); $this->drupalGet('admin/appearance'); @@ -88,7 +67,7 @@ public function testThemeInstallWithModuleDependencies($theme_name) { 'test module required by theme (disabled)', 'test another module required by theme (disabled)', ]; - $this->verifyUninstallableTheme($expected_requires_list_items, $theme_name); + $this->assertUninstallableTheme($expected_requires_list_items, $theme_name); // Enable one of the two required modules. $this->drupalPostForm('admin/modules', [ @@ -103,7 +82,7 @@ public function testThemeInstallWithModuleDependencies($theme_name) { $expected_requires_list_items = [ 'test another module required by theme (disabled)', ]; - $this->verifyUninstallableTheme($expected_requires_list_items, $theme_name); + $this->assertUninstallableTheme($expected_requires_list_items, $theme_name); $this->drupalPostForm('admin/modules', [ 'modules[test_another_module_required_by_theme][enable]' => 1, @@ -138,12 +117,8 @@ public function testThemeInstallWithModuleDependencies($theme_name) { 'uninstall[test_another_module_required_by_theme]' => 1, ], 'Uninstall'); $confirmation_message = 'The following modules will be completely uninstalled from your site, and all data from these modules will be lost!test another module required by themetest module required by themeWould you like to continue with uninstalling the above?'; - $page_text = $this->getSession()->getPage()->getText(); - $this->assertNotFalse(strpos($page_text, $confirmation_message)); - $button_xpath = '//input[@type="submit"][@value="Uninstall"]'; - $button = $this->xpath($button_xpath); - $this->assertCount(1, $button); - $button[0]->click(); + $assert_session->pageTextContains($confirmation_message); + $page->pressButton('Uninstall'); $assert_session->pageTextContains('The selected modules have been uninstalled.'); } @@ -152,8 +127,8 @@ public function testThemeInstallWithModuleDependencies($theme_name) { */ public function providerTestThemeInstallWithModuleDependencies() { return [ - ['test theme depending on modules'], - ['test theme with a base theme depending on modules'], + 'test theme depending on modules' => ['test theme depending on modules'], + 'test theme with a base theme depending on modules' => ['test theme with a base theme depending on modules'], ]; } @@ -165,23 +140,18 @@ public function providerTestThemeInstallWithModuleDependencies() { * @param string $theme_name * The name of the theme. */ - protected function verifyUninstallableTheme(array $expected_requires_list_items, $theme_name) { - $themeXpath = "//h3[contains(text(), \"$theme_name\")]"; - $elements = $this->xpath($themeXpath); - $this->assertCount(1, $elements); - $element = $elements[0]; - $container = $element->getParent(); - $requires = $container->find('css', '.theme-info__requires'); - $requires_list_items = $requires->find('css', 'li'); + protected function assertUninstallableTheme(array $expected_requires_list_items, $theme_name) { + $theme_container = $this->getSession()->getPage()->find('css', "h3:contains(\"$theme_name\")")->getParent(); + $requires_list_items = $theme_container->find('css', '.theme-info__requires li'); foreach ($requires_list_items as $key => $item) { $this->assertSame($expected_requires_list_items[$key], $item->getText()); } - $incompatible = $container->find('css', '.incompatible'); + $incompatible = $theme_container->find('css', '.incompatible'); $expected_incompatible_text = 'This theme requires the listed modules to operate correctly. They must first be enabled via the Extend page.'; $this->assertSame($expected_incompatible_text, $incompatible->getText()); - $this->assertFalse($container->hasLink('Install test theme depending on modules theme')); + $this->assertFalse($theme_container->hasLink('Install test theme depending on modules theme')); } /** @@ -189,12 +159,9 @@ protected function verifyUninstallableTheme(array $expected_requires_list_items, */ public function testInstallModuleWithMissingDependencies() { $this->drupalGet('admin/appearance'); - $themeXpath = '//h3[contains(text(), "test theme depending on nonexisting module")]'; - $elements = $this->xpath($themeXpath); - $this->assertCount(1, $elements); - $parent = $elements[0]->find('xpath', '..'); - $this->assertContains('missing', $parent->getText()); - $this->assertContains('This theme requires the listed modules to operate correctly.', $parent->getText()); + $theme_container = $this->getSession()->getPage()->find('css', 'h3:contains("test theme depending on nonexisting module")')->getParent(); + $this->assertContains('missing', $theme_container->getText()); + $this->assertContains('This theme requires the listed modules to operate correctly.', $theme_container->getText()); } } diff --git a/core/modules/system/tests/themes/test_theme_depending_on_modules/test_module_required_by_theme/src/Service.php b/core/modules/system/tests/themes/test_theme_depending_on_modules/test_module_required_by_theme/src/Service.php deleted file mode 100644 index 3e7d7eedfa..0000000000 --- a/core/modules/system/tests/themes/test_theme_depending_on_modules/test_module_required_by_theme/src/Service.php +++ /dev/null @@ -1,7 +0,0 @@ -