Mercurial > hg > isophonics-drupal-site
view core/lib/Drupal/Core/Extension/ThemeInstaller.php @ 12:7a779792577d
Update Drupal core to v8.4.5 (via Composer)
author | Chris Cannam |
---|---|
date | Fri, 23 Feb 2018 15:52:07 +0000 |
parents | 4c8ae668cc8c |
children | 1fec387a4317 |
line wrap: on
line source
<?php namespace Drupal\Core\Extension; use Drupal\Core\Asset\AssetCollectionOptimizerInterface; use Drupal\Core\Cache\Cache; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\ConfigInstallerInterface; use Drupal\Core\Config\ConfigManagerInterface; use Drupal\Core\Routing\RouteBuilderInterface; use Drupal\Core\State\StateInterface; use Psr\Log\LoggerInterface; /** * Manages theme installation/uninstallation. */ class ThemeInstaller implements ThemeInstallerInterface { /** * @var \Drupal\Core\Extension\ThemeHandlerInterface */ protected $themeHandler; /** * @var \Drupal\Core\Config\ConfigFactoryInterface */ protected $configFactory; /** * @var \Drupal\Core\Config\ConfigInstallerInterface */ protected $configInstaller; /** * @var \Drupal\Core\Extension\ModuleHandlerInterface */ protected $moduleHandler; /** * @var \Drupal\Core\State\StateInterface */ protected $state; /** * @var \Drupal\Core\Config\ConfigManagerInterface */ protected $configManager; /** * @var \Drupal\Core\Asset\AssetCollectionOptimizerInterface */ protected $cssCollectionOptimizer; /** * @var \Drupal\Core\Routing\RouteBuilderInterface */ protected $routeBuilder; /** * @var \Psr\Log\LoggerInterface */ protected $logger; /** * Constructs a new ThemeInstaller. * * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler * The theme handler. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory to get the installed themes. * @param \Drupal\Core\Config\ConfigInstallerInterface $config_installer * (optional) The config installer to install configuration. This optional * to allow the theme handler to work before Drupal is installed and has a * database. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler to fire themes_installed/themes_uninstalled hooks. * @param \Drupal\Core\Config\ConfigManagerInterface $config_manager * The config manager used to uninstall a theme. * @param \Drupal\Core\Asset\AssetCollectionOptimizerInterface $css_collection_optimizer * The CSS asset collection optimizer service. * @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder * (optional) The route builder service to rebuild the routes if a theme is * installed. * @param \Psr\Log\LoggerInterface $logger * A logger instance. * @param \Drupal\Core\State\StateInterface $state * The state store. */ public function __construct(ThemeHandlerInterface $theme_handler, ConfigFactoryInterface $config_factory, ConfigInstallerInterface $config_installer, ModuleHandlerInterface $module_handler, ConfigManagerInterface $config_manager, AssetCollectionOptimizerInterface $css_collection_optimizer, RouteBuilderInterface $route_builder, LoggerInterface $logger, StateInterface $state) { $this->themeHandler = $theme_handler; $this->configFactory = $config_factory; $this->configInstaller = $config_installer; $this->moduleHandler = $module_handler; $this->configManager = $config_manager; $this->cssCollectionOptimizer = $css_collection_optimizer; $this->routeBuilder = $route_builder; $this->logger = $logger; $this->state = $state; } /** * {@inheritdoc} */ public function install(array $theme_list, $install_dependencies = TRUE) { $extension_config = $this->configFactory->getEditable('core.extension'); $theme_data = $this->themeHandler->rebuildThemeData(); if ($install_dependencies) { $theme_list = array_combine($theme_list, $theme_list); if ($missing = array_diff_key($theme_list, $theme_data)) { // One or more of the given themes doesn't exist. throw new \InvalidArgumentException('Unknown themes: ' . implode(', ', $missing) . '.'); } // Only process themes that are not installed currently. $installed_themes = $extension_config->get('theme') ?: []; if (!$theme_list = array_diff_key($theme_list, $installed_themes)) { // Nothing to do. All themes already installed. return TRUE; } while (list($theme) = each($theme_list)) { // 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) { if (!isset($theme_data[$dependency])) { // The dependency does not exist. return FALSE; } // Skip already installed themes. if (!isset($theme_list[$dependency]) && !isset($installed_themes[$dependency])) { $theme_list[$dependency] = $dependency; } } } // Set the actual theme weights. $theme_list = array_map(function ($theme) use ($theme_data) { return $theme_data[$theme]->sort; }, $theme_list); // Sort the theme list by their weights (reverse). arsort($theme_list); $theme_list = array_keys($theme_list); } else { $installed_themes = $extension_config->get('theme') ?: []; } $themes_installed = []; foreach ($theme_list as $key) { // Only process themes that are not already installed. $installed = $extension_config->get("theme.$key") !== NULL; if ($installed) { continue; } // Throw an exception if the theme name is too long. if (strlen($key) > DRUPAL_EXTENSION_NAME_MAX_LENGTH) { throw new ExtensionNameLengthException("Theme name $key is over the maximum allowed length of " . DRUPAL_EXTENSION_NAME_MAX_LENGTH . ' characters.'); } // Validate default configuration of the theme. If there is existing // configuration then stop installing. $this->configInstaller->checkConfigurationToInstall('theme', $key); // The value is not used; the weight is ignored for themes currently. Do // not check schema when saving the configuration. $extension_config ->set("theme.$key", 0) ->save(TRUE); // Add the theme to the current list. // @todo Remove all code that relies on $status property. $theme_data[$key]->status = 1; $this->themeHandler->addTheme($theme_data[$key]); // Update the current theme data accordingly. $current_theme_data = $this->state->get('system.theme.data', []); $current_theme_data[$key] = $theme_data[$key]; $this->state->set('system.theme.data', $current_theme_data); // Reset theme settings. $theme_settings = &drupal_static('theme_get_setting'); unset($theme_settings[$key]); // @todo Remove system_list(). $this->systemListReset(); // Only install default configuration if this theme has not been installed // already. if (!isset($installed_themes[$key])) { // Install default configuration of the theme. $this->configInstaller->installDefaultConfig('theme', $key); } $themes_installed[] = $key; // Record the fact that it was installed. $this->logger->info('%theme theme installed.', ['%theme' => $key]); } $this->cssCollectionOptimizer->deleteAll(); $this->resetSystem(); // Invoke hook_themes_installed() after the themes have been installed. $this->moduleHandler->invokeAll('themes_installed', [$themes_installed]); return !empty($themes_installed); } /** * {@inheritdoc} */ public function uninstall(array $theme_list) { $extension_config = $this->configFactory->getEditable('core.extension'); $theme_config = $this->configFactory->getEditable('system.theme'); $list = $this->themeHandler->listInfo(); foreach ($theme_list as $key) { if (!isset($list[$key])) { throw new \InvalidArgumentException("Unknown theme: $key."); } if ($key === $theme_config->get('default')) { throw new \InvalidArgumentException("The current default theme $key cannot be uninstalled."); } if ($key === $theme_config->get('admin')) { throw new \InvalidArgumentException("The current administration theme $key cannot be uninstalled."); } // Base themes cannot be uninstalled if sub themes are installed, and if // they are not uninstalled at the same time. // @todo https://www.drupal.org/node/474684 and // https://www.drupal.org/node/1297856 themes should leverage the module // dependency system. if (!empty($list[$key]->sub_themes)) { foreach ($list[$key]->sub_themes as $sub_key => $sub_label) { if (isset($list[$sub_key]) && !in_array($sub_key, $theme_list, TRUE)) { throw new \InvalidArgumentException("The base theme $key cannot be uninstalled, because theme $sub_key depends on it."); } } } } $this->cssCollectionOptimizer->deleteAll(); $current_theme_data = $this->state->get('system.theme.data', []); foreach ($theme_list as $key) { // The value is not used; the weight is ignored for themes currently. $extension_config->clear("theme.$key"); // Update the current theme data accordingly. unset($current_theme_data[$key]); // Reset theme settings. $theme_settings = &drupal_static('theme_get_setting'); unset($theme_settings[$key]); // Remove all configuration belonging to the theme. $this->configManager->uninstall('theme', $key); } // Don't check schema when uninstalling a theme since we are only clearing // keys. $extension_config->save(TRUE); $this->state->set('system.theme.data', $current_theme_data); // @todo Remove system_list(). $this->themeHandler->refreshInfo(); $this->resetSystem(); $this->moduleHandler->invokeAll('themes_uninstalled', [$theme_list]); } /** * Resets some other systems like rebuilding the route information or caches. */ protected function resetSystem() { if ($this->routeBuilder) { $this->routeBuilder->setRebuildNeeded(); } $this->systemListReset(); // @todo It feels wrong to have the requirement to clear the local tasks // cache here. Cache::invalidateTags(['local_task']); $this->themeRegistryRebuild(); } /** * Wraps drupal_theme_rebuild(). */ protected function themeRegistryRebuild() { drupal_theme_rebuild(); } /** * Wraps system_list_reset(). */ protected function systemListReset() { system_list_reset(); } }