You are here

public function ConfigManager::getConfigEntitiesToChangeOnDependencyRemoval in Drupal 8

Same name and namespace in other branches
  1. 9 core/lib/Drupal/Core/Config/ConfigManager.php \Drupal\Core\Config\ConfigManager::getConfigEntitiesToChangeOnDependencyRemoval()
  2. 10 core/lib/Drupal/Core/Config/ConfigManager.php \Drupal\Core\Config\ConfigManager::getConfigEntitiesToChangeOnDependencyRemoval()

Lists which config entities to update and delete on removal of a dependency.

Parameters

string $type: The type of dependency being checked. Either 'module', 'theme', 'config' or 'content'.

array $names: The specific names to check. If $type equals 'module' or 'theme' then it should be a list of module names or theme names. In the case of 'config' or 'content' it should be a list of configuration dependency names.

bool $dry_run: If set to FALSE the entities returned in the list of updates will be modified. In order to make the changes the caller needs to save them. If set to TRUE the entities returned will not be modified.

Return value

array An array with the keys: 'update', 'delete' and 'unchanged'. The value of each is a list of configuration entities that need to have that action applied when the supplied dependencies are removed. Updates need to be processed before deletes. The order of the deletes is significant and must be processed in the returned order.

Overrides ConfigManagerInterface::getConfigEntitiesToChangeOnDependencyRemoval

1 call to ConfigManager::getConfigEntitiesToChangeOnDependencyRemoval()
ConfigManager::uninstall in core/lib/Drupal/Core/Config/ConfigManager.php
Uninstalls the configuration of a given extension.

File

core/lib/Drupal/Core/Config/ConfigManager.php, line 318

Class

ConfigManager
The ConfigManager provides helper functions for the configuration system.

Namespace

Drupal\Core\Config

Code

public function getConfigEntitiesToChangeOnDependencyRemoval($type, array $names, $dry_run = TRUE) {
  $dependency_manager = $this
    ->getConfigDependencyManager();

  // Store the list of dependents in three separate variables. This allows us
  // to determine how the dependency graph changes as entities are fixed by
  // calling the onDependencyRemoval() method.
  // The list of original dependents on $names. This list never changes.
  $original_dependents = $this
    ->findConfigEntityDependentsAsEntities($type, $names, $dependency_manager);

  // The current list of dependents on $names. This list is recalculated when
  // calling an entity's onDependencyRemoval() method results in the entity
  // changing. This list is passed to each entity's onDependencyRemoval()
  // method as the list of affected entities.
  $current_dependents = $original_dependents;

  // The list of dependents to process. This list changes as entities are
  // processed and are either fixed or deleted.
  $dependents_to_process = $original_dependents;

  // Initialize other variables.
  $affected_uuids = [];
  $return = [
    'update' => [],
    'delete' => [],
    'unchanged' => [],
  ];

  // Try to fix the dependents and find out what will happen to the dependency
  // graph. Entities are processed in the order of most dependent first. For
  // example, this ensures that Menu UI third party dependencies on node types
  // are fixed before processing the node type's other dependents.
  while ($dependent = array_pop($dependents_to_process)) {

    /** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $dependent */
    if ($dry_run) {

      // Clone the entity so any changes do not change any static caches.
      $dependent = clone $dependent;
    }
    $fixed = FALSE;
    if ($this
      ->callOnDependencyRemoval($dependent, $current_dependents, $type, $names)) {

      // Recalculate dependencies and update the dependency graph data.
      $dependent
        ->calculateDependencies();
      $dependency_manager
        ->updateData($dependent
        ->getConfigDependencyName(), $dependent
        ->getDependencies());

      // Based on the updated data rebuild the list of current dependents.
      // This will remove entities that are no longer dependent after the
      // recalculation.
      $current_dependents = $this
        ->findConfigEntityDependentsAsEntities($type, $names, $dependency_manager);

      // Rebuild the list of entities that we need to process using the new
      // list of current dependents and removing any entities that we've
      // already processed.
      $dependents_to_process = array_filter($current_dependents, function ($current_dependent) use ($affected_uuids) {
        return !in_array($current_dependent
          ->uuid(), $affected_uuids);
      });

      // Ensure that the dependent has actually been fixed. It is possible
      // that other dependencies cause it to still be in the list.
      $fixed = TRUE;
      foreach ($dependents_to_process as $key => $entity) {
        if ($entity
          ->uuid() == $dependent
          ->uuid()) {
          $fixed = FALSE;
          unset($dependents_to_process[$key]);
          break;
        }
      }
      if ($fixed) {
        $affected_uuids[] = $dependent
          ->uuid();
        $return['update'][] = $dependent;
      }
    }

    // If the entity cannot be fixed then it has to be deleted.
    if (!$fixed) {
      $affected_uuids[] = $dependent
        ->uuid();

      // Deletes should occur in the order of the least dependent first. For
      // example, this ensures that fields are removed before field storages.
      array_unshift($return['delete'], $dependent);
    }
  }

  // Use the list of affected UUIDs to filter the original list to work out
  // which configuration entities are unchanged.
  $return['unchanged'] = array_filter($original_dependents, function ($dependent) use ($affected_uuids) {
    return !in_array($dependent
      ->uuid(), $affected_uuids);
  });
  return $return;
}