From f26598bf830b1652129abb136b1ac2b69048e692 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Tue, 28 May 2024 09:09:43 +0100
Subject: [PATCH] Issue #3432595 by longwave, kim.pepper, alexpott: Use a
 tagged service iterator for uninstall validators instead of individual lazy
 proxies

---
 core/.phpstan-baseline.php                    |  5 +
 core/core.services.yml                        | 27 ++----
 core/lib/Drupal/Core/CoreServiceProvider.php  |  4 +
 .../ConfigImportSubscriber.php                | 28 ++----
 ...mportModuleUninstallValidatorInterface.php |  3 +-
 .../Drupal/Core/Extension/ModuleInstaller.php | 29 ++++--
 .../Extension/ModuleInstallerInterface.php    |  5 +
 .../ModuleUninstallValidatorInterface.php     |  3 +-
 .../Entity/ContentUninstallValidator.php      | 88 -----------------
 .../DatabaseDriverUninstallValidator.php      | 88 -----------------
 .../InstallProfileUninstallValidator.php      | 88 -----------------
 ...duleRequiredByThemesUninstallValidator.php | 96 -------------------
 .../RequiredModuleUninstallValidator.php      | 88 -----------------
 core/modules/field/field.services.yml         |  6 +-
 .../ProxyClass/FieldUninstallValidator.php    | 88 -----------------
 core/modules/filter/filter.services.yml       |  6 +-
 .../ProxyClass/FilterUninstallValidator.php   | 88 -----------------
 .../Core/DependencyInjection/AutowireTest.php |  1 -
 .../Core/Extension/ModuleInstallerTest.php    | 25 +++++
 19 files changed, 84 insertions(+), 682 deletions(-)
 delete mode 100644 core/lib/Drupal/Core/ProxyClass/Entity/ContentUninstallValidator.php
 delete mode 100644 core/lib/Drupal/Core/ProxyClass/Extension/DatabaseDriverUninstallValidator.php
 delete mode 100644 core/lib/Drupal/Core/ProxyClass/Extension/InstallProfileUninstallValidator.php
 delete mode 100644 core/lib/Drupal/Core/ProxyClass/Extension/ModuleRequiredByThemesUninstallValidator.php
 delete mode 100644 core/lib/Drupal/Core/ProxyClass/Extension/RequiredModuleUninstallValidator.php
 delete mode 100644 core/modules/field/src/ProxyClass/FieldUninstallValidator.php
 delete mode 100644 core/modules/filter/src/ProxyClass/FilterUninstallValidator.php

diff --git a/core/.phpstan-baseline.php b/core/.phpstan-baseline.php
index 53e300330b99..2f79a47e0218 100644
--- a/core/.phpstan-baseline.php
+++ b/core/.phpstan-baseline.php
@@ -397,6 +397,11 @@
 	'count' => 1,
 	'path' => __DIR__ . '/lib/Drupal/Core/Extension/ExtensionVersion.php',
 ];
