Commit 2c90c67c authored by webchick's avatar webchick

Issue #1067408 by alexpott, Jalandhar, jessebeach, Désiré, neetu morwani,...

Issue #1067408 by alexpott, Jalandhar, jessebeach, Désiré, neetu morwani, dawehner, sun: Themes do not have an installation status.
parent 45e59c9b
module: {}
theme:
stark: 0
theme: {}
disabled:
theme: {}
......@@ -203,7 +203,7 @@ services:
arguments: ['%container.modules%', '@cache.bootstrap']
theme_handler:
class: Drupal\Core\Extension\ThemeHandler
arguments: ['@config.factory', '@module_handler', '@cache.default', '@info_parser', '@config.installer', '@router.builder']
arguments: ['@config.factory', '@module_handler', '@state', '@info_parser', '@config.installer', '@router.builder']
entity.manager:
class: Drupal\Core\Entity\EntityManager
arguments: ['@container.namespaces', '@module_handler', '@cache.discovery', '@language_manager', '@string_translation']
......
......@@ -686,6 +686,8 @@ function install_tasks($install_state) {
'display_name' => t('Install site'),
'type' => 'batch',
),
'install_profile_themes' => array(
),
'install_import_translations' => array(
'display_name' => t('Set up translations'),
'display' => $needs_translations,
......@@ -1827,6 +1829,34 @@ function install_profile_modules(&$install_state) {
return $batch;
}
/**
* Installs themes.
*
* This does not use a batch, since installing themes is faster than modules and
* because an installation profile typically enables 1-3 themes only (default
* theme, base theme, admin theme).
*
* @param $install_state
* An array of information about the current installation state.
*/
function install_profile_themes(&$install_state) {
$theme_handler = \Drupal::service('theme_handler');
// ThemeHandler::enable() resets the current list of themes. The theme used in
// the installer is not necessarily in the list of themes to install, so
// retain the current list.
// @see _drupal_maintenance_theme()
$current_themes = $theme_handler->listInfo();
// Install the themes specified by the installation profile.
$themes = $install_state['profile_info']['themes'];
$theme_handler->enable($themes);
foreach ($current_themes as $theme) {
$theme_handler->addTheme($theme);
}
}
/**
* Imports languages via a batch process during installation.
*
......
......@@ -1077,6 +1077,7 @@ function install_profile_info($profile, $langcode = 'en') {
// Set defaults for module info.
$defaults = array(
'dependencies' => array(),
'themes' => array('stark'),
'description' => '',
'version' => NULL,
'hidden' => FALSE,
......
......@@ -9,26 +9,18 @@
use Drupal\Core\Extension\ExtensionDiscovery;
/**
* Builds a list of bootstrap modules and enabled modules and themes.
* Builds a list of enabled themes.
*
* @param $type
* The type of list to return:
* - module_enabled: All enabled modules.
* - bootstrap: All enabled modules required for bootstrap.
* - theme: All themes.
* - theme: All enabled themes.
*
* @return
* An associative array of modules or themes, keyed by name. For $type
* 'bootstrap' and 'module_enabled', the array values equal the keys.
* An associative array of themes, keyed by name.
* For $type 'theme', the array values are objects representing the
* respective database row, with the 'info' property already unserialized.
*
* @see list_themes()
*
* @todo There are too many layers/levels of caching involved for system_list()
* data. Consider to add a \Drupal::config($name, $cache = TRUE) argument to allow
* callers like system_list() to force-disable a possible configuration
* storage cache or some other way to circumvent it/take it over.
*/
function system_list($type) {
$lists = &drupal_static(__FUNCTION__);
......@@ -40,32 +32,15 @@ function system_list($type) {
'theme' => array(),
'filepaths' => array(),
);
// Build a list of themes.
$enabled_themes = \Drupal::config('core.extension')->get('theme') ?: array();
// @todo Themes include all themes, including disabled/uninstalled. This
// system.theme.data state will go away entirely as soon as themes have
// a proper installation status.
// @see http://drupal.org/node/1067408
$theme_data = \Drupal::state()->get('system.theme.data');
if (empty($theme_data)) {
// @todo: system_list() may be called from _drupal_bootstrap_code(), in
// which case system.module is not loaded yet.
// Prevent a filesystem scan in drupal_load() and include it directly.
// @see http://drupal.org/node/1067408
require_once DRUPAL_ROOT . '/core/modules/system/system.module';
$theme_data = system_rebuild_theme_data();
}
// ThemeHandler maintains the 'system.theme.data' state record.
$theme_data = \Drupal::state()->get('system.theme.data', array());
foreach ($theme_data as $name => $theme) {
$theme->status = (int) isset($enabled_themes[$name]);
$lists['theme'][$name] = $theme;
// Build a list of filenames so drupal_get_filename can use it.
if (isset($enabled_themes[$name])) {
$lists['filepaths'][] = array(
'type' => 'theme',
'name' => $name,
'filepath' => $theme->getPathname(),
);
}
$lists['filepaths'][] = array(
'type' => 'theme',
'name' => $name,
'filepath' => $theme->getPathname(),
);
}
\Drupal::cache('bootstrap')->set('system_list', $lists);
}
......@@ -84,25 +59,17 @@ function system_list($type) {
function system_list_reset() {
drupal_static_reset('system_list');
drupal_static_reset('system_rebuild_module_data');
drupal_static_reset('list_themes');
\Drupal::cache('bootstrap')->delete('system_list');
\Drupal::cache()->delete('system_info');
// Clear the library info cache.
// Libraries may be provided by all extension types, and may be altered by any
// other extensions (types) due to the nature of
// \Drupal\Core\Extension\ModuleHandler::alter() and the fact that profiles
// are recorded and handled as modules.
// @todo Trigger an event upon module install/uninstall and theme
// enable/disable, and move this into an event subscriber.
// @see https://drupal.org/node/2206347
Cache::invalidateTags(array('extension' => TRUE));
// Remove last known theme data state.
// This causes system_list() to call system_rebuild_theme_data() on its next
// invocation. When enabling a module that implements hook_system_info_alter()
// to inject a new (testing) theme or manipulate an existing theme, then that
// will cause system_list_reset() to be called, but theme data is not
// necessarily rebuilt afterwards.
// @todo Obsolete with proper installation status for themes.
\Drupal::state()->delete('system.theme.data');
}
/**
......
......@@ -103,7 +103,21 @@ function drupal_theme_initialize() {
// Determine the active theme for the theme negotiator service. This includes
// the default theme as well as really specific ones like the ajax base theme.
$request = \Drupal::request();
$theme = \Drupal::service('theme.negotiator')->determineActiveTheme($request) ?: 'stark';
$theme = \Drupal::service('theme.negotiator')->determineActiveTheme($request);
// If no theme could be negotiated, or if the negotiated theme is not within
// the list of enabled themes, fall back to the default theme output of core
// and modules (similar to Stark, but without a theme extension at all). This
// is possible, because _drupal_theme_initialize() always loads the Twig theme
// engine.
if (!$theme || !isset($themes[$theme])) {
$theme = 'core';
$theme_key = $theme;
// /core/core.info.yml does not actually exist, but is required because
// Extension expects a pathname.
_drupal_theme_initialize(new Extension('theme', 'core/core.info.yml'));
return;
}
// Store the identifier for retrieving theme settings with.
$theme_key = $theme;
......@@ -401,6 +415,8 @@ function _theme($hook, $variables = array()) {
if (!$module_handler->isLoaded() && !defined('MAINTENANCE_MODE')) {
throw new Exception(t('_theme() may not be called until all modules are loaded.'));
}
// Ensure the theme is initialized.
drupal_theme_initialize();
/** @var \Drupal\Core\Utility\ThemeRegistry $theme_registry */
$theme_registry = \Drupal::service('theme.registry')->getRuntime();
......@@ -851,8 +867,8 @@ function theme_get_setting($setting_name, $theme = NULL) {
// Get the values for the theme-specific settings from the .info.yml files
// of the theme and all its base themes.
if ($theme) {
$themes = list_themes();
$themes = list_themes();
if ($theme && isset($themes[$theme])) {
$theme_object = $themes[$theme];
// Create a list which includes the current theme and all its base themes.
......@@ -874,7 +890,7 @@ function theme_get_setting($setting_name, $theme = NULL) {
// Get the global settings from configuration.
$cache[$theme]->merge(\Drupal::config('system.theme.global')->get());
if ($theme) {
if ($theme && isset($themes[$theme])) {
// Retrieve configured theme-specific settings, if any.
try {
if ($theme_settings = \Drupal::config($theme . '.settings')->get()) {
......@@ -975,13 +991,16 @@ function theme_settings_convert_to_config(array $theme_settings, Config $config)
* @param $theme_list
* An array of theme names.
*
* @return bool
* Whether any of the given themes have been enabled.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::service('theme_handler')->enable().
*
* @see \Drupal\Core\Extension\ThemeHandler::enable().
*/
function theme_enable($theme_list) {
\Drupal::service('theme_handler')->enable($theme_list);
return \Drupal::service('theme_handler')->enable($theme_list);
}
/**
......@@ -990,13 +1009,16 @@ function theme_enable($theme_list) {
* @param $theme_list
* An array of theme names.
*
* @return bool
* Whether any of the given themes have been disabled.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::service('theme_handler')->disable().
*
* @see \Drupal\Core\Extension\ThemeHandler::disable().
*/
function theme_disable($theme_list) {
\Drupal::service('theme_handler')->disable($theme_list);
return \Drupal::service('theme_handler')->disable($theme_list);
}
/**
......
......@@ -66,7 +66,7 @@ function _drupal_maintenance_theme() {
}
// Ensure that system.module is loaded.
if (!function_exists('_system_rebuild_theme_data')) {
if (!function_exists('system_rebuild_theme_data')) {
$module_handler = \Drupal::moduleHandler();
$module_handler->addModule('system', 'core/modules/system');
$module_handler->load('system');
......@@ -74,6 +74,14 @@ function _drupal_maintenance_theme() {
$themes = list_themes();
// If no themes are installed yet, or if the requested custom theme is not
// installed, retrieve all available themes.
if (empty($themes) || !isset($themes[$custom_theme])) {
$theme_handler = \Drupal::service('theme_handler');
$themes = $theme_handler->rebuildThemeData();
$theme_handler->addTheme($themes[$custom_theme]);
}
// list_themes() triggers a \Drupal\Core\Extension\ModuleHandler::alter() in
// maintenance mode, but we can't let themes alter the .info.yml data until
// we know a theme's base themes. So don't set global $theme until after
......
......@@ -41,7 +41,7 @@ public function register(ContainerBuilder $container) {
$container->register('theme_handler', 'Drupal\Core\Extension\ThemeHandler')
->addArgument(new Reference('config.factory'))
->addArgument(new Reference('module_handler'))
->addArgument(new Reference('cache.default'))
->addArgument(new Reference('state'))
->addArgument(new Reference('info_parser'));
}
}
......
......@@ -758,8 +758,6 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
// Refresh the schema to include it.
drupal_get_schema(NULL, TRUE);
// Update the theme registry to include it.
drupal_theme_rebuild();
// Allow modules to react prior to the installation of a module.
$this->invokeAll('module_preinstall', array($module));
......@@ -804,8 +802,18 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
// Record the fact that it was installed.
$modules_installed[] = $module;
// Update the theme registry to include it.
drupal_theme_rebuild();
// Modules can alter theme info, so refresh theme data.
// @todo ThemeHandler cannot be injected into ModuleHandler, since that
// causes a circular service dependency.
// @see https://drupal.org/node/2208429
\Drupal::service('theme_handler')->refreshInfo();
// Allow the module to perform install tasks.
$this->invoke($module, 'install');
// Record the fact that it was installed.
watchdog('system', '%module module installed.', array('%module' => $module), WATCHDOG_INFO);
}
......@@ -912,6 +920,12 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
// Update the theme registry to remove the newly uninstalled module.
drupal_theme_rebuild();
// Modules can alter theme info, so refresh theme data.
// @todo ThemeHandler cannot be injected into ModuleHandler, since that
// causes a circular service dependency.
// @see https://drupal.org/node/2208429
\Drupal::service('theme_handler')->refreshInfo();
watchdog('system', '%module module uninstalled.', array('%module' => $module), WATCHDOG_INFO);
$schema_store->delete($module);
......
......@@ -9,9 +9,9 @@
use Drupal\Component\Utility\String;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ConfigInstallerInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Routing\RouteBuilder;
/**
......@@ -41,7 +41,7 @@ class ThemeHandler implements ThemeHandlerInterface {
*
* @var array
*/
protected $list = array();
protected $list;
/**
* The config factory to get the enabled themes.
......@@ -58,11 +58,11 @@ class ThemeHandler implements ThemeHandlerInterface {
protected $moduleHandler;
/**
* The cache backend to clear the local tasks cache.
* The state backend.
*
* @var \Drupal\Core\Cache\CacheBackendInterface
* @var \Drupal\Core\State\StateInterface
*/
protected $cacheBackend;
protected $state;
/**
* The config installer to install configuration.
......@@ -99,8 +99,8 @@ class ThemeHandler implements ThemeHandlerInterface {
* The config factory to get the enabled themes.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler to fire themes_enabled/themes_disabled hooks.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* The cache backend to clear the local tasks cache.
* @param \Drupal\Core\State\StateInterface $state
* The state store.
* @param \Drupal\Core\Extension\InfoParserInterface $info_parser
* The info parser to parse the theme.info.yml files.
* @param \Drupal\Core\Config\ConfigInstallerInterface $config_installer
......@@ -112,10 +112,10 @@ class ThemeHandler implements ThemeHandlerInterface {
* @param \Drupal\Core\Extension\ExtensionDiscovery $extension_discovery
* (optional) A extension discovery instance (for unit tests).
*/
public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, InfoParserInterface $info_parser, ConfigInstallerInterface $config_installer = NULL, RouteBuilder $route_builder = NULL, ExtensionDiscovery $extension_discovery = NULL) {
public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, StateInterface $state, InfoParserInterface $info_parser, ConfigInstallerInterface $config_installer = NULL, RouteBuilder $route_builder = NULL, ExtensionDiscovery $extension_discovery = NULL) {
$this->configFactory = $config_factory;
$this->moduleHandler = $module_handler;
$this->cacheBackend = $cache_backend;
$this->state = $state;
$this->infoParser = $info_parser;
$this->configInstaller = $config_installer;
$this->routeBuilder = $route_builder;
......@@ -125,10 +125,90 @@ public function __construct(ConfigFactoryInterface $config_factory, ModuleHandle
/**
* {@inheritdoc}
*/
public function enable(array $theme_list) {
$this->clearCssCache();
public function getDefault() {
return $this->configFactory->get('system.theme')->get('default');
}
/**
* {@inheritdoc}
*/
public function setDefault($name) {
if (!isset($this->list)) {
$this->listInfo();
}
if (!isset($this->list[$name])) {
throw new \InvalidArgumentException("$name theme is not enabled.");
}
$this->configFactory->get('system.theme')
->set('default', $name)
->save();
return $this;
}
/**
* {@inheritdoc}
*/
public function enable(array $theme_list, $enable_dependencies = TRUE) {
$extension_config = $this->configFactory->get('core.extension');
$theme_data = $this->rebuildThemeData();
if ($enable_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(String::format('Unknown themes: !themes.', array(
'!themes' => implode(', ', $missing),
)));
}
// Only process themes that are not enabled currently.
$installed_themes = $extension_config->get('theme') ?: array();
if (!$theme_list = array_diff_key($theme_list, $installed_themes)) {
// Nothing to do. All themes already enabled.
return TRUE;
}
$installed_themes += $extension_config->get('disabled.theme') ?: array();
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') ?: array();
$installed_themes += $extension_config->get('disabled.theme') ?: array();
}
$themes_enabled = array();
foreach ($theme_list as $key) {
// Only process themes that are not already enabled.
$enabled = $extension_config->get("theme.$key") !== NULL;
if ($enabled) {
continue;
}
// Throw an exception if the theme name is too long.
if (strlen($key) > DRUPAL_EXTENSION_NAME_MAX_LENGTH) {
throw new ExtensionNameLengthException(String::format('Theme name %name is over the maximum allowed length of @max characters.', array(
......@@ -143,53 +223,107 @@ public function enable(array $theme_list) {
->clear("disabled.theme.$key")
->save();
// Refresh the theme list as installation of default configuration needs
// an updated list to work.
$this->reset();
// The default config installation storage only knows about the currently
// enabled list of themes, so it has to be reset in order to pick up the
// default config of the newly installed theme. However, do not reset the
// source storage when synchronizing configuration, since that would
// needlessly trigger a reload of the whole configuration to be imported.
if (!$this->configInstaller->isSyncing()) {
$this->configInstaller->resetSourceStorage();
// Add the theme to the current list.
// @todo Remove all code that relies on $status property.
$theme_data[$key]->status = 1;
$this->addTheme($theme_data[$key]);
// Update the current theme data accordingly.
$current_theme_data = $this->state->get('system.theme.data', array());
$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])) {
// The default config installation storage only knows about the currently
// enabled list of themes, so it has to be reset in order to pick up the
// default config of the newly installed theme. However, do not reset the
// source storage when synchronizing configuration, since that would
// needlessly trigger a reload of the whole configuration to be imported.
if (!$this->configInstaller->isSyncing()) {
$this->configInstaller->resetSourceStorage();
}
// Install default configuration of the theme.
$this->configInstaller->installDefaultConfig('theme', $key);
}
// Install default configuration of the theme.
$this->configInstaller->installDefaultConfig('theme', $key);
$themes_enabled[] = $key;
// Record the fact that it was enabled.
watchdog('system', '%theme theme enabled.', array('%theme' => $key), WATCHDOG_INFO);
}
$this->clearCssCache();
$this->resetSystem();
// Invoke hook_themes_enabled() after the themes have been enabled.
$this->moduleHandler->invokeAll('themes_enabled', array($theme_list));
$this->moduleHandler->invokeAll('themes_enabled', array($themes_enabled));
return !empty($themes_enabled);
}
/**
* {@inheritdoc}
*/
public function disable(array $theme_list) {
// Don't disable the default or admin themes.
$theme_config = $this->configFactory->get('system.theme');
$default_theme = $theme_config->get('default');
$admin_theme = $theme_config->get('admin');
$theme_list = array_diff($theme_list, array($default_theme, $admin_theme));
if (empty($theme_list)) {
return;
foreach ($theme_list as $key) {
if (!isset($this->list[$key])) {
throw new \InvalidArgumentException("Unknown theme: $key.");
}
if ($key === $theme_config->get('default')) {
throw new \InvalidArgumentException("The current default theme $key cannot be disabled.");
}
if ($key === $theme_config->get('admin')) {
throw new \InvalidArgumentException("The current admin theme $key cannot be disabled.");
}
// Base themes cannot be disabled if sub themes are enabled, and if they
// are not disabled at the same time.
if (!empty($this->list[$key]->sub_themes)) {
foreach ($this->list[$key]->sub_themes as $sub_key => $sub_label) {
if (isset($this->list[$sub_key]) && !in_array($sub_key, $theme_list, TRUE)) {
throw new \InvalidArgumentException("The base theme $key cannot be disabled, because theme $sub_key depends on it.");
}
}
}
}
$this->clearCssCache();
$extension_config = $this->configFactory->get('core.extension');
$current_theme_data = $this->state->get('system.theme.data', array());
foreach ($theme_list as $key) {
// The value is not used; the weight is ignored for themes currently.
$extension_config
->clear("theme.$key")
->set("disabled.theme.$key", 0);
// Remove the theme from the current list.
unset($this->list[$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]);
// @todo Remove system_list().
$this->systemListReset();
}
$extension_config->save();
$this->state->set('system.theme.data', $current_theme_data);
$this->reset();
$this->resetSystem();
// Invoke hook_themes_disabled after the themes have been disabled.
......@@ -200,52 +334,63 @@ public function disable(array $theme_list) {
* {@inheritdoc}
*/
public function listInfo() {
if (empty($this->list)) {
if (!isset($this->list)) {
$this->list = array();
try {
$themes = $this->systemThemeList();
$themes = $this->systemThemeList();
foreach ($themes as $theme) {
$this->addTheme($theme);
}
catch (\Exception $e) {
// If the database is not available, rebuild the theme data.
$themes = $this->rebuildThemeData();
}
return $this->list;
}
/**
* {@inheritdoc}
*/
public function addTheme(Extension $theme) {
// @todo Remove this 100% unnecessary duplication of properties.
foreach ($theme->info['stylesheets'] as $media => $stylesheets) {
foreach ($stylesheets as $stylesheet => $path) {
$theme->stylesheets[$media][$stylesheet] = $path;
}
}
foreach ($theme->info['libraries'] as $library => $name) {
$theme->libraries[$library] = $name;
}
if (isset($theme->info['engine'])) {
$theme->engine = $theme->info['engine'];
}
if (isset($theme->info['base theme'])) {
$theme->base_theme = $theme->info['base theme'];
}
$this->list[$theme->getName()] = $theme;
}
foreach ($themes as $theme) {
foreach ($theme->info['stylesheets'] as $media => $stylesheets) {
foreach ($stylesheets as $stylesheet => $path) {
$theme->stylesheets[$media][$stylesheet] = $path;
}
}
foreach ($theme->info['libraries'] as $library => $name) {
$theme->libraries[$library] = $name;
}
if (isset($theme->info['engine'])) {
$theme->engine = $theme->info['engine'];
}
if (isset($theme->info['base theme'])) {
$theme->base_theme = $theme->info['base theme'];
}
// Status is normally retrieved from the database. Add zero values when
// read from the installation directory to prevent notices.
if (!isset($theme->status)) {
$theme->status = 0;
}
$this->list[$theme->getName()] = $theme;
/**
* {@inheritdoc}
*/
public function refreshInfo() {
$this->reset();
$extension_config = $this->configFactory->get('core.extension');
$enabled = $extension_config->get('theme') ?: array();
// @todo Avoid re-scanning all themes by retaining the original (unaltered)
// theme info somewhere.
$list = $this->rebuildThemeData();
foreach ($list as $name => $theme) {
if (isset($enabled[$name])) {
$this->list[$name] = $theme;
}
}
return $this->list;
$this->state->set('system.theme.data', $this->list);
}
/**
* {@inheritdoc}
*/
public function reset() {
// listInfo() calls system_info() which has a lot of side effects that have
// to be triggered like the classloading of theme classes.
$this->list = array();
$this->systemListReset();
$this->listInfo();
$this->list = array();
$this->list = NULL;
}
/**
......@@ -255,6 +400,8 @@ public function rebuildThemeData() {
$listing = $this->getExtensionDiscovery();
$themes = $listing->scan('theme');
$engines = $listing->scan('theme_engine');
$extension_config = $this->configFactory->get('core.extension');