From 2358408c67ef7930370e16d5a0ed8238dfd4edb1 Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Mon, 9 Nov 2015 18:11:28 +0000
Subject: [PATCH] Issue #2581443 by alexpott, lauriii, Cottser: Make Classy
 extend from the new Stable base theme

---
 .../Theme/MissingThemeDependencyException.php | 47 +++++++++++++++++++
 .../Drupal/Core/Theme/ThemeInitialization.php | 10 ++++
 .../Theme/ThemeInitializationInterface.php    |  3 ++
 .../Tests/ConfigImportInstallProfileTest.php  |  1 +
 .../Update/UpdatePathRC1TestBaseTest.php      |  9 +++-
 core/modules/system/system.install            | 47 ++++++++++++-------
 core/themes/classy/classy.info.yml            |  1 -
 7 files changed, 98 insertions(+), 20 deletions(-)
 create mode 100644 core/lib/Drupal/Core/Theme/MissingThemeDependencyException.php

diff --git a/core/lib/Drupal/Core/Theme/MissingThemeDependencyException.php b/core/lib/Drupal/Core/Theme/MissingThemeDependencyException.php
new file mode 100644
index 000000000000..0708450f8f5a
--- /dev/null
+++ b/core/lib/Drupal/Core/Theme/MissingThemeDependencyException.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Theme\MissingThemeDependencyException.
+ */
+
+namespace Drupal\Core\Theme;
+
+/**
+ * Exception to be thrown when base theme for installed theme is not installed.
+ *
+ * @see \Drupal\Core\Theme\ThemeInitialization::getActiveThemeByName().
+ */
+class MissingThemeDependencyException extends \Exception {
+
+  /**
+   * The missing theme dependency.
+   *
+   * @var string
+   */
+  protected $theme;
+
+  /**
+   * Constructs the exception.
+   *
+   * @param string $message
+   *   The exception message.
+   * @param string $theme
+   *   The missing theme dependency.
+   */
+  public function __construct($message, $theme) {
+    parent::__construct($message);
+    $this->theme = $theme;
+  }
+
+  /**
+   * Gets the machine name of the missing theme.
+   *
+   * @return string
+   *   The machine name of the theme that is missing.
+   */
+  public function getMissingThemeName() {
+    return $this->theme;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Theme/ThemeInitialization.php b/core/lib/Drupal/Core/Theme/ThemeInitialization.php
index 95f27a9d028a..d0c91662e313 100644
--- a/core/lib/Drupal/Core/Theme/ThemeInitialization.php
+++ b/core/lib/Drupal/Core/Theme/ThemeInitialization.php
@@ -109,6 +109,16 @@ public function getActiveThemeByName($theme_name) {
     $ancestor = $theme_name;
     while ($ancestor && isset($themes[$ancestor]->base_theme)) {
       $ancestor = $themes[$ancestor]->base_theme;
+      if (!$this->themeHandler->themeExists($ancestor)) {
+        if ($ancestor == 'stable') {
+          // Themes that depend on Stable will be fixed by system_update_8014().
+          // There is no harm in not adding it as an ancestor since at worst
+          // some people might experience slight visual regressions on
+          // update.php.
+          continue;
+        }
+        throw new MissingThemeDependencyException(sprintf('Base theme %s has not been installed.', $ancestor), $ancestor);
+      }
       $base_themes[] = $themes[$ancestor];
     }
 
diff --git a/core/lib/Drupal/Core/Theme/ThemeInitializationInterface.php b/core/lib/Drupal/Core/Theme/ThemeInitializationInterface.php
index f2b1547ed164..cd5c1be7a021 100644
--- a/core/lib/Drupal/Core/Theme/ThemeInitializationInterface.php
+++ b/core/lib/Drupal/Core/Theme/ThemeInitializationInterface.php
@@ -34,6 +34,9 @@ public function initTheme($theme_name);
    *
    * @return \Drupal\Core\Theme\ActiveTheme
    *   An active theme object instance for the given theme.
+   *
+   * @throws \Drupal\Core\Theme\MissingThemeDependencyException
+   *   Thrown when base theme for installed theme is not installed.
    */
   public function getActiveThemeByName($theme_name);
 
diff --git a/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php b/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php
index 19ef2eec08a7..e15d3acbfa13 100644
--- a/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php
+++ b/core/modules/config/src/Tests/ConfigImportInstallProfileTest.php
@@ -67,6 +67,7 @@ public function testInstallProfileValidation() {
     $core['module']['testing_config_import'] = 0;
     unset($core['module']['syslog']);
     unset($core['theme']['stark']);
+    $core['theme']['stable'] = 0;
     $core['theme']['classy'] = 0;
     $sync->write('core.extension', $core);
     $sync->deleteAll('syslog.');
diff --git a/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseTest.php b/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseTest.php
index 47e70b17e791..54c2d1e93092 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseTest.php
+++ b/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseTest.php
@@ -34,6 +34,8 @@ protected function setDatabaseDumpFiles() {
    * Tests that the database was properly loaded.
    */
   public function testDatabaseLoaded() {
+    $extensions = \Drupal::service('config.storage')->read('core.extension');
+    $this->assertFalse(isset($extensions['theme']['stable']), 'Stable is not installed before updating.');
     $hook_updates = [
       'user' => '8000',
       'node' => '8003',
@@ -57,11 +59,14 @@ public function testDatabaseLoaded() {
       $this->assertEqual($existing_updates[$expected_update], 1, new FormattableMarkup("@expected_update exists in 'existing_updates' key and only appears once.", ['@expected_update' => $expected_update]));
     }
 
-    // @todo there are no updates to run.
-    // $this->runUpdates();
+    $this->runUpdates();
     $this->assertEqual(\Drupal::config('system.site')->get('name'), 'Site-Install');
     $this->drupalGet('<front>');
     $this->assertText('Site-Install');
+    $extensions = \Drupal::service('config.storage')->read('core.extension');
+    $this->assertTrue(isset($extensions['theme']['stable']), 'Stable is installed after updating.');
+    $blocks = \Drupal::entityManager()->getStorage('block')->loadByProperties(['theme' => 'stable']);
+    $this->assertTrue(empty($blocks), 'No blocks have been placed for Stable.');
   }
 
 }
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 69044a1edf97..c9e81754e166 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1464,6 +1464,7 @@ function system_update_8005() {
         break;
 
       case 'classy':
+      case 'stable':
         // Don't place any blocks or trigger custom themes installed warning.
         break;
 
@@ -1541,6 +1542,7 @@ function system_update_8006() {
 
       case 'seven':
       case 'classy':
+      case 'stable':
         // Don't place any blocks or trigger custom themes installed warning.
         break;
       default:
@@ -1805,23 +1807,6 @@ function system_update_8011() {
   _system_update_create_block($name, $theme_name, $values);
 }
 
-/**
- * Install the Stable base theme if needed.
- */
-function system_update_8012() {
-  $theme_handler = \Drupal::service('theme_handler');
-  // Ensure we have fresh info.
-  $theme_handler->rebuildThemeData();
-  foreach ($theme_handler->listInfo() as $theme) {
-    // We first check that a base theme is set because if it's set to false then
-    // it's unset in \Drupal\Core\Extension\ThemeHandler::rebuildThemeData().
-    if (isset($theme->info['base theme']) && $theme->info['base theme'] == 'stable') {
-      $theme_handler->install(['stable']);
-      return;
-    }
-  }
-}
-
 /**
  * Enable automated cron module and move the config into it.
  */
@@ -1847,3 +1832,31 @@ function system_update_8013() {
 /**
  * @} End of "addtogroup updates-8.0.0-beta".
  */
+
+/**
+ * @addtogroup updates-8.0.0-rc
+ * @{
+ */
+
+/**
+ * Install the Stable base theme if needed.
+ */
+function system_update_8014() {
+  $theme_handler = \Drupal::service('theme_handler');
+  if ($theme_handler->themeExists('stable')) {
+    return;
+  }
+  $theme_handler->refreshInfo();
+  foreach ($theme_handler->listInfo() as $theme) {
+    // We first check that a base theme is set because if it's set to false then
+    // it's unset in \Drupal\Core\Extension\ThemeHandler::rebuildThemeData().
+    if (isset($theme->info['base theme']) && $theme->info['base theme'] == 'stable') {
+      $theme_handler->install(['stable']);
+      return;
+    }
+  }
+}
+
+/**
+ * @} End of "addtogroup updates-8.0.0-rc".
+ */
diff --git a/core/themes/classy/classy.info.yml b/core/themes/classy/classy.info.yml
index 5ed9b8054bba..007c566e56b6 100644
--- a/core/themes/classy/classy.info.yml
+++ b/core/themes/classy/classy.info.yml
@@ -4,7 +4,6 @@ description: 'A base theme with sensible default CSS classes added. Learn how to
 package: Core
 version: VERSION
 core: 8.x
-base theme: false
 hidden: true
 
 libraries:
-- 
GitLab