Commit 5448b07b authored by catch's avatar catch

Issue #3065545 by Wim Leers, lauriii, alexpott, xjm: Deprecate base theme fallback to Stable

parent 90a550d5
......@@ -22,7 +22,6 @@ class ThemeExtensionList extends ExtensionList {
*/
protected $defaults = [
'engine' => 'twig',
'base theme' => 'stable',
'regions' => [
'sidebar_first' => 'Left sidebar',
'sidebar_second' => 'Right sidebar',
......@@ -247,6 +246,23 @@ protected function doGetBaseThemes(array $themes, $theme, array $used_themes = [
*/
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) {
......
name: 'BigPipe test theme'
type: theme
base theme: stable
description: 'Theme for testing BigPipe edge cases.'
version: VERSION
core: 8.x
name: '<"Cat" & ''Mouse''>'
type: theme
base theme: stable
description: 'Theme for testing special characters in block admin.'
core: 8.x
regions:
......
name: 'Block test theme'
type: theme
base theme: stable
description: 'Theme for testing the block system'
version: VERSION
core: 8.x
......
name: 'Color test theme'
type: theme
base theme: stable
description: 'Theme for testing the color module'
version: VERSION
core: 8.x
......
name: 'Configuration Translation Test Theme'
type: theme
base theme: stable
description: 'Theme for testing the configuration translation mapper system'
version: VERSION
core: 8.x
name: Test Help Topics
type: theme
base theme: stable
description: A theme to test help topics.
version: VERSION
core: 8.x
name: 'Statistics test attached theme'
type: theme
base theme: stable
description: 'Theme for testing attached library'
version: VERSION
core: 8.x
......@@ -2,7 +2,19 @@
namespace Drupal\Tests\system\Functional\Update;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderInterface;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Extension\InfoParser;
use Drupal\Core\Extension\InfoParserInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Extension\ThemeEngineExtensionList;
use Drupal\Core\Extension\ThemeExtensionList;
use Drupal\Core\State\StateInterface;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
use org\bovigo\vfs\vfsStream;
/**
* Tests the upgrade path for introducing the Stable base theme.
......@@ -12,7 +24,7 @@
* @group system
* @group legacy
*/
class StableBaseThemeUpdateTest extends UpdatePathTestBase {
class StableBaseThemeUpdateTest extends UpdatePathTestBase implements ServiceProviderInterface {
/**
* The theme handler.
......@@ -31,6 +43,22 @@ protected function setDatabaseDumpFiles() {
];
}
/**
* {@inheritdoc}
*/
public function register(ContainerBuilder $container) {
$container->getDefinition('extension.list.theme')
->setClass(VfsThemeExtensionList::class);
}
/**
* {@inheritdoc}
*/
protected function prepareEnvironment() {
parent::prepareEnvironment();
$GLOBALS['conf']['container_service_providers']['test'] = $this;
}
/**
* {@inheritdoc}
*/
......@@ -38,10 +66,28 @@ protected function setUp() {
parent::setUp();
$this->themeHandler = $this->container->get('theme_handler');
$this->themeHandler->refreshInfo();
$vfs_root = vfsStream::setup('root');
$vfs_root->addChild(vfsStream::newDirectory($this->siteDirectory));
$site_dir = $vfs_root->getChild($this->siteDirectory);
vfsStream::create([
'themes' => [
'test_stable' => [
'test_stable.info.yml' => file_get_contents(DRUPAL_ROOT . '/core/tests/fixtures/test_stable/test_stable.info.yml'),
'test_stable.theme' => file_get_contents(DRUPAL_ROOT . '/core/tests/fixtures/test_stable/test_stable.theme'),
],
'stable' => [
'stable.info.yml' => file_get_contents(DRUPAL_ROOT . '/core/themes/stable/stable.info.yml'),
'stable.theme' => file_get_contents(DRUPAL_ROOT . '/core/themes/stable/stable.theme'),
],
],
], $site_dir);
}
/**
* Tests that the Stable base theme is installed if necessary.
*
* @expectedDeprecation There is no `base theme` property specified in the test_stable.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
*/
public function testUpdateHookN() {
$this->assertTrue($this->themeHandler->themeExists('test_stable'));
......@@ -55,3 +101,41 @@ public function testUpdateHookN() {
}
}
class VfsThemeExtensionList extends ThemeExtensionList {
/**
* The extension discovery for this extension list.
*
* @var \Drupal\Core\Extension\ExtensionDiscovery
*/
protected $extensionDiscovery;
/**
* {@inheritdoc}
*/
public function __construct(string $root, string $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, $config_factory, $engine_list, $install_profile);
$this->extensionDiscovery = new ExtensionDiscovery('vfs://root');
$this->infoParser = new VfsInfoParser();
}
/**
* {@inheritdoc}
*/
public function getExtensionDiscovery() {
return $this->extensionDiscovery;
}
}
class VfsInfoParser extends InfoParser {
/**
* {@inheritdoc}
*/
public function parse($filename) {
return parent::parse("vfs://root/$filename");
}
}
name: 'Theme test with semver core version'
type: theme
base theme: stable
description: 'Test theme which has semver core version.'
version: VERSION
core_version_requirement: ^8 || ^9
name: 'Theme test with invalid core version'
type: theme
base theme: stable
description: 'Test theme which has an invalid core version.'
version: VERSION
core: 7.x
name: 'Theme test with invalid semver core version'
type: theme
base theme: stable
description: 'Test theme which has an invalid semver core version.'
version: VERSION
core_version_requirement: ^7
name: 'Theme test with missing content region'
type: theme
base theme: stable
description: 'Test theme which has a non-existent content region.'
version: VERSION
core: 8.x
......
name: Test features
type: theme
base theme: stable
core: 8.x
description: 'Test theme to test theme settings with limited features.'
features:
......
name: 'Twig registry loader test'
type: theme
base theme: stable
description: 'Support module for Twig registry loader testing.'
version: VERSION
core: 8.x
name: 'Update test base theme'
type: theme
base theme: stable
description: 'Test theme which acts as a base theme for other test subthemes.'
version: VERSION
core: 8.x
name: 'User Test theme'
type: theme
base theme: stable
description: 'Theme for testing the available fields in user twig template'
version: VERSION
core: 8.x
name: Views test checkboxes theme
type: theme
base theme: stable
description: Theme for testing Views rendering of checkboxes.
version: VERSION
core: 8.x
name: Views test theme
type: theme
base theme: stable
description: Theme for testing Views functionality.
version: VERSION
core: 8.x
<?php
namespace Drupal\KernelTests\Core\Theme;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Extension\InfoParser;
use Drupal\Core\Extension\InfoParserInterface;
use Drupal\Core\Extension\ThemeExtensionList;
use Drupal\Core\Test\TestDatabase;
use Drupal\KernelTests\KernelTestBase;
use org\bovigo\vfs\vfsStream;
/**
* Tests the behavior of the Stable theme.
*
* @group Theme
*/
class BaseThemeDefaultDeprecationTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system'];
/**
* The theme installer.
*
* @var \Drupal\Core\Extension\ThemeInstallerInterface
*/
protected $themeInstaller;
/**
* The theme manager.
*
* @var \Drupal\Core\Theme\ThemeManagerInterface
*/
protected $themeManager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->themeInstaller = $this->container->get('theme_installer');
$this->themeManager = $this->container->get('theme.manager');
}
/**
* {@inheritdoc}
*/
public function register(ContainerBuilder $container) {
parent::register($container);
$container->getDefinition('extension.list.theme')
->setClass(VfsThemeExtensionList::class);
}
/**
* {@inheritdoc}
*/
protected function setUpFilesystem() {
parent::setUpFilesystem();
$test_db = new TestDatabase($this->databasePrefix);
$test_site_path = $test_db->getTestSitePath();
$test_site_dir = $this->vfsRoot->getChild($test_site_path);
vfsStream::create([
'themes' => [
'test_stable' => [
'test_stable.info.yml' => file_get_contents(DRUPAL_ROOT . '/core/tests/fixtures/test_stable/test_stable.info.yml'),
'test_stable.theme' => file_get_contents(DRUPAL_ROOT . '/core/tests/fixtures/test_stable/test_stable.theme'),
],
'stable' => [
'stable.info.yml' => file_get_contents(DRUPAL_ROOT . '/core/themes/stable/stable.info.yml'),
'stable.theme' => file_get_contents(DRUPAL_ROOT . '/core/themes/stable/stable.theme'),
],
],
], $test_site_dir);
// The origin site search directory used by the extension discovery service
// relies on the \Drupal::service('site.path') service to determine which
// directories to scan. It then prepends the root to each of those
// directories. But ::bootKernel() sets the origin site to
// $this->siteDirectory, which was in turns updated by ::setUpFileSystem()
// to include the virtual file system root. We must undo this if we want to
// use extension discovery on a virtual system.
// @see \Drupal\Core\Extension\ExtensionDiscovery::ORIGIN_SITE
$this->siteDirectory = $test_site_path;
}
/**
* Ensures Stable is used by default when no base theme has been defined.
*
* @group legacy
* @expectedDeprecation There is no `base theme` property specified in the test_stable.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
*/
public function testStableIsDefault() {
$this->container->get('extension.list.theme')
->setExtensionDiscovery(new ExtensionDiscovery('vfs://root'))
->setInfoParser(new VfsInfoParser());
$this->themeInstaller->install(['test_stable']);
$this->config('system.theme')->set('default', 'test_stable')->save();
$theme = $this->themeManager->getActiveTheme();
$base_themes = $theme->getBaseThemeExtensions();
$base_theme = reset($base_themes);
$this->assertTrue($base_theme->getName() == 'stable', "Stable theme is the base theme if a theme hasn't decided to opt out.");
}
}
/**
* Test theme extension list class.
*/
class VfsThemeExtensionList extends ThemeExtensionList {
/**
* The extension discovery for this extension list.
*
* @var \Drupal\Core\Extension\ExtensionDiscovery
*/
protected $extensionDiscovery;
/**
* Sets the extension discovery.
*
* @param \Drupal\Core\Extension\ExtensionDiscovery $discovery
* The extension discovery.
*
* @return self
*/
public function setExtensionDiscovery(ExtensionDiscovery $discovery) {
$this->extensionDiscovery = $discovery;
return $this;
}
/**
* Sets the info parser.
*
* @param \Drupal\Core\Extension\InfoParserInterface $info_parser
* The info parser.
*
* @return self
*/
public function setInfoParser(InfoParserInterface $info_parser) {
$this->infoParser = $info_parser;
return $this;
}
/**
* {@inheritdoc}
*/
public function getExtensionDiscovery() {
return $this->extensionDiscovery;
}
}
class VfsInfoParser extends InfoParser {
/**
* {@inheritdoc}
*/
public function parse($filename) {
return parent::parse("vfs://root/$filename");
}
}
......@@ -5,16 +5,14 @@
use Drupal\KernelTests\KernelTestBase;
/**
* Tests the behavior of the Stable theme.
* Tests the behavior of the `base theme` key.
*
* @group Theme
*/
class StableThemeTest extends KernelTestBase {
class BaseThemeRequiredTest extends KernelTestBase {
/**
* Modules to install.
*
* @var array
* {@inheritdoc}
*/
public static $modules = ['system'];
......@@ -42,18 +40,6 @@ protected function setUp() {
$this->themeManager = $this->container->get('theme.manager');
}
/**
* Ensures Stable is used by default when no base theme has been defined.
*/
public function testStableIsDefault() {
$this->themeInstaller->install(['test_stable']);
$this->config('system.theme')->set('default', 'test_stable')->save();
$theme = $this->themeManager->getActiveTheme();
$base_themes = $theme->getBaseThemeExtensions();
$base_theme = reset($base_themes);
$this->assertTrue($base_theme->getName() == 'stable', "Stable theme is the base theme if a theme hasn't decided to opt out.");
}
/**
* Tests opting out of Stable by setting the base theme to false.
*/
......
......@@ -116,7 +116,7 @@ public function testGetRegistryForModule() {
$test_stable = new ActiveTheme([
'name' => 'test_stable',
'path' => 'core/modules/system/tests/themes/test_stable/test_stable.info.yml',
'path' => 'core/tests/fixtures/test_stable/test_stable.info.yml',
'engine' => 'twig',
'owner' => 'twig',
'stylesheets_remove' => [],
......@@ -133,7 +133,7 @@ public function testGetRegistryForModule() {
// Include the module and theme files so that hook_theme can be called.
include_once $this->root . '/core/modules/system/tests/modules/theme_test/theme_test.module';
include_once $this->root . '/core/modules/system/tests/themes/test_stable/test_stable.theme';
include_once $this->root . '/core/tests/fixtures/test_stable/test_stable.theme';
$this->moduleHandler->expects($this->exactly(2))
->method('getImplementations')
->with('theme')
......
name: Classy
type: theme
base theme: stable
description: 'A base theme with sensible default CSS classes added. Learn how to use Classy as a base theme in the <a href="https://www.drupal.org/docs/8/theming">Drupal 8 Theming Guide</a>.'
package: Core
version: VERSION
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment