class ThemeExtensionList
Same name in other branches
- 9 core/lib/Drupal/Core/Extension/ThemeExtensionList.php \Drupal\Core\Extension\ThemeExtensionList
- 10 core/lib/Drupal/Core/Extension/ThemeExtensionList.php \Drupal\Core\Extension\ThemeExtensionList
- 11.x core/lib/Drupal/Core/Extension/ThemeExtensionList.php \Drupal\Core\Extension\ThemeExtensionList
Provides a list of available themes.
@internal This class is not yet stable and therefore there are no guarantees that the internal implementations including constructor signature and protected properties / methods will not change over time. This will be reviewed after https://www.drupal.org/project/drupal/issues/2940481
Hierarchy
- class \Drupal\Core\Extension\ExtensionList
- class \Drupal\Core\Extension\ThemeExtensionList extends \Drupal\Core\Extension\ExtensionList
Expanded class hierarchy of ThemeExtensionList
7 files declare their use of ThemeExtensionList
- BaseThemeDefaultDeprecationTest.php in core/
tests/ Drupal/ KernelTests/ Core/ Theme/ BaseThemeDefaultDeprecationTest.php - InstallerThemeExtensionList.php in core/
lib/ Drupal/ Core/ Installer/ InstallerThemeExtensionList.php - ModuleRequiredByThemesUninstallValidatorTest.php in core/
tests/ Drupal/ Tests/ Core/ Extension/ ModuleRequiredByThemesUninstallValidatorTest.php - ThemeController.php in core/
modules/ system/ src/ Controller/ ThemeController.php - ThemeExperimentalConfirmForm.php in core/
modules/ system/ src/ Form/ ThemeExperimentalConfirmForm.php
1 string reference to 'ThemeExtensionList'
- core.services.yml in core/
core.services.yml - core/core.services.yml
1 service uses ThemeExtensionList
File
-
core/
lib/ Drupal/ Core/ Extension/ ThemeExtensionList.php, line 18
Namespace
Drupal\Core\ExtensionView source
class ThemeExtensionList extends ExtensionList {
/**
* {@inheritdoc}
*/
protected $defaults = [
'engine' => 'twig',
'regions' => [
'sidebar_first' => 'Left sidebar',
'sidebar_second' => 'Right sidebar',
'content' => 'Content',
'header' => 'Header',
'primary_menu' => 'Primary menu',
'secondary_menu' => 'Secondary menu',
'footer' => 'Footer',
'highlighted' => 'Highlighted',
'help' => 'Help',
'page_top' => 'Page top',
'page_bottom' => 'Page bottom',
'breadcrumb' => 'Breadcrumb',
],
'description' => '',
// The following array should be kept inline with
// _system_default_theme_features().
'features' => [
'favicon',
'logo',
'node_user_picture',
'comment_user_picture',
'comment_user_verification',
],
'screenshot' => 'screenshot.png',
'version' => NULL,
'php' => DRUPAL_MINIMUM_PHP,
'libraries' => [],
'libraries_extend' => [],
'libraries_override' => [],
'dependencies' => [],
];
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The theme engine list needed by this theme list.
*
* @var \Drupal\Core\Extension\ThemeEngineExtensionList
*/
protected $engineList;
/**
* The list of installed themes.
*
* @var string[]
*/
protected $installedThemes;
/**
* Constructs a new ThemeExtensionList instance.
*
* @param string $root
* The app root.
* @param string $type
* The extension type.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
* The cache.
* @param \Drupal\Core\Extension\InfoParserInterface $info_parser
* The info parser.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\Core\State\StateInterface $state
* The state service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Drupal\Core\Extension\ThemeEngineExtensionList $engine_list
* The theme engine extension listing.
* @param string $install_profile
* The install profile used by the site.
*/
public function __construct($root, $type, CacheBackendInterface $cache, InfoParserInterface $info_parser, ModuleHandlerInterface $module_handler, StateInterface $state, ConfigFactoryInterface $config_factory, ThemeEngineExtensionList $engine_list, $install_profile) {
parent::__construct($root, $type, $cache, $info_parser, $module_handler, $state, $install_profile);
$this->configFactory = $config_factory;
$this->engineList = $engine_list;
}
/**
* {@inheritdoc}
*/
protected function doList() {
// Find themes.
$themes = parent::doList();
$engines = $this->engineList
->getList();
// Always get the freshest list of themes (rather than the already cached
// list in $this->installedThemes) when building the theme listing because a
// theme could have just been installed or uninstalled.
$this->installedThemes = $this->configFactory
->get('core.extension')
->get('theme') ?: [];
$sub_themes = [];
// Read info files for each theme.
foreach ($themes as $name => $theme) {
// Defaults to 'twig' (see self::defaults above).
$engine = $theme->info['engine'];
if (isset($engines[$engine])) {
$theme->owner = $engines[$engine]->getExtensionPathname();
$theme->prefix = $engines[$engine]->getName();
}
// Add this theme as a sub-theme if it has a base theme.
if (!empty($theme->info['base theme'])) {
$sub_themes[] = $name;
}
// Add status.
$theme->status = (int) isset($this->installedThemes[$name]);
}
// Build dependencies.
$themes = $this->moduleHandler
->buildModuleDependencies($themes);
// After establishing the full list of available themes, fill in data for
// sub-themes.
$this->fillInSubThemeData($themes, $sub_themes);
foreach ($themes as $key => $theme) {
// After $theme is processed by buildModuleDependencies(), there can be a
// `$theme->requires` array containing both module and base theme
// dependencies. The module dependencies are copied to their own property
// so they are available to operations specific to module dependencies.
if (isset($theme->requires)) {
$theme->module_dependencies = array_diff_key($theme->requires, $themes);
}
else {
// Even if no requirements are specified, the theme installation process
// expects the presence of the `requires` and `module_dependencies`
// properties, so they should be initialized here as empty arrays.
$theme->requires = [];
$theme->module_dependencies = [];
}
}
return $themes;
}
/**
* Fills in data for themes that are also sub-themes.
*
* @param array $themes
* The array of partly processed theme information.
* @param array $sub_themes
* A list of themes from the $theme array that are also sub-themes.
*/
protected function fillInSubThemeData(array &$themes, array $sub_themes) {
foreach ($sub_themes as $name) {
$sub_theme = $themes[$name];
// The $base_themes property is optional; only set for sub themes.
// @see ThemeHandlerInterface::listInfo()
$sub_theme->base_themes = $this->doGetBaseThemes($themes, $name);
// empty() cannot be used here, since static::doGetBaseThemes() adds
// the key of a base theme with a value of NULL in case it is not found,
// in order to prevent needless iterations.
if (!current($sub_theme->base_themes)) {
continue;
}
// Determine the root base theme.
$root_key = key($sub_theme->base_themes);
// Build the list of sub-themes for each of the theme's base themes.
foreach (array_keys($sub_theme->base_themes) as $base_theme) {
$themes[$base_theme]->sub_themes[$name] = $sub_theme->info['name'];
}
// Add the theme engine info from the root base theme.
if (isset($themes[$root_key]->owner)) {
$sub_theme->info['engine'] = $themes[$root_key]->info['engine'];
$sub_theme->owner = $themes[$root_key]->owner;
$sub_theme->prefix = $themes[$root_key]->prefix;
}
}
}
/**
* Finds all the base themes for the specified theme.
*
* Themes can inherit templates and function implementations from earlier
* themes.
*
* @param \Drupal\Core\Extension\Extension[] $themes
* An array of available themes.
* @param string $theme
* The name of the theme whose base we are looking for.
*
* @return array
* Returns an array of all of the theme's ancestors; the first element's
* value will be NULL if an error occurred.
*/
public function getBaseThemes(array $themes, $theme) {
return $this->doGetBaseThemes($themes, $theme);
}
/**
* Finds the base themes for the specific theme.
*
* @param array $themes
* An array of available themes.
* @param string $theme
* The name of the theme whose base we are looking for.
* @param array $used_themes
* (optional) A recursion parameter preventing endless loops. Defaults to
* an empty array.
*
* @return array
* An array of base themes.
*/
protected function doGetBaseThemes(array $themes, $theme, array $used_themes = []) {
if (!isset($themes[$theme]->info['base theme'])) {
return [];
}
$base_key = $themes[$theme]->info['base theme'];
// Does the base theme exist?
if (!isset($themes[$base_key])) {
return [
$base_key => NULL,
];
}
$current_base_theme = [
$base_key => $themes[$base_key]->info['name'],
];
// Is the base theme itself a child of another theme?
if (isset($themes[$base_key]->info['base theme'])) {
// Do we already know the base themes of this theme?
if (isset($themes[$base_key]->base_themes)) {
return $themes[$base_key]->base_themes + $current_base_theme;
}
// Prevent loops.
if (!empty($used_themes[$base_key])) {
return [
$base_key => NULL,
];
}
$used_themes[$base_key] = TRUE;
return $this->doGetBaseThemes($themes, $base_key, $used_themes) + $current_base_theme;
}
// If we get here, then this is our parent theme.
return $current_base_theme;
}
/**
* {@inheritdoc}
*/
protected function createExtensionInfo(Extension $extension) {
$info = parent::createExtensionInfo($extension);
// In the past, Drupal used to default to the `stable` theme as the base
// theme. Explicitly opting out by specifying `base theme: false` was (and
// still is) possible. However, defaulting to `base theme: stable` prevents
// automatic updates to the next major version of Drupal, since each major
// version may have a different version of "the stable theme", for example:
// - for Drupal 8: `stable`
// - for Drupal 9: `stable9`
// - for Drupal 10: `stable10`
// - et cetera
// It is impossible to reliably determine which should be used by default,
// hence we now require the base theme to be explicitly specified.
if (!isset($info['base theme'])) {
@trigger_error(sprintf('There is no `base theme` property specified in the %s.info.yml file. The optionality of the `base theme` property is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. All Drupal 8 themes must add `base theme: stable` to their *.info.yml file for them to continue to work as-is in future versions of Drupal. Drupal 9 requires the `base theme` property to be specified. See https://www.drupal.org/node/3066038', $extension->getName()), E_USER_DEPRECATED);
$info['base theme'] = 'stable';
}
// Remove the default Stable base theme when 'base theme: false' is set in
// a theme .info.yml file.
if ($info['base theme'] === FALSE) {
unset($info['base theme']);
}
if (!empty($info['base theme'])) {
// Add the base theme as a proper dependency.
$info['dependencies'][] = $info['base theme'];
}
// Prefix screenshot with theme path.
if (!empty($info['screenshot'])) {
$info['screenshot'] = $extension->getPath() . '/' . $info['screenshot'];
}
return $info;
}
/**
* {@inheritdoc}
*/
protected function getInstalledExtensionNames() {
// Cache the installed themes to avoid multiple calls to the config system.
if (!isset($this->installedThemes)) {
$this->installedThemes = $this->configFactory
->get('core.extension')
->get('theme') ?: [];
}
return array_keys($this->installedThemes);
}
/**
* {@inheritdoc}
*/
public function reset() {
parent::reset();
$this->installedThemes = NULL;
return $this;
}
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overriden Title | Overrides |
---|---|---|---|---|---|
ExtensionList::$addedPathNames | protected | property | A list of extension folder names directly added in code (not discovered). | ||
ExtensionList::$cache | protected | property | The cache. | ||
ExtensionList::$extensionInfo | protected | property | Static caching for extension info. | ||
ExtensionList::$extensions | protected | property | The cached extensions. | ||
ExtensionList::$infoParser | protected | property | The info parser. | ||
ExtensionList::$installProfile | protected | property | The install profile used by the site. | ||
ExtensionList::$moduleHandler | protected | property | The module handler. | ||
ExtensionList::$pathNames | protected | property | A list of extension folder names keyed by extension name. | ||
ExtensionList::$root | protected | property | The app root. | ||
ExtensionList::$state | protected | property | The state store. | ||
ExtensionList::$type | protected | property | The type of the extension: "module", "theme" or "profile". | ||
ExtensionList::checkIncompatibility | public | function | Tests the compatibility of an extension. | ||
ExtensionList::doScanExtensions | protected | function | Scans the available extensions. | 1 | |
ExtensionList::exists | public | function | Determines if an extension exists in the filesystem. | ||
ExtensionList::get | public | function | Returns a single extension. | ||
ExtensionList::getAllAvailableInfo | public | function | Returns an array of info files information of available extensions. | ||
ExtensionList::getAllInstalledInfo | public | function | Returns an array of info files information of installed extensions. | ||
ExtensionList::getExtensionDiscovery | protected | function | Returns the extension discovery. | 3 | |
ExtensionList::getExtensionInfo | public | function | Returns information about a specified extension. | ||
ExtensionList::getInfoCacheId | protected | function | Returns the extension info cache ID. | ||
ExtensionList::getList | public | function | Returns all available extensions. | ||
ExtensionList::getListCacheId | protected | function | Returns the extension list cache ID. | ||
ExtensionList::getName | public | function | Returns the human-readable name of the extension. | ||
ExtensionList::getPath | public | function | Gets the path to an extension of a specific type (module, theme, etc.). | ||
ExtensionList::getPathname | public | function | Gets the info file path for an extension. | ||
ExtensionList::getPathnames | public | function | Returns a list of extension file paths keyed by machine name. | ||
ExtensionList::getPathnamesCacheId | protected | function | Returns the extension filenames cache ID. | ||
ExtensionList::recalculateInfo | protected | function | Generates the information from .info.yml files for extensions of this type. | ||
ExtensionList::recalculatePathnames | protected | function | Generates a sorted list of .info.yml file locations for all extensions. | ||
ExtensionList::setPathname | public | function | Sets the pathname for an extension. | ||
ThemeExtensionList::$configFactory | protected | property | The config factory. | ||
ThemeExtensionList::$defaults | protected | property | Default values to be merged into *.info.yml file arrays. | Overrides ExtensionList::$defaults | |
ThemeExtensionList::$engineList | protected | property | The theme engine list needed by this theme list. | ||
ThemeExtensionList::$installedThemes | protected | property | The list of installed themes. | ||
ThemeExtensionList::createExtensionInfo | protected | function | Creates the info value for an extension object. | Overrides ExtensionList::createExtensionInfo | |
ThemeExtensionList::doGetBaseThemes | protected | function | Finds the base themes for the specific theme. | ||
ThemeExtensionList::doList | protected | function | Builds the list of extensions. | Overrides ExtensionList::doList | |
ThemeExtensionList::fillInSubThemeData | protected | function | Fills in data for themes that are also sub-themes. | ||
ThemeExtensionList::getBaseThemes | public | function | Finds all the base themes for the specified theme. | ||
ThemeExtensionList::getInstalledExtensionNames | protected | function | Returns a list of machine names of installed extensions. | Overrides ExtensionList::getInstalledExtensionNames | |
ThemeExtensionList::reset | public | function | Resets the stored extension list. | Overrides ExtensionList::reset | |
ThemeExtensionList::__construct | public | function | Constructs a new ThemeExtensionList instance. | Overrides ExtensionList::__construct |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.