You are here

public function ConfigManager::getConfigEntitiesToChangeOnDependencyRemoval in Drupal 10

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

File

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

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
    ->findConfigEntityDependenciesAsEntities($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
        ->findConfigEntityDependenciesAsEntities($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;
}