Problem/Motivation

while uninstalling themes during a config import (drush cim) I get the error message:
"The base theme $key cannot be uninstalled, because theme $sub_key depends on it."

but in the same config import I would also uninstall the sub theme.

on config import all the uninstalled themes should be in the same uninstall call, so that the test about
"Base themes cannot be uninstalled if sub themes are installed, and if they are not uninstalled at the same time." is possible.

/core/lib/Drupal/Core/Extension/ThemeInstaller.php Line 232:

      // 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.");
          }
        }
      }

as a temporary solution I replaced

            throw new \InvalidArgumentException("The base theme $key cannot be uninstalled, because theme $sub_key depends on it.");

with a recursive call

            $this->uninstall([$sub_key]);

Steps to reproduce

  1. Install minimal and enable test themes to be installed.
  2. Export your configuration
  3. Install test_basetheme, test_subtheme and test_subsubtheme
  4. Try to import the configuration again - you won't be able to because it can't uninstall the themes

Proposed resolution

Fix \Drupal\Core\Config\ConfigImporter::createExtensionChangelist() to use the theme's sort information to ensure dependencies are processed in the correct order on install and uninstall.

Remaining tasks

User interface changes

None

API changes

The constructor of the following classes:

  • \Drupal\Core\Config\ConfigImporter
  • \Drupal\config\Form\ConfigSync
  • \Drupal\config\Form\ConfigSingleImportForm

now require an argument of extension.list.theme service implementing \Drupal\Core\Extension\ThemeExtensionList.

\Drupal\config\Form\ConfigSync and \Drupal\config\Form\ConfigSingleImportForm are forms and are consider to be internal.

Data model changes

None

Release notes snippet

N/a

Comments

ifux created an issue. See original summary.

cilefen’s picture

8.4.x is unsupported.

Version: 8.4.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Branches prior to 8.8.x are not supported, and Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

pameeela’s picture

Title: Uninstall sub themes before base theme » Unable to uninstall base theme and subtheme at the same time
Issue tags: -theme, -uninstall, -dependencies, -order +Bug Smash Initiative

I can still reproduce this. If you try to import config that uninstalls a base theme and sub theme at the same time, it throws an error.

But I'm not sure whether it's something to be fixed/supported or just need to update that comment to say they can't be uninstalled at the same time?

Oscaner’s picture

Status: Active » Needs work
StatusFileSize
new2.78 KB
mlncn’s picture

Version: 8.9.x-dev » 9.2.x-dev
Issue tags: +Configuration system, +CMI 2.0 candidate