+$ignoreErrors[] = [
+	'message' => '#^The "module_installer\\.uninstall_validators" service is deprecated in drupal:11.1.0 and is removed from drupal:12.0.0\\. Inject "\\!tagged_iterator module_install\\.uninstall_validator" instead\\. See https\\://www\\.drupal\\.org/node/3432595$#',
+	'count' => 1,
+	'path' => __DIR__ . '/lib/Drupal/Core/Extension/ModuleInstaller.php',
+];
 $ignoreErrors[] = [
 	// identifier: isset.variable
 	'message' => '#^Variable \\$callback in isset\\(\\) always exists and is not nullable\\.$#',
diff --git a/core/core.services.yml b/core/core.services.yml
index 64c3fe278596..4e3749a5e185 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -648,11 +648,13 @@ services:
   Drupal\Core\Extension\ModuleHandlerInterface: '@module_handler'
   module_installer:
     class: Drupal\Core\Extension\ModuleInstaller
-    tags:
-      - { name: service_collector, tag: 'module_install.uninstall_validator', call: addUninstallValidator }
-    arguments: ['%app.root%', '@module_handler', '@kernel', '@database', '@update.update_hook_registry', '@logger.channel.default']
+    autowire: true
     lazy: true
   Drupal\Core\Extension\ModuleInstallerInterface: '@module_installer'
+  module_installer.uninstall_validators:
+    class: \IteratorIterator
+    arguments: [!tagged_iterator module_install.uninstall_validator]
+    deprecated: The "%service_id%" service is deprecated in drupal:11.1.0 and is removed from drupal:12.0.0. Inject "!tagged_iterator module_install.uninstall_validator" instead. See https://www.drupal.org/node/3432595
   extension.list.module:
     class: Drupal\Core\Extension\ModuleExtensionList
     arguments: ['%app.root%', 'module', '@cache.default', '@info_parser', '@module_handler', '@state', '@config.factory', '@extension.list.profile', '%install_profile%', '%container.modules%']
@@ -679,34 +681,19 @@ services:
   Drupal\Core\Extension\ExtensionPathResolver: '@extension.path.resolver'
   content_uninstall_validator:
     class: Drupal\Core\Entity\ContentUninstallValidator
-    tags:
-      - { name: module_install.uninstall_validator }
     arguments: ['@entity_type.manager', '@string_translation']
-    lazy: true
   required_module_uninstall_validator:
     class: Drupal\Core\Extension\RequiredModuleUninstallValidator
-    tags:
-      - { name: module_install.uninstall_validator }
     arguments: ['@string_translation', '@extension.list.module']
-    lazy: true
   module_required_by_themes_uninstall_validator:
     class: Drupal\Core\Extension\ModuleRequiredByThemesUninstallValidator
-    tags:
-      - { name: module_install.uninstall_validator }
     arguments: ['@string_translation', '@extension.list.module', '@extension.list.theme']
-    lazy: true
   database_driver_uninstall_validator:
     class: Drupal\Core\Extension\DatabaseDriverUninstallValidator
-    tags:
-      - { name: module_install.uninstall_validator }
     arguments: ['@string_translation', '@extension.list.module', '@database']
-    lazy: true
   install_profile_uninstall_validator:
     class: Drupal\Core\Extension\InstallProfileUninstallValidator
-    tags:
-      - { name: module_install.uninstall_validator }
     arguments: ['@string_translation', '@extension.list.module', '@extension.list.theme', '%install_profile%', '%app.root%', '%site.path%']
-    lazy: true
   theme_handler:
     class: Drupal\Core\Extension\ThemeHandler
     arguments: ['%app.root%', '@config.factory', '@extension.list.theme']
@@ -1415,9 +1402,7 @@ services:
     class: Drupal\Core\EventSubscriber\RedirectLeadingSlashesSubscriber
   config_import_subscriber:
     class: Drupal\Core\EventSubscriber\ConfigImportSubscriber
-    tags:
-      - { name: service_collector, tag: 'module_install.uninstall_validator', call: addUninstallValidator }
-    arguments: ['@extension.list.theme', '@extension.list.module']
+    autowire: true
   config_snapshot_subscriber:
     class: Drupal\Core\EventSubscriber\ConfigSnapshotSubscriber
     arguments: ['@config.manager', '@config.storage', '@config.storage.snapshot']
diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php
index f8221fe69126..af5234b14c6d 100644
--- a/core/lib/Drupal/Core/CoreServiceProvider.php
+++ b/core/lib/Drupal/Core/CoreServiceProvider.php
@@ -24,6 +24,7 @@
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\DependencyInjection\ServiceModifierInterface;
 use Drupal\Core\DependencyInjection\ServiceProviderInterface;
+use Drupal\Core\Extension\ModuleUninstallValidatorInterface;
 use Drupal\Core\Plugin\PluginManagerPass;
 use Drupal\Core\Queue\QueueFactoryInterface;
 use Drupal\Core\Render\MainContent\MainContentRenderersPass;
@@ -113,6 +114,9 @@ public function register(ContainerBuilder $container) {
 
     $container->registerForAutoconfiguration(QueueFactoryInterface::class)
       ->addTag('queue_factory');
+
+    $container->registerForAutoconfiguration(ModuleUninstallValidatorInterface::class)
+      ->addTag('module_install.uninstall_validator');
   }
 
   /**
diff --git a/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php
index d2259643b44e..2167ba35f3d6 100644
--- a/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php
@@ -9,9 +9,9 @@
 use Drupal\Core\Config\ConfigNameException;
 use Drupal\Core\Extension\ConfigImportModuleUninstallValidatorInterface;
 use Drupal\Core\Extension\ModuleExtensionList;
-use Drupal\Core\Extension\ModuleUninstallValidatorInterface;
 use Drupal\Core\Extension\ThemeExtensionList;
 use Drupal\Core\Installer\InstallerKernel;
+use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;
 
 /**
  * Config import subscriber for config import events.
@@ -39,13 +39,6 @@ class ConfigImportSubscriber extends ConfigImportValidateEventSubscriberBase {
    */
   protected ThemeExtensionList $themeList;
 
-  /**
-   * The uninstall validators.
-   *
-   * @var \Drupal\Core\Extension\ModuleUninstallValidatorInterface[]
-   */
-  protected $uninstallValidators = [];
-
   /**
    * Constructs the ConfigImportSubscriber.
    *
@@ -53,22 +46,19 @@ class ConfigImportSubscriber extends ConfigImportValidateEventSubscriberBase {
    *   The theme extension list.
    * @param \Drupal\Core\Extension\ModuleExtensionList $extension_list_module
    *   The module extension list.
+   * @param \Traversable $uninstallValidators
+   *   The uninstall validator services.
    */
-  public function __construct(ThemeExtensionList $theme_extension_list, ModuleExtensionList $extension_list_module) {
+  public function __construct(
+    ThemeExtensionList $theme_extension_list,
+    ModuleExtensionList $extension_list_module,
+    #[AutowireIterator(tag: 'module_install.uninstall_validator')]
+    protected \Traversable $uninstallValidators,
+  ) {
     $this->themeList = $theme_extension_list;
     $this->moduleExtensionList = $extension_list_module;
   }
 
-  /**
-   * Adds a module uninstall validator.
-   *
-   * @param \Drupal\Core\Extension\ModuleUninstallValidatorInterface $uninstall_validator
-   *   The uninstall validator to add.
-   */
-  public function addUninstallValidator(ModuleUninstallValidatorInterface $uninstall_validator): void {
-    $this->uninstallValidators[] = $uninstall_validator;
-  }
-
   /**
    * Validates the configuration to be imported.
    *
diff --git a/core/lib/Drupal/Core/Extension/ConfigImportModuleUninstallValidatorInterface.php b/core/lib/Drupal/Core/Extension/ConfigImportModuleUninstallValidatorInterface.php
index 061b025119f2..cfb0e4a8076e 100644
--- a/core/lib/Drupal/Core/Extension/ConfigImportModuleUninstallValidatorInterface.php
+++ b/core/lib/Drupal/Core/Extension/ConfigImportModuleUninstallValidatorInterface.php
@@ -10,7 +10,8 @@
  * A module uninstall validator that needs different functionality prior to a
  * configuration import should implement this interface and be defined in
  * a Drupal @link container service @endlink that is tagged
- * module_install.uninstall_validator.
+ * module_install.uninstall_validator. If autoconfiguration is enabled, the
+ * service will be automatically tagged.
  */
 interface ConfigImportModuleUninstallValidatorInterface extends ModuleUninstallValidatorInterface {
 
diff --git a/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
index def9f0236afe..ab9378c55038 100644
--- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php
+++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
@@ -14,6 +14,8 @@
 use Drupal\Core\Update\UpdateHookRegistry;
 use Drupal\Core\Utility\Error;
 use Psr\Log\LoggerInterface;
+use Symfony\Component\DependencyInjection\Attribute\Autowire;
+use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;
 
 /**
  * Default implementation of the module installer.
@@ -63,13 +65,6 @@ class ModuleInstaller implements ModuleInstallerInterface {
    */
   protected $updateRegistry;
 
-  /**
-   * The uninstall validators.
-   *
-   * @var \Drupal\Core\Extension\ModuleUninstallValidatorInterface[]
-   */
-  protected $uninstallValidators;
-
   /**
    * Constructs a new ModuleInstaller instance.
    *
@@ -85,23 +80,39 @@ class ModuleInstaller implements ModuleInstallerInterface {
    *   The update registry service.
    * @param \Psr\Log\LoggerInterface|null $logger
    *   The logger.
+   * @param \Traversable|null $uninstallValidators
+   *   The uninstall validator services.
    *
    * @see \Drupal\Core\DrupalKernel
    * @see \Drupal\Core\CoreServiceProvider
    */
-  public function __construct($root, ModuleHandlerInterface $module_handler, DrupalKernelInterface $kernel, Connection $connection, UpdateHookRegistry $update_registry, protected LoggerInterface $logger) {
+  public function __construct(
+    #[Autowire(param: 'app.root')]
+    string $root,
+    ModuleHandlerInterface $module_handler,
+    DrupalKernelInterface $kernel,
+    Connection $connection,
+    UpdateHookRegistry $update_registry,
+    #[Autowire(service: 'logger.channel.default')]
+    protected LoggerInterface $logger,
+    #[AutowireIterator(tag: 'module_install.uninstall_validator')]
+    protected ?\Traversable $uninstallValidators = NULL,
+  ) {
     $this->root = $root;
     $this->moduleHandler = $module_handler;
     $this->kernel = $kernel;
     $this->connection = $connection;
     $this->updateRegistry = $update_registry;
+    if ($this->uninstallValidators === NULL) {
+      $this->uninstallValidators = \Drupal::service('module_installer.uninstall_validators');
+    }
   }
 
   /**
    * {@inheritdoc}
    */
   public function addUninstallValidator(ModuleUninstallValidatorInterface $uninstall_validator) {
-    $this->uninstallValidators[] = $uninstall_validator;
+    @trigger_error(__METHOD__ . ' is deprecated in drupal:11.1.0 and is removed from drupal:12.0.0. Inject the uninstall validators into the constructor instead. See https://www.drupal.org/node/3432595', E_USER_DEPRECATED);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Extension/ModuleInstallerInterface.php b/core/lib/Drupal/Core/Extension/ModuleInstallerInterface.php
index 3fb4ff61ab72..1e90fa7fadee 100644
--- a/core/lib/Drupal/Core/Extension/ModuleInstallerInterface.php
+++ b/core/lib/Drupal/Core/Extension/ModuleInstallerInterface.php
@@ -77,6 +77,11 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE);
    *
    * @param \Drupal\Core\Extension\ModuleUninstallValidatorInterface $uninstall_validator
    *   The uninstall validator to add.
+   *
+   * @deprecated in drupal:11.1.0 and is removed from drupal:11.1.0. Inject
+   *   the uninstall validators into the constructor instead.
+   *
+   * @see https://www.drupal.org/node/3432595
    */
   public function addUninstallValidator(ModuleUninstallValidatorInterface $uninstall_validator);
 
diff --git a/core/lib/Drupal/Core/Extension/ModuleUninstallValidatorInterface.php b/core/lib/Drupal/Core/Extension/ModuleUninstallValidatorInterface.php
index 01fd07ba89cd..27e792bd481f 100644
--- a/core/lib/Drupal/Core/Extension/ModuleUninstallValidatorInterface.php
+++ b/core/lib/Drupal/Core/Extension/ModuleUninstallValidatorInterface.php
@@ -7,7 +7,8 @@
  *
  * A module uninstall validator must implement this interface and be defined in
  * a Drupal @link container service @endlink that is tagged
- * module_install.uninstall_validator.
+ * module_install.uninstall_validator. If autoconfiguration is enabled, the
+ * service will be automatically tagged.
  *
  * Validators are called during module uninstall and prior to running a
  * configuration import. If different logic is required when uninstalling via
diff --git a/core/lib/Drupal/Core/ProxyClass/Entity/ContentUninstallValidator.php b/core/lib/Drupal/Core/ProxyClass/Entity/ContentUninstallValidator.php
deleted file mode 100644
index 4d646bc40a94..000000000000
--- a/core/lib/Drupal/Core/ProxyClass/Entity/ContentUninstallValidator.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-// phpcs:ignoreFile
-
-/**
- * This file was generated via php core/scripts/generate-proxy-class.php 'Drupal\Core\Entity\ContentUninstallValidator' "core/lib/Drupal/Core".
- */
-
-namespace Drupal\Core\ProxyClass\Entity {
-
-    /**
-     * Provides a proxy class for \Drupal\Core\Entity\ContentUninstallValidator.
-     *
-     * @see \Drupal\Component\ProxyBuilder
-     */
-    class ContentUninstallValidator implements \Drupal\Core\Extension\ModuleUninstallValidatorInterface
-    {
-
-        use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
-
-        /**
-         * The id of the original proxied service.
-         *
-         * @var string
-         */
-        protected $drupalProxyOriginalServiceId;
-
-        /**
-         * The real proxied service, after it was lazy loaded.
-         *
-         * @var \Drupal\Core\Entity\ContentUninstallValidator
-         */
-        protected $service;
-
-        /**
-         * The service container.
-         *
-         * @var \Symfony\Component\DependencyInjection\ContainerInterface
-         */
-        protected $container;
-
-        /**
-         * Constructs a ProxyClass Drupal proxy object.
-         *
-         * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
-         *   The container.
-         * @param string $drupal_proxy_original_service_id
-         *   The service ID of the original service.
-         */
-        public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
-        {
-            $this->container = $container;
-            $this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
-        }
-
-        /**
-         * Lazy loads the real service from the container.
-         *
-         * @return object
-         *   Returns the constructed real service.
-         */
-        protected function lazyLoadItself()
-        {
-            if (!isset($this->service)) {
-                $this->service = $this->container->get($this->drupalProxyOriginalServiceId);
-            }
-
-            return $this->service;
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function validate($module)
-        {
-            return $this->lazyLoadItself()->validate($module);
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function setStringTranslation(\Drupal\Core\StringTranslation\TranslationInterface $translation)
-        {
-            return $this->lazyLoadItself()->setStringTranslation($translation);
-        }
-
-    }
-
-}
diff --git a/core/lib/Drupal/Core/ProxyClass/Extension/DatabaseDriverUninstallValidator.php b/core/lib/Drupal/Core/ProxyClass/Extension/DatabaseDriverUninstallValidator.php
deleted file mode 100644
index 43fab980d287..000000000000
--- a/core/lib/Drupal/Core/ProxyClass/Extension/DatabaseDriverUninstallValidator.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-// phpcs:ignoreFile
-
-/**
- * This file was generated via php core/scripts/generate-proxy-class.php 'Drupal\Core\Extension\DatabaseDriverUninstallValidator' "core/lib/Drupal/Core".
- */
-
-namespace Drupal\Core\ProxyClass\Extension {
-
-    /**
-     * Provides a proxy class for \Drupal\Core\Extension\DatabaseDriverUninstallValidator.
-     *
-     * @see \Drupal\Component\ProxyBuilder
-     */
-    class DatabaseDriverUninstallValidator implements \Drupal\Core\Extension\ModuleUninstallValidatorInterface
-    {
-
-        use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
-
-        /**
-         * The id of the original proxied service.
-         *
-         * @var string
-         */
-        protected $drupalProxyOriginalServiceId;
-
-        /**
-         * The real proxied service, after it was lazy loaded.
-         *
-         * @var \Drupal\Core\Extension\DatabaseDriverUninstallValidator
-         */
-        protected $service;
-
-        /**
-         * The service container.
-         *
-         * @var \Symfony\Component\DependencyInjection\ContainerInterface
-         */
-        protected $container;
-
-        /**
-         * Constructs a ProxyClass Drupal proxy object.
-         *
-         * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
-         *   The container.
-         * @param string $drupal_proxy_original_service_id
-         *   The service ID of the original service.
-         */
-        public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
-        {
-            $this->container = $container;
-            $this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
-        }
-
-        /**
-         * Lazy loads the real service from the container.
-         *
-         * @return object
-         *   Returns the constructed real service.
-         */
-        protected function lazyLoadItself()
-        {
-            if (!isset($this->service)) {
-                $this->service = $this->container->get($this->drupalProxyOriginalServiceId);
-            }
-
-            return $this->service;
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function validate($module)
-        {
-            return $this->lazyLoadItself()->validate($module);
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function setStringTranslation(\Drupal\Core\StringTranslation\TranslationInterface $translation)
-        {
-            return $this->lazyLoadItself()->setStringTranslation($translation);
-        }
-
-    }
-
-}
diff --git a/core/lib/Drupal/Core/ProxyClass/Extension/InstallProfileUninstallValidator.php b/core/lib/Drupal/Core/ProxyClass/Extension/InstallProfileUninstallValidator.php
deleted file mode 100644
index 9c7213dea6a2..000000000000
--- a/core/lib/Drupal/Core/ProxyClass/Extension/InstallProfileUninstallValidator.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-// phpcs:ignoreFile
-
-/**
- * This file was generated via php core/scripts/generate-proxy-class.php 'Drupal\Core\Extension\InstallProfileUninstallValidator' "core/lib/Drupal/Core".
- */
-
-namespace Drupal\Core\ProxyClass\Extension {
-
-    /**
-     * Provides a proxy class for \Drupal\Core\Extension\InstallProfileUninstallValidator.
-     *
-     * @see \Drupal\Component\ProxyBuilder
-     */
-    class InstallProfileUninstallValidator implements \Drupal\Core\Extension\ModuleUninstallValidatorInterface
-    {
-
-        use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
-
-        /**
-         * The id of the original proxied service.
-         *
-         * @var string
-         */
-        protected $drupalProxyOriginalServiceId;
-
-        /**
-         * The real proxied service, after it was lazy loaded.
-         *
-         * @var \Drupal\Core\Extension\InstallProfileUninstallValidator
-         */
-        protected $service;
-
-        /**
-         * The service container.
-         *
-         * @var \Symfony\Component\DependencyInjection\ContainerInterface
-         */
-        protected $container;
-
-        /**
-         * Constructs a ProxyClass Drupal proxy object.
-         *
-         * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
-         *   The container.
-         * @param string $drupal_proxy_original_service_id
-         *   The service ID of the original service.
-         */
-        public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
-        {
-            $this->container = $container;
-            $this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
-        }
-
-        /**
-         * Lazy loads the real service from the container.
-         *
-         * @return object
-         *   Returns the constructed real service.
-         */
-        protected function lazyLoadItself()
-        {
-            if (!isset($this->service)) {
-                $this->service = $this->container->get($this->drupalProxyOriginalServiceId);
-            }
-
-            return $this->service;
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function validate($module)
-        {
-            return $this->lazyLoadItself()->validate($module);
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function setStringTranslation(\Drupal\Core\StringTranslation\TranslationInterface $translation)
-        {
-            return $this->lazyLoadItself()->setStringTranslation($translation);
-        }
-
-    }
-
-}
diff --git a/core/lib/Drupal/Core/ProxyClass/Extension/ModuleRequiredByThemesUninstallValidator.php b/core/lib/Drupal/Core/ProxyClass/Extension/ModuleRequiredByThemesUninstallValidator.php
deleted file mode 100644
index cde2c6b44879..000000000000
--- a/core/lib/Drupal/Core/ProxyClass/Extension/ModuleRequiredByThemesUninstallValidator.php
+++ /dev/null
@@ -1,96 +0,0 @@
-<?php
-// phpcs:ignoreFile
-
-/**
- * This file was generated via php core/scripts/generate-proxy-class.php 'Drupal\Core\Extension\ModuleRequiredByThemesUninstallValidator' "core/lib/Drupal/Core".
- */
-
-namespace Drupal\Core\ProxyClass\Extension {
-
-    /**
-     * Provides a proxy class for \Drupal\Core\Extension\ModuleRequiredByThemesUninstallValidator.
-     *
-     * @see \Drupal\Component\ProxyBuilder
-     */
-    class ModuleRequiredByThemesUninstallValidator implements \Drupal\Core\Extension\ConfigImportModuleUninstallValidatorInterface
-    {
-
-        use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
-
-        /**
-         * The id of the original proxied service.
-         *
-         * @var string
-         */
-        protected $drupalProxyOriginalServiceId;
-
-        /**
-         * The real proxied service, after it was lazy loaded.
-         *
-         * @var \Drupal\Core\Extension\ModuleRequiredByThemesUninstallValidator
-         */
-        protected $service;
-
-        /**
-         * The service container.
-         *
-         * @var \Symfony\Component\DependencyInjection\ContainerInterface
-         */
-        protected $container;
-
-        /**
-         * Constructs a ProxyClass Drupal proxy object.
-         *
-         * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
-         *   The container.
-         * @param string $drupal_proxy_original_service_id
-         *   The service ID of the original service.
-         */
-        public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
-        {
-            $this->container = $container;
-            $this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
-        }
-
-        /**
-         * Lazy loads the real service from the container.
-         *
-         * @return object
-         *   Returns the constructed real service.
-         */
-        protected function lazyLoadItself()
-        {
-            if (!isset($this->service)) {
-                $this->service = $this->container->get($this->drupalProxyOriginalServiceId);
-            }
-
-            return $this->service;
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function validate($module)
-        {
-            return $this->lazyLoadItself()->validate($module);
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function validateConfigImport(string $module, \Drupal\Core\Config\StorageInterface $source_storage): array
-        {
-            return $this->lazyLoadItself()->validateConfigImport($module, $source_storage);
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function setStringTranslation(\Drupal\Core\StringTranslation\TranslationInterface $translation)
-        {
-            return $this->lazyLoadItself()->setStringTranslation($translation);
-        }
-
-    }
-
-}
diff --git a/core/lib/Drupal/Core/ProxyClass/Extension/RequiredModuleUninstallValidator.php b/core/lib/Drupal/Core/ProxyClass/Extension/RequiredModuleUninstallValidator.php
deleted file mode 100644
index 58c0043ccaa7..000000000000
--- a/core/lib/Drupal/Core/ProxyClass/Extension/RequiredModuleUninstallValidator.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-// phpcs:ignoreFile
-
-/**
- * This file was generated via php core/scripts/generate-proxy-class.php 'Drupal\Core\Extension\RequiredModuleUninstallValidator' "core/lib/Drupal/Core".
- */
-
-namespace Drupal\Core\ProxyClass\Extension {
-
-    /**
-     * Provides a proxy class for \Drupal\Core\Extension\RequiredModuleUninstallValidator.
-     *
-     * @see \Drupal\Component\ProxyBuilder
-     */
-    class RequiredModuleUninstallValidator implements \Drupal\Core\Extension\ModuleUninstallValidatorInterface
-    {
-
-        use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
-
-        /**
-         * The id of the original proxied service.
-         *
-         * @var string
-         */
-        protected $drupalProxyOriginalServiceId;
-
-        /**
-         * The real proxied service, after it was lazy loaded.
-         *
-         * @var \Drupal\Core\Extension\RequiredModuleUninstallValidator
-         */
-        protected $service;
-
-        /**
-         * The service container.
-         *
-         * @var \Symfony\Component\DependencyInjection\ContainerInterface
-         */
-        protected $container;
-
-        /**
-         * Constructs a ProxyClass Drupal proxy object.
-         *
-         * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
-         *   The container.
-         * @param string $drupal_proxy_original_service_id
-         *   The service ID of the original service.
-         */
-        public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
-        {
-            $this->container = $container;
-            $this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
-        }
-
-        /**
-         * Lazy loads the real service from the container.
-         *
-         * @return object
-         *   Returns the constructed real service.
-         */
-        protected function lazyLoadItself()
-        {
-            if (!isset($this->service)) {
-                $this->service = $this->container->get($this->drupalProxyOriginalServiceId);
-            }
-
-            return $this->service;
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function validate($module)
-        {
-            return $this->lazyLoadItself()->validate($module);
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function setStringTranslation(\Drupal\Core\StringTranslation\TranslationInterface $translation)
-        {
-            return $this->lazyLoadItself()->setStringTranslation($translation);
-        }
-
-    }
-
-}
diff --git a/core/modules/field/field.services.yml b/core/modules/field/field.services.yml
index 321cf916cf07..2c8eda317df8 100644
--- a/core/modules/field/field.services.yml
+++ b/core/modules/field/field.services.yml
@@ -1,7 +1,7 @@
 services:
+  _defaults:
+    autoconfigure: true
+
   field.uninstall_validator:
     class: Drupal\field\FieldUninstallValidator
-    tags:
-      - { name: module_install.uninstall_validator }
     arguments: ['@entity_type.manager', '@string_translation', '@plugin.manager.field.field_type']
-    lazy: true
diff --git a/core/modules/field/src/ProxyClass/FieldUninstallValidator.php b/core/modules/field/src/ProxyClass/FieldUninstallValidator.php
deleted file mode 100644
index 0861eea532fa..000000000000
--- a/core/modules/field/src/ProxyClass/FieldUninstallValidator.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-// phpcs:ignoreFile
-
-/**
- * This file was generated via php core/scripts/generate-proxy-class.php 'Drupal\field\FieldUninstallValidator' "core/modules/field/src".
- */
-
-namespace Drupal\field\ProxyClass {
-
-    /**
-     * Provides a proxy class for \Drupal\field\FieldUninstallValidator.
-     *
-     * @see \Drupal\Component\ProxyBuilder
-     */
-    class FieldUninstallValidator implements \Drupal\Core\Extension\ModuleUninstallValidatorInterface
-    {
-
-        use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
-
-        /**
-         * The id of the original proxied service.
-         *
-         * @var string
-         */
-        protected $drupalProxyOriginalServiceId;
-
-        /**
-         * The real proxied service, after it was lazy loaded.
-         *
-         * @var \Drupal\field\FieldUninstallValidator
-         */
-        protected $service;
-
-        /**
-         * The service container.
-         *
-         * @var \Symfony\Component\DependencyInjection\ContainerInterface
-         */
-        protected $container;
-
-        /**
-         * Constructs a ProxyClass Drupal proxy object.
-         *
-         * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
-         *   The container.
-         * @param string $drupal_proxy_original_service_id
-         *   The service ID of the original service.
-         */
-        public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
-        {
-            $this->container = $container;
-            $this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
-        }
-
-        /**
-         * Lazy loads the real service from the container.
-         *
-         * @return object
-         *   Returns the constructed real service.
-         */
-        protected function lazyLoadItself()
-        {
-            if (!isset($this->service)) {
-                $this->service = $this->container->get($this->drupalProxyOriginalServiceId);
-            }
-
-            return $this->service;
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function validate($module)
-        {
-            return $this->lazyLoadItself()->validate($module);
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function setStringTranslation(\Drupal\Core\StringTranslation\TranslationInterface $translation)
-        {
-            return $this->lazyLoadItself()->setStringTranslation($translation);
-        }
-
-    }
-
-}
diff --git a/core/modules/filter/filter.services.yml b/core/modules/filter/filter.services.yml
index 1c1b706f0df8..4c228d471668 100644
--- a/core/modules/filter/filter.services.yml
+++ b/core/modules/filter/filter.services.yml
@@ -1,11 +1,11 @@
 services:
+  _defaults:
+    autoconfigure: true
+
   plugin.manager.filter:
     class: Drupal\filter\FilterPluginManager
     parent: default_plugin_manager
 
   filter.uninstall_validator:
     class: Drupal\filter\FilterUninstallValidator
-    tags:
-      - { name: module_install.uninstall_validator }
     arguments: ['@plugin.manager.filter', '@entity_type.manager', '@string_translation']
-    lazy: true
diff --git a/core/modules/filter/src/ProxyClass/FilterUninstallValidator.php b/core/modules/filter/src/ProxyClass/FilterUninstallValidator.php
deleted file mode 100644
index 2e7ccc184c04..000000000000
--- a/core/modules/filter/src/ProxyClass/FilterUninstallValidator.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-// phpcs:ignoreFile
-
-/**
- * This file was generated via php core/scripts/generate-proxy-class.php 'Drupal\filter\FilterUninstallValidator' "core/modules/filter/src".
- */
-
-namespace Drupal\filter\ProxyClass {
-
-    /**
-     * Provides a proxy class for \Drupal\filter\FilterUninstallValidator.
-     *
-     * @see \Drupal\Component\ProxyBuilder
-     */
-    class FilterUninstallValidator implements \Drupal\Core\Extension\ModuleUninstallValidatorInterface
-    {
-
-        use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
-
-        /**
-         * The id of the original proxied service.
-         *
-         * @var string
-         */
-        protected $drupalProxyOriginalServiceId;
-
-        /**
-         * The real proxied service, after it was lazy loaded.
-         *
-         * @var \Drupal\filter\FilterUninstallValidator
-         */
-        protected $service;
-
-        /**
-         * The service container.
-         *
-         * @var \Symfony\Component\DependencyInjection\ContainerInterface
-         */
-        protected $container;
-
-        /**
-         * Constructs a ProxyClass Drupal proxy object.
-         *
-         * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
-         *   The container.
-         * @param string $drupal_proxy_original_service_id
-         *   The service ID of the original service.
-         */
-        public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
-        {
-            $this->container = $container;
-            $this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
-        }
-
-        /**
-         * Lazy loads the real service from the container.
-         *
-         * @return object
-         *   Returns the constructed real service.
-         */
-        protected function lazyLoadItself()
-        {
-            if (!isset($this->service)) {
-                $this->service = $this->container->get($this->drupalProxyOriginalServiceId);
-            }
-
-            return $this->service;
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function validate($module)
-        {
-            return $this->lazyLoadItself()->validate($module);
-        }
-
-        /**
-         * {@inheritdoc}
-         */
-        public function setStringTranslation(\Drupal\Core\StringTranslation\TranslationInterface $translation)
-        {
-            return $this->lazyLoadItself()->setStringTranslation($translation);
-        }
-
-    }
-
-}
diff --git a/core/tests/Drupal/KernelTests/Core/DependencyInjection/AutowireTest.php b/core/tests/Drupal/KernelTests/Core/DependencyInjection/AutowireTest.php
index 0214efbe1155..37eb7c65baed 100644
--- a/core/tests/Drupal/KernelTests/Core/DependencyInjection/AutowireTest.php
+++ b/core/tests/Drupal/KernelTests/Core/DependencyInjection/AutowireTest.php
@@ -70,7 +70,6 @@ public function testCoreServiceAliases(): void {
                 'cache.context',
                 'context_provider',
                 'event_subscriber',
-                'module_install.uninstall_validator',
               ])) {
                 continue 2;
               }
diff --git a/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php b/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php
index 8dcad9b6e9a2..d232e0cd0f16 100644
--- a/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php
@@ -7,6 +7,8 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\Extension\MissingDependencyException;
 use Drupal\Core\Extension\Exception\ObsoleteExtensionException;
+use Drupal\Core\Extension\ModuleInstaller;
+use Drupal\Core\Extension\ModuleUninstallValidatorInterface;
 use Drupal\KernelTests\KernelTestBase;
 use Symfony\Component\Routing\Exception\RouteNotFoundException;
 
@@ -161,4 +163,27 @@ public function testDeprecatedInstall() {
     $this->assertTrue(\Drupal::service('module_handler')->moduleExists('deprecated_module'));
   }
 
+  /**
+   * Tests the BC layer for uninstall validators.
+   *
+   * @covers ::__construct
+   * @covers ::addUninstallValidator
+   *
+   * @group legacy
+   */
+  public function testUninstallValidatorsBC() {
+    $this->expectDeprecation('The "module_installer.uninstall_validators" service is deprecated in drupal:11.1.0 and is removed from drupal:12.0.0. Inject "!tagged_iterator module_install.uninstall_validator" instead. See https://www.drupal.org/node/3432595');
+    $module_installer = new ModuleInstaller(
+      $this->container->getParameter('app.root'),
+      $this->container->get('module_handler'),
+      $this->container->get('kernel'),
+      $this->container->get('database'),
+      $this->container->get('update.update_hook_registry'),
+      $this->container->get('logger.channel.default'),
+    );
+
+    $this->expectDeprecation('Drupal\Core\Extension\ModuleInstaller::addUninstallValidator is deprecated in drupal:11.1.0 and is removed from drupal:12.0.0. Inject the uninstall validators into the constructor instead. See https://www.drupal.org/node/3432595');
+    $module_installer->addUninstallValidator($this->createMock(ModuleUninstallValidatorInterface::class));
+  }
+
 }
-- 
GitLab