diff --git a/core/lib/Drupal/Core/Extension/ThemeHandler.php b/core/lib/Drupal/Core/Extension/ThemeHandler.php index 3363efc..f22fcfa 100644 --- a/core/lib/Drupal/Core/Extension/ThemeHandler.php +++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php @@ -272,6 +272,7 @@ public function rebuildThemeData() { 'screenshot' => 'screenshot.png', 'php' => DRUPAL_MINIMUM_PHP, 'libraries' => array(), + 'dependencies' => array(), ); $sub_themes = array(); @@ -358,6 +359,11 @@ public function rebuildThemeData() { } } + // Store the list of module dependencies separately from the full requires list. + foreach ($themes as $key => $theme) { + $themes[$key]->module_dependencies = isset($theme->base_themes) ? array_diff_key($theme->requires, $theme->base_themes) : $theme->requires; + } + return $themes; } diff --git a/core/lib/Drupal/Core/Extension/ThemeInstaller.php b/core/lib/Drupal/Core/Extension/ThemeInstaller.php index f86a08c..fbfe1e9 100644 --- a/core/lib/Drupal/Core/Extension/ThemeInstaller.php +++ b/core/lib/Drupal/Core/Extension/ThemeInstaller.php @@ -134,14 +134,13 @@ public function install(array $theme_list, $install_dependencies = TRUE) { } while (list($theme) = each($theme_list)) { - $module_dependencies = array_diff_key($theme_data[$theme]->requires, $theme_data); + $module_dependencies = $theme_data[$theme]->module_dependencies; $theme_dependencies = array_diff_key($theme_data[$theme]->requires, $module_dependencies); $this->getModuleInstaller()->install(array_keys($module_dependencies)); - $theme_data[$theme]->requires = $theme_dependencies; // Add dependencies to the list. The new themes will be processed as // the while loop continues. - foreach (array_keys($theme_data[$theme]->requires) as $dependency) { + foreach (array_keys($theme_dependencies) as $dependency) { if (!isset($theme_data[$dependency])) { // The dependency does not exist. return FALSE; diff --git a/core/modules/system/src/Controller/SystemController.php b/core/modules/system/src/Controller/SystemController.php index 98d6179..d6c0f05 100644 --- a/core/modules/system/src/Controller/SystemController.php +++ b/core/modules/system/src/Controller/SystemController.php @@ -11,6 +11,7 @@ use Drupal\Core\Menu\MenuTreeParameters; use Drupal\Core\Theme\ThemeAccessCheck; use Drupal\Core\Url; +use Drupal\system\Form\ModulesListForm; use Drupal\system\SystemManager; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -202,6 +203,7 @@ public function themesPage() { $theme_groups = array('installed' => array(), 'uninstalled' => array()); $admin_theme = $config->get('admin'); $admin_theme_options = array(); + $modules = array(); foreach ($themes as &$theme) { if (!empty($theme->info['hidden'])) { @@ -244,9 +246,37 @@ public function themesPage() { $theme->incompatible_base = (isset($theme->info['base theme']) && !($theme->base_themes === array_filter($theme->base_themes))); // Confirm that the theme engine is available. $theme->incompatible_engine = isset($theme->info['engine']) && !isset($theme->owner); + // Confirm that module dependencies are available. + $theme->incompatible_module = FALSE; } + + // Check module dependencies. + if ($theme->module_dependencies) { + if (empty($modules)) { + $modules = system_rebuild_module_data(); + } + foreach ($theme->module_dependencies as $dependency => $version) { + if ($incompatible = ModulesListForm::checkDependency($modules, $dependency, $version)) { + $theme->module_dependencies[$dependency] = $incompatible; + $theme->incompatible_module = TRUE; + } + // Only display visible modules. + elseif (!empty($modules[$dependency]->hidden)) { + unset($theme->module_dependencies[$dependency]); + } else { + $name = $modules[$dependency]->info['name']; + if ($modules[$dependency]->status) { + $theme->module_dependencies[$dependency] = $this->t('@module', array('@module' => $name)); + } + else { + $theme->module_dependencies[$dependency] = $this->t('@module (disabled)', array('@module' => $name)); + } + } + } + } + $theme->operations = array(); - if (!empty($theme->status) || !$theme->incompatible_core && !$theme->incompatible_php && !$theme->incompatible_base && !$theme->incompatible_engine) { + if (!empty($theme->status) || !$theme->incompatible_core && !$theme->incompatible_php && !$theme->incompatible_base && !$theme->incompatible_engine && !$theme->incompatible_module) { // Create the operations links. $query['theme'] = $theme->getName(); if ($this->themeAccess->checkAccess($theme->getName())) { diff --git a/core/modules/system/src/Form/ModulesListForm.php b/core/modules/system/src/Form/ModulesListForm.php index 7831c38..256b94c 100644 --- a/core/modules/system/src/Form/ModulesListForm.php +++ b/core/modules/system/src/Form/ModulesListForm.php @@ -187,10 +187,45 @@ public function buildForm(array $form, FormStateInterface $form_state) { } /** + * @param array $modules + * The list of existing modules. + * @param $dependency + * The dependency to check. + * @param $version + * Version information from the module whose dependency we are checking. + * + * @return + * NULL if compatible, otherwise a string describing the incompatibility. + */ + public static function checkDependency(array $modules, $dependency, $version) { + if (!isset($modules[$dependency])) { + return t('@module (missing)', array('@module' => Unicode::ucfirst($dependency))); + } + // Only display visible modules. + elseif (empty($modules[$dependency]->hidden)) { + $name = $modules[$dependency]->info['name']; + // Check if it is incompatible with the dependency's version. + if ($incompatible_version = drupal_check_incompatibility($version, str_replace(\Drupal::CORE_COMPATIBILITY . '-', '', $modules[$dependency]->info['version']))) { + return t('@module (incompatible with version @version)', array( + '@module' => $name . $incompatible_version, + '@version' => $modules[$dependency]->info['version'], + )); + } + // Disable the checkbox if the dependency is incompatible with this + // version of Drupal core. + elseif ($modules[$dependency]->info['core'] != \Drupal::CORE_COMPATIBILITY) { + return t('@module (incompatible with this version of Drupal core)', array( + '@module' => $name, + )); + } + } + } + + /** * Builds a table row for the system modules page. * * @param array $modules - * The list existing modules. + * The list of existing modules. * @param \Drupal\Core\Extension\Extension $module * The module for which to build the form row. * @param $distribution @@ -297,31 +332,14 @@ protected function buildRow(array $modules, Extension $module, $distribution) { // If this module requires other modules, add them to the array. foreach ($module->requires as $dependency => $version) { - if (!isset($modules[$dependency])) { - $row['#requires'][$dependency] = $this->t('@module (missing)', array('@module' => Unicode::ucfirst($dependency))); + if ($incompatible = $this->checkDependency($modules, $dependency, $version)) { + $row['#requires'][$dependency] = $incompatible; $row['enable']['#disabled'] = TRUE; } // Only display visible modules. elseif (empty($modules[$dependency]->hidden)) { $name = $modules[$dependency]->info['name']; - // Disable the module's checkbox if it is incompatible with the - // dependency's version. - if ($incompatible_version = drupal_check_incompatibility($version, str_replace(\Drupal::CORE_COMPATIBILITY . '-', '', $modules[$dependency]->info['version']))) { - $row['#requires'][$dependency] = $this->t('@module (incompatible with version @version)', array( - '@module' => $name . $incompatible_version, - '@version' => $modules[$dependency]->info['version'], - )); - $row['enable']['#disabled'] = TRUE; - } - // Disable the checkbox if the dependency is incompatible with this - // version of Drupal core. - elseif ($modules[$dependency]->info['core'] != \Drupal::CORE_COMPATIBILITY) { - $row['#requires'][$dependency] = $this->t('@module (incompatible with this version of Drupal core)', array( - '@module' => $name, - )); - $row['enable']['#disabled'] = TRUE; - } - elseif ($modules[$dependency]->status) { + if ($modules[$dependency]->status) { $row['#requires'][$dependency] = $this->t('@module', array('@module' => $name)); } else { diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index 2b4eb8f..d050ecd 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -225,6 +225,7 @@ function template_preprocess_system_modules_details(&$variables) { ]; $module['requires'] = $renderer->render($requires); } + // @TODO: Add theme dependencies. if (!empty($module['#required_by'])) { $required_by = [ '#theme' => 'item_list', @@ -350,6 +351,15 @@ function template_preprocess_system_themes_page(&$variables) { $current_theme['is_default'] = $theme->is_default; $current_theme['is_admin'] = $theme->is_admin; + $current_theme['requires'] = ''; + if (!empty($theme->module_dependencies)) { + $current_theme['requires'] = [ + '#theme' => 'item_list', + '#items' => $theme->module_dependencies, + '#context' => ['list_style' => 'comma-list'], + ]; + } + // Make sure to provide feedback on compatibility. $current_theme['incompatible'] = ''; if (!empty($theme->incompatible_core)) { @@ -370,8 +380,9 @@ function template_preprocess_system_themes_page(&$variables) { elseif (!empty($theme->incompatible_engine)) { $current_theme['incompatible'] = t('This theme requires the theme engine @theme_engine to operate correctly.', array('@theme_engine' => $theme->info['engine'])); } - - $current_theme['requires'] = $theme->requires; + elseif (!empty($theme->incompatible_module)) { + $current_theme['incompatible'] = t('This theme requires the listed modules to operate correctly.'); + } // Build operation links. $current_theme['operations'] = array( diff --git a/core/modules/system/templates/system-themes-page.html.twig b/core/modules/system/templates/system-themes-page.html.twig index 02a0a82..45b4930 100644 --- a/core/modules/system/templates/system-themes-page.html.twig +++ b/core/modules/system/templates/system-themes-page.html.twig @@ -22,6 +22,7 @@ * - notes: Identifies what context this theme is being used in, e.g., * default theme, admin theme. * - incompatible: Text describing any compatibility issues. + * - requires: A list of modules that this theme requires. * - operations: A list of operation links, e.g., Settings, Enable, Disable, * etc. these links should only be displayed if the theme is compatible. * @@ -62,13 +63,13 @@ {%- endif -%}
{{ theme.description }}
+ {% if theme.requires %} +
Requires: {{ theme.requires }}
+ {% endif %} {# Display operation links if the theme is compatible. #} {% if theme.incompatible %}
{{ theme.incompatible }}
{% else %} - {% if theme.requires %} - Module dependencies: {{ theme.requires | keys | safe_join(', ')}} - {% endif %} {{ theme.operations }} {% endif %} diff --git a/core/themes/stable/templates/admin/system-themes-page.html.twig b/core/themes/stable/templates/admin/system-themes-page.html.twig index 333278f..0bc0439 100644 --- a/core/themes/stable/templates/admin/system-themes-page.html.twig +++ b/core/themes/stable/templates/admin/system-themes-page.html.twig @@ -22,6 +22,7 @@ * - notes: Identifies what context this theme is being used in, e.g., * default theme, admin theme. * - incompatible: Text describing any compatibility issues. + * - requires: A list of modules that this theme requires. * - operations: A list of operation links, e.g., Settings, Enable, Disable, * etc. these links should only be displayed if the theme is compatible. * @@ -60,13 +61,13 @@ {%- endif -%}
{{ theme.description }}
+ {% if theme.requires %} +
Requires: {{ theme.requires }}
+ {% endif %} {# Display operation links if the theme is compatible. #} {% if theme.incompatible %}
{{ theme.incompatible }}
{% else %} - {% if theme.requires %} - Module dependencies: {{ theme.requires | keys | safe_join(', ')}} - {% endif %} {{ theme.operations }} {% endif %}