Problem/Motivation

We want to load as few as code as possible on requests, unless needed.

Currently the ThemeHandler has quite a lot of dependencies:

public function __construct($root, ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, StateInterface $state, InfoParserInterface $info_parser,LoggerInterface $logger, AssetCollectionOptimizerInterface $css_collection_optimizer = NULL, ConfigInstallerInterface $config_installer = NULL, ConfigManagerInterface $config_manager = NULL, RouteBuilderInterface $route_builder = NULL, ExtensionDiscovery $extension_discovery = NULL) {

Another problem is that the module_installer exists, but the theme_handler is still responsible for installing

Proposed resolution

Move the installation code of themes into its separate entity, called ThemeInstaller.
That itself improves the performance a bit.

As BC layer we can keep ThemeHandler::install() but just call out to the other code.

Remaining tasks

User interface changes

API changes

  • New service called theme_installer
  • theme_handler->install() => theme_install->install()
  • theme_handler->uninstall() => theme_install->uninstall()

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Task, because it improves performance a bit.
Issue priority Normal, as the impact is not that high
Disruption The amount of people installing / uninstalling a theme in core is not high, but we have the advantage of having to initiate less themes.
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dawehner’s picture

FileSize
24.68 KB

Initial quick try.

dawehner’s picture

Status: Active » Needs review

.

Status: Needs review » Needs work

The last submitted patch, 1: 2465887-1.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
24.68 KB
600 bytes

Doh.

Status: Needs review » Needs work

The last submitted patch, 4: 2465887-4.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
36.41 KB
11.19 KB

Some fixes.

Status: Needs review » Needs work

The last submitted patch, 6: 2465887-6.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
1.31 KB
36.33 KB

Let's fix the failure.

dawehner queued 8: 2465887-8.patch for re-testing.

jibran’s picture

+++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php
@@ -190,180 +172,14 @@ public function setDefault($name) {
+    \Drupal::service('theme_installer')->install($theme_list, $install_dependencies);
...
+    \Drupal::service('theme_installer')->uninstall($theme_list);

Can we use setter injection to avoid circular dependency and remove \Drupal use? Just like we did in #2448847: [regression] Themes unable to implement hook_theme_registry_alter().

amateescu’s picture

Issue tags: +D8 Accelerate Dev Days
FileSize
38.05 KB
2.15 KB

The patch looks great to me, it should improve the performance a bit because the object that we're using more often, the theme handler, is quite a bit lighter in dependencies.

Also rerolled the patch, added a docblock to the new interface and removed the methods from ThemeHandlerInterface (that's why also ThemeHandler implements ThemeInstallerInterface now, right?)

Just a small question before RTBC-ing this:

+++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php
@@ -190,180 +172,14 @@ public function setDefault($name) {
+    \Drupal::service('theme_installer')->install($theme_list, $install_dependencies);
...
+    \Drupal::service('theme_installer')->uninstall($theme_list);

Do you think we should put a comment above this line to say that not doing any kind of dependency injection here is because it would cause a circular dependency and it would also remove all the benefits of this patch.

dawehner’s picture

Also rerolled the patch, added a docblock to the new interface and removed the methods from ThemeHandlerInterface (that's why also ThemeHandler implements ThemeInstallerInterface now, right?)

This itself is a great idea. Thank you!

Do you think we should put a comment above this line to say that not doing any kind of dependency injection here is because it would cause a circular dependency and it would also remove all the benefits of this patch.

Maybe we could ask whether we could remove the BC layer entirely.

dawehner’s picture

Issue summary: View changes

Adding some points after discussing the issue with @xjm in montpellier.

dawehner’s picture

FileSize
38.26 KB
965 bytes

Do you think we should put a comment above this line to say that not doing any kind of dependency injection here is because it would cause a circular dependency and it would also remove all the benefits of this patch.

Well, its not only circular dependency, but its just an old BC layer we are dealing with. Adapted the comment for that.

amateescu’s picture

Status: Needs review » Reviewed & tested by the community

Thanks for the comment, it should be helpful if anyone stumbles upon this code. Looks great now :)

jibran’s picture

Should anyone care to comment on #10?

dawehner’s picture

Should anyone care to comment on #10?

I thoguht it got answered with the fact that we have a BC layer here.

dawehner’s picture

Should anyone care to comment on #10?

I thoguht it got answered with the fact that we have a BC layer here.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

This makes sense - it brings us inline with ModuleHandler and we're not breaking BC. It would be nice to know the impact of doing this. But I do appreciate that it part of disentangling the dependency knots in the container.

+++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php
@@ -190,180 +172,18 @@ public function setDefault($name) {
    * {@inheritdoc}
    */
   public function install(array $theme_list, $install_dependencies = TRUE) {
...
   /**
    * {@inheritdoc}
    */
   public function uninstall(array $theme_list) {

+++ b/core/lib/Drupal/Core/Extension/ThemeHandlerInterface.php
@@ -8,45 +8,11 @@
   /**
-   * Installs a given list of themes.
-   *
-   * @param array $theme_list
-   *   An array of theme names.
-   * @param bool $install_dependencies
-   *   (optional) If TRUE, dependencies will automatically be installed in the
-   *   correct order. This incurs a significant performance cost, so use FALSE
-   *   if you know $theme_list is already complete and in the correct order.
-   *
-   * @return bool
-   *   Whether any of the given themes have been installed.
-   *
-   * @throws \Drupal\Core\Extension\ExtensionNameLengthException
-   *   Thrown when the theme name is to long
-   */
-  public function install(array $theme_list, $install_dependencies = TRUE);
-
-  /**
-   * Uninstalls a given list of themes.
-   *
-   * Uninstalling a theme removes all related configuration (like blocks) and
-   * invokes the 'themes_uninstalled' hook.
-   *
-   * @param array $theme_list
-   *   The themes to uninstall.
-   *
-   * @throws \InvalidArgumentException
-   *   Thrown when you uninstall an not installed theme.
-   *
-   * @see hook_themes_uninstalled()
-   */
-  public function uninstall(array $theme_list);

I don't think we should remove them from the interface I think we should add an @deprecated D9 statement and an @see to the new service.

alexpott’s picture

  1. Theres a tonne of use statements at the top of ThemeHandler that can be removed.
  2. +++ b/core/lib/Drupal/Core/Extension/ThemeInstaller.php
    @@ -0,0 +1,306 @@
    +
    +class ThemeInstaller implements ThemeInstallerInterface {
    

    No class doc.

dawehner’s picture

Status: Needs work » Needs review
FileSize
38.55 KB
4.17 KB

Fair point, did those.

msonnabaum’s picture

Status: Needs review » Reviewed & tested by the community

Still see parts of ThemeHandler that look rough, but nothing in scope for this issue. This patch is a solid code improvement. Looks great!

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 21: 2465887-21.patch, failed testing.

tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
38.45 KB

No changes, just git apply -3

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

Meant to put it back

dawehner’s picture

Thank you @msonnabaum I kinda might try to ping you more in the future!

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Not instantiating ConfigInstaller at general runtime just seems sensible and a performance improvement. Committed 6e8eb8e and pushed to 8.0.x. Thanks!

  • alexpott committed 6e8eb8e on 8.0.x
    Issue #2465887 by dawehner, amateescu, tim.plunkett: Extract the install...

Status: Fixed » Closed (fixed)

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

cilefen’s picture

andypost’s picture

andypost’s picture

+++ b/core/lib/Drupal/Core/Extension/ThemeInstaller.php
@@ -0,0 +1,312 @@
+    // @todo It feels wrong to have the requirement to clear the local tasks
+    //   cache here.
+    Cache::invalidateTags(array('local_task'));

Filed follow-up for todo #3350933: Fix @todo in \Drupal\Core\Extension\ThemeInstaller::resetSystem()