final class ExcludedModulesEventSubscriber in Drupal 10
Same name and namespace in other branches
- 8 core/lib/Drupal/Core/EventSubscriber/ExcludedModulesEventSubscriber.php \Drupal\Core\EventSubscriber\ExcludedModulesEventSubscriber
- 9 core/lib/Drupal/Core/EventSubscriber/ExcludedModulesEventSubscriber.php \Drupal\Core\EventSubscriber\ExcludedModulesEventSubscriber
The event subscriber preventing excluded modules to be exported.
Hierarchy
- class \Drupal\Core\EventSubscriber\ExcludedModulesEventSubscriber implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
Expanded class hierarchy of ExcludedModulesEventSubscriber
1 string reference to 'ExcludedModulesEventSubscriber'
- core.services.yml in core/core.services.yml 
- core/core.services.yml
1 service uses ExcludedModulesEventSubscriber
File
- core/lib/ Drupal/ Core/ EventSubscriber/ ExcludedModulesEventSubscriber.php, line 14 
Namespace
Drupal\Core\EventSubscriberView source
final class ExcludedModulesEventSubscriber implements EventSubscriberInterface {
  /**
   * The key in settings and state for listing excluded modules.
   *
   * @var string
   */
  const EXCLUDED_MODULES_KEY = "config_exclude_modules";
  /**
   * @var \Drupal\Core\Config\StorageInterface
   */
  private $activeStorage;
  /**
   * @var \Drupal\Core\Site\Settings
   */
  private $settings;
  /**
   * @var \Drupal\Core\Config\ConfigManagerInterface
   */
  private $manager;
  /**
   * EnvironmentModulesEventSubscriber constructor.
   *
   * @param \Drupal\Core\Config\StorageInterface $active_storage
   *   The active config storage.
   * @param \Drupal\Core\Site\Settings $settings
   *   The Drupal settings.
   * @param \Drupal\Core\Config\ConfigManagerInterface $manager
   *   The config manager.
   */
  public function __construct(StorageInterface $active_storage, Settings $settings, ConfigManagerInterface $manager) {
    $this->activeStorage = $active_storage;
    $this->settings = $settings;
    $this->manager = $manager;
  }
  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() : array {
    // React early on export and late on import.
    return [
      'config.transform.import' => [
        'onConfigTransformImport',
        -500,
      ],
      'config.transform.export' => [
        'onConfigTransformExport',
        500,
      ],
    ];
  }
  /**
   * Transform the storage which is used to import the configuration.
   *
   * Make sure excluded modules are not uninstalled by adding them and their
   * config to the storage when importing configuration.
   *
   * @param \Drupal\Core\Config\StorageTransformEvent $event
   *   The transformation event.
   */
  public function onConfigTransformImport(StorageTransformEvent $event) {
    $storage = $event
      ->getStorage();
    if (!$storage
      ->exists('core.extension')) {
      // If the core.extension config is not present there is nothing to do.
      // This means that probably the storage is empty or non-functional.
      return;
    }
    foreach (array_merge([
      StorageInterface::DEFAULT_COLLECTION,
    ], $this->activeStorage
      ->getAllCollectionNames()) as $collectionName) {
      $collection = $storage
        ->createCollection($collectionName);
      $activeCollection = $this->activeStorage
        ->createCollection($collectionName);
      foreach ($this
        ->getDependentConfigNames() as $configName) {
        if (!$collection
          ->exists($configName) && $activeCollection
          ->exists($configName)) {
          // Make sure the config is not removed if it exists.
          $collection
            ->write($configName, $activeCollection
            ->read($configName));
        }
      }
    }
    $extension = $storage
      ->read('core.extension');
    $existing = $this->activeStorage
      ->read('core.extension');
    $modules = $extension['module'];
    foreach ($this
      ->getExcludedModules() as $module) {
      if (array_key_exists($module, $existing['module'])) {
        // Set the modules weight from the active store.
        $modules[$module] = $existing['module'][$module];
      }
    }
    // Sort the extensions.
    $extension['module'] = module_config_sort($modules);
    // Set the modified extension.
    $storage
      ->write('core.extension', $extension);
  }
  /**
   * Transform the storage which is used to export the configuration.
   *
   * Make sure excluded modules are not exported by removing all the config
   * which depends on them from the storage that is exported.
   *
   * @param \Drupal\Core\Config\StorageTransformEvent $event
   *   The transformation event.
   */
  public function onConfigTransformExport(StorageTransformEvent $event) {
    $storage = $event
      ->getStorage();
    if (!$storage
      ->exists('core.extension')) {
      // If the core.extension config is not present there is nothing to do.
      // This means some other process has rendered it non-functional already.
      return;
    }
    foreach (array_merge([
      StorageInterface::DEFAULT_COLLECTION,
    ], $storage
      ->getAllCollectionNames()) as $collectionName) {
      $collection = $storage
        ->createCollection($collectionName);
      foreach ($this
        ->getDependentConfigNames() as $configName) {
        $collection
          ->delete($configName);
      }
    }
    $extension = $storage
      ->read('core.extension');
    // Remove all the excluded modules from the extensions list.
    $extension['module'] = array_diff_key($extension['module'], array_flip($this
      ->getExcludedModules()));
    $storage
      ->write('core.extension', $extension);
  }
  /**
   * Get the modules set as excluded in the Drupal settings.
   *
   * @return string[]
   *   An array of module names.
   */
  private function getExcludedModules() {
    return $this->settings
      ->get(self::EXCLUDED_MODULES_KEY, []);
  }
  /**
   * Get all the configuration which depends on one of the excluded modules.
   *
   * @return string[]
   *   An array of configuration names.
   */
  private function getDependentConfigNames() {
    $modules = $this
      ->getExcludedModules();
    $dependencyManager = $this->manager
      ->getConfigDependencyManager();
    $config = [];
    // Find all the configuration depending on the excluded modules.
    foreach ($modules as $module) {
      foreach ($dependencyManager
        ->getDependentEntities('module', $module) as $dependent) {
        $config[] = $dependent
          ->getConfigDependencyName();
      }
      $config = array_merge($config, $this->activeStorage
        ->listAll($module . '.'));
    }
    // Find all configuration that depends on the configuration found above.
    foreach ($this->manager
      ->findConfigEntityDependencies('config', array_unique($config)) as $dependent) {
      $config[] = $dependent
        ->getConfigDependencyName();
    }
    return array_unique($config);
  }
}