Just ran into this exact same problem that config sync cannot uninstall base theme and theme at same time, and looked to make sure an issue was already filed. This is clearly a pretty important cleanup of the configuration management system which is usually pretty solid, or at least works if you run it twice (that doesn't fix anything here).

iyyappan.govind’s picture

Hi, Did you run drush updb or/update.php first? then try the drush cim or configuration import via UI.

codebymikey’s picture

Issue tags: +Needs tests

The patch on #5 works for me, all it needs is a test for it to get merged in.

@iyyappan.govind, I think this isn't related to the cache and something fundamental in the implementation where it uninstalls the themes in alphabetical order rather than based on their dependency tree.

deviantintegral’s picture

This also comes up for sites upgrading from Drupal 8 to Drupal 9 due to #3115223: Remove Stable as a base theme of core themes.

deviantintegral’s picture

I wrote the following update hook to handle a site using Claro in Drupal 8, which had dependencies on Stable and Classy.

/**
 * Workaround for Drupal 9 uninstalling stable and classy.
 *
 * Claro in Drupal 8 depends on stable and classy, but no longer does in Drupal
 * 9. We import configuration before running post-update hooks, which means that
 * if we export the expected config after an update, it fails on deployments
 * because we can't remove stable and classy yet.
 *
 * @see https://www.drupal.org/project/drupal/issues/3001430
 */
function HOOK_update_8004() {
  /** @var \Drupal\Core\Extension\ThemeInstallerInterface $installer */
  $installer = \Drupal::service('theme_installer');
  // Install seven so we can change the default theme. It will be uninstalled
  // when configuration is next imported.
  $installer->install(['seven']);

  $config = \Drupal::configFactory()->getEditable('system.theme');
  $config->set('admin', 'seven');
  $config->save(TRUE);

  // Claro will be installed with the next configuration import.
  $installer->uninstall(['claro', 'classy', 'stable']);
}

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.1.10 (June 4, 2021) and Drupal 9.2.10 (November 24, 2021) were the last bugfix releases of those minor version series. Drupal 9 bug reports should be targeted for the 9.3.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

alexpott’s picture

StatusFileSize
new2.79 KB

The theme list actually has weights assigned by dependency - see \Drupal\Core\Extension\ThemeExtensionList::doList() - it calls into \Drupal\Core\Extension\ModuleHandlerInterface::buildModuleDependencies() and creates a graph ... so we can do the same as modules. I'm going to add a test to prove that we install and uninstall themes with base themes via config sync correctly.

alexpott’s picture

Version: 9.3.x-dev » 9.4.x-dev
Status: Needs work » Needs review
StatusFileSize
new2 KB
new3.92 KB

Here's a test and a proper patch. #12 was the same as #5 oops...

So we now using the theme's sort property to sort them for installing and uninstalling. Plus I've got a test that proves the fix and the fact we have a problem.

The last 9.3.x bugfix release has gone out so moving to 9.4.x

The last submitted patch, 13: 3001430-13.test-only.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 13: 3001430-13.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new18.15 KB
new23.46 KB

Fixing the tests and injecting the theme extension list into the config importer.

alexpott’s picture

Issue tags: -Needs tests
alexpott’s picture

Issue summary: View changes

Updating the issue summary.

alexpott’s picture

Title: Unable to uninstall base theme and subtheme at the same time » Unable to uninstall base theme and subtheme via config sync at the same time
alexpott’s picture

lauriii’s picture

StatusFileSize
new22.61 KB

I removed the changes to \Drupal\Tests\config\Functional\ConfigImportUITest because they are no longer needed since the test is now using Olivero instead of Bartik.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative

Actually noticed this bug while prepping a site for D10

@trigger_error('Calling ' . __METHOD__ . ' without the $extension_list_theme argument is deprecated in drupal:9.4.0 and will be required in drupal:10.0.0

1. Should be updated for 10.1.x and 11 now I think.

Testing out the functionality by editing a contrib theme I'm using to base theme off stark.
Before installing I exported my config
Installed theme which installed stark
Ran config import and got the error

Applied fix
Ran config import and both uninstalled.

So this looks good just needs that 1 update.

_utsavsharma’s picture

StatusFileSize
new3.2 KB
new22.61 KB

Addressed the pointer in #23.
Please review.

markdorison’s picture

Version: 9.5.x-dev » 10.1.x-dev
Status: Needs work » Needs review
smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Issue has been addressed

catch’s picture

+++ b/core/lib/Drupal/Core/Config/ConfigImporter.php
@@ -448,9 +463,24 @@ protected function createExtensionChangelist() {
+    // Set the actual module weights.

Should this say theme weights?

Also is there no API method for that anywhere?

alexpott’s picture

StatusFileSize
new1.2 KB
new23.14 KB

Yes it should say theme weights... it's about setting them in the array we're creating to do the ordering... so it's not setting the theme weights in the system... will fix this to be clearer. It's a copy/pasta so fixing it above too.

Leaving at RTBC as this is only fixing a comment as @catch requested.

catch’s picture

Version: 10.1.x-dev » 9.5.x-dev
Status: Reviewed & tested by the community » Fixed

@alexpott found #2241855: Provide canonical extension sorting by dependencies in the extension system which covers my remaining concern here, which was apparently a remaining concern on a similar issue 9 years ago.

Committed/pushed to 10.1.x, cherry-picked to 10.0.x and 9.5.x, thanks!

  • catch committed a36db890 on 10.0.x
    Issue #3001430 by alexpott, _utsavsharma, Oscaner, lauriii, smustgrave,...

  • catch committed fab2025f on 10.1.x
    Issue #3001430 by alexpott, _utsavsharma, Oscaner, lauriii, smustgrave,...

  • catch committed 95a2a252 on 9.5.x
    Issue #3001430 by alexpott, _utsavsharma, Oscaner, lauriii, smustgrave,...
catch’s picture

alexpott’s picture

StatusFileSize
new1.7 KB

I agree that we should fix this in 9.5 and 10.0 so here's a patch to remove the deprecation message as we should only be adding them in 10.1

  • catch committed 6f8aa738 on 10.0.x
    Issue #3001430 by alexpott, _utsavsharma, lauriii, Oscaner, catch,...

  • catch committed 6433cd0a on 9.5.x
    Issue #3001430 by alexpott, _utsavsharma, lauriii, Oscaner, catch,...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Hmm fair enough, this is the tricky thing about best effort bc vs. backporting bugfixes with internal API changes. Committed/pushed to 10.0.x and 9.5.x, thanks! I don't think anyone's going to be overriding either class so hopefully this is moot.

larowlan’s picture

Version: 9.5.x-dev » 10.1.x-dev
Status: Fixed » Needs work

Just a couple of micronits

  1. +++ b/core/lib/Drupal/Core/Config/ConfigImporter.php
    @@ -166,6 +167,13 @@ class ConfigImporter {
    +  protected $themeExtensionList;
    
    +++ b/core/modules/config/src/Form/ConfigSingleImportForm.php
    @@ -104,6 +105,13 @@ class ConfigSingleImportForm extends ConfirmFormBase {
    +  protected $themeExtensionList;
    
    +++ b/core/modules/config/src/Form/ConfigSync.php
    @@ -121,6 +122,13 @@ class ConfigSync extends FormBase {
    +  protected $themeExtensionList;
    

    Let's add a property type-hint here for the D10 version.

  2. +++ b/core/lib/Drupal/Core/Config/ConfigImporter.php
    @@ -448,9 +463,24 @@ protected function createExtensionChangelist() {
    +    // Set the actual module weights.
    

    %s/module/theme

  3. +++ b/core/tests/Drupal/KernelTests/Core/Config/ConfigImporterTest.php
    @@ -687,6 +687,37 @@ public function testRequiredModuleValidation() {
    +   * Tests installing a base themes and sub themes during configuration import.
    

    %s/base themes/base theme

  4. +++ b/core/tests/Drupal/KernelTests/Core/Config/ConfigImporterTest.php
    @@ -687,6 +687,37 @@ public function testRequiredModuleValidation() {
    +    $this->assertTrue($this->container->get('theme_handler')->themeExists('test_basetheme'));
    +    $this->assertTrue($this->container->get('theme_handler')->themeExists('test_subsubtheme'));
    +    $this->assertTrue($this->container->get('theme_handler')->themeExists('test_subtheme'));
    ...
    +    $this->assertFalse($this->container->get('theme_handler')->themeExists('test_basetheme'));
    +    $this->assertFalse($this->container->get('theme_handler')->themeExists('test_subsubtheme'));
    +    $this->assertFalse($this->container->get('theme_handler')->themeExists('test_subtheme'));
    

    micronit: is it worth putting the theme_handler service into a local variable ?

    would probably need to assign it twice to allow for any container rebuild as a result of updating core.extension

larowlan’s picture

Status: Needs work » Fixed

Ah crosspost

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

quietone’s picture

Published the change record.