88use Drupal \Core \Config \ConfigFactoryInterface ;
99use Drupal \Core \Config \ConfigInstallerInterface ;
1010use Drupal \Core \Config \ConfigManagerInterface ;
11+ use Drupal \Core \DrupalKernelInterface ;
1112use Drupal \Core \Extension \Exception \UnknownExtensionException ;
1213use Drupal \Core \Routing \RouteBuilderInterface ;
1314use Drupal \Core \State \StateInterface ;
1415use Drupal \Core \StringTranslation \StringTranslationTrait ;
1516use Drupal \Core \Theme \Registry ;
1617use Psr \Log \LoggerInterface ;
18+ use Symfony \Component \DependencyInjection \Attribute \Autowire ;
1719
1820/**
1921 * Manages theme installation/uninstallation.
@@ -24,23 +26,26 @@ class ThemeInstaller implements ThemeInstallerInterface {
2426 use StringTranslationTrait;
2527
2628 public function __construct (
27- protected readonly ThemeHandlerInterface $ themeHandler ,
28- protected readonly ConfigFactoryInterface $ configFactory ,
29- protected readonly ConfigInstallerInterface $ configInstaller ,
30- protected readonly ModuleHandlerInterface $ moduleHandler ,
31- protected readonly ConfigManagerInterface $ configManager ,
32- protected readonly AssetCollectionOptimizerInterface $ cssCollectionOptimizer ,
33- protected readonly RouteBuilderInterface $ routeBuilder ,
34- protected readonly LoggerInterface $ logger ,
35- protected readonly StateInterface $ state ,
36- protected readonly ModuleExtensionList $ moduleExtensionList ,
37- protected readonly Registry $ themeRegistry ,
38- protected readonly ThemeExtensionList $ themeExtensionList ,
39- protected ?CachedDiscoveryInterface $ componentPluginManager = NULL ,
29+ protected ThemeHandlerInterface $ themeHandler ,
30+ protected ConfigFactoryInterface $ configFactory ,
31+ protected ConfigInstallerInterface $ configInstaller ,
32+ protected ModuleHandlerInterface $ moduleHandler ,
33+ protected ConfigManagerInterface $ configManager ,
34+ #[Autowire(service: 'asset.css.collection_optimizer ' )]
35+ protected AssetCollectionOptimizerInterface $ cssCollectionOptimizer ,
36+ protected RouteBuilderInterface $ routeBuilder ,
37+ #[Autowire(service: 'logger.channel.default ' )]
38+ protected LoggerInterface $ logger ,
39+ protected StateInterface $ state ,
40+ protected ModuleExtensionList $ moduleExtensionList ,
41+ protected Registry $ themeRegistry ,
42+ protected ThemeExtensionList $ themeExtensionList ,
43+ #[Autowire(service: 'kernel ' )]
44+ protected DrupalKernelInterface |CachedDiscoveryInterface |null $ kernel = NULL ,
4045 ) {
41- if ($ this ->componentPluginManager === NULL ) {
42- @trigger_error ('Calling ' . __METHOD__ . ' without the $componentPluginManager argument is deprecated in drupal:11.2 .0 and it will be required in drupal:12.0.0. See https://www.drupal.org/node/3525649 ' , E_USER_DEPRECATED );
43- $ this ->componentPluginManager = \Drupal::service ('plugin.manager.sdc ' );
46+ if (! $ this ->kernel instanceof DrupalKernelInterface ) {
47+ @trigger_error ('Calling ' . __METHOD__ . ' without the $kernel argument is deprecated in drupal:11.3 .0 and it will be required in drupal:12.0.0. See https://www.drupal.org/node/3551652 ' , E_USER_DEPRECATED );
48+ $ this ->kernel = \Drupal::service ('kernel ' );
4449 }
4550 }
4651
@@ -170,7 +175,11 @@ public function install(array $theme_list, $install_dependencies = TRUE) {
170175 }
171176
172177 $ this ->cssCollectionOptimizer ->deleteAll ();
173- $ this ->resetSystem ();
178+ // Add new themes to the list of installed themes.
179+ $ register_themes = array_merge (array_keys ($ installed_themes ), $ themes_installed );
180+ // Get list of extensions for the new list of themes.
181+ $ register_themes = array_intersect_key ($ theme_data , array_flip ($ register_themes ));
182+ $ this ->resetSystem ($ register_themes );
174183
175184 // Invoke hook_themes_installed() after the themes have been installed.
176185 $ this ->moduleHandler ->invokeAll ('themes_installed ' , [$ themes_installed ]);
@@ -185,6 +194,8 @@ public function uninstall(array $theme_list) {
185194 $ extension_config = $ this ->configFactory ->getEditable ('core.extension ' );
186195 $ theme_config = $ this ->configFactory ->getEditable ('system.theme ' );
187196 $ list = $ this ->themeHandler ->listInfo ();
197+ $ installed_themes = $ extension_config ->get ('theme ' ) ?: [];
198+ $ theme_data = $ this ->themeExtensionList ->reset ()->getList ();
188199 foreach ($ theme_list as $ key ) {
189200 if ($ extension_config ->get ("theme. $ key " ) === NULL ) {
190201 throw new UnknownExtensionException ("Unknown theme: $ key. " );
@@ -219,19 +230,43 @@ public function uninstall(array $theme_list) {
219230 $ extension_config ->save (TRUE );
220231
221232 // Refresh theme info.
222- $ this ->resetSystem ();
223233 $ this ->themeHandler ->reset ();
234+ // Remove themes that were uninstalled from the list.
235+ $ register_themes = array_diff (array_keys ($ installed_themes ), $ theme_list );
236+ // Get list of extensions for the new list of themes.
237+ $ register_themes = array_intersect_key ($ theme_data , array_flip ($ register_themes ));
238+ $ this ->resetSystem ($ register_themes );
224239
225240 $ this ->moduleHandler ->invokeAll ('themes_uninstalled ' , [$ theme_list ]);
226241 }
227242
228243 /**
229244 * Resets some other systems like rebuilding the route information or caches.
245+ *
246+ * @param array<string, \Drupal\Core\Extension\Extension> $register_themes
247+ * Extension data for themes that should be registered, keyed by name.
230248 */
231- protected function resetSystem () {
232- $ this ->routeBuilder ->setRebuildNeeded ();
249+ protected function resetSystem (array $ register_themes ) {
233250 $ this ->themeRegistry ->reset ();
234- $ this ->componentPluginManager ->clearCachedDefinitions ();
251+ $ this ->kernel ->updateThemes ($ register_themes );
252+ $ container = $ this ->kernel ->getContainer ();
253+ $ this ->themeHandler = $ container ->get ('theme_handler ' );
254+ $ this ->configFactory = $ container ->get ('config.factory ' );
255+ $ this ->configInstaller = $ container ->get ('config.installer ' );
256+ $ this ->moduleHandler = $ container ->get ('module_handler ' );
257+ $ this ->configManager = $ container ->get ('config.manager ' );
258+ $ this ->cssCollectionOptimizer = $ container ->get ('asset.css.collection_optimizer ' );
259+ $ this ->routeBuilder = $ container ->get ('router.builder ' );
260+ $ this ->logger = $ container ->get ('logger.channel.default ' );
261+ $ this ->state = $ container ->get ('state ' );
262+ $ this ->moduleExtensionList = $ container ->get ('extension.list.module ' );
263+ $ this ->themeRegistry = $ container ->get ('theme.registry ' );
264+ $ this ->themeExtensionList = $ container ->get ('extension.list.theme ' );
265+
266+ $ container ->get ('stream_wrapper_manager ' )->register ();
267+ // Clear all plugin caches.
268+ $ container ->get ('plugin.cache_clearer ' )->clearCachedDefinitions ();
269+ $ this ->routeBuilder ->setRebuildNeeded ();
235270 }
236271
237272}
0 commit comments