// dependencies on the config entity classes. Assume data with UUID is a
// config entity. Only configuration entities can be depended on so we can
// ignore everything else.
- $data = array_map(function($config) {
+ $data = array_map(function ($config) {
$data = $config->get();
if (isset($data['uuid'])) {
return $data;
* {@inheritdoc}
*/
public function getConfigEntitiesToChangeOnDependencyRemoval($type, array $names, $dry_run = TRUE) {
- // Determine the current list of dependent configuration entities and set up
- // initial values.
$dependency_manager = $this->getConfigDependencyManager();
- $dependents = $this->findConfigEntityDependentsAsEntities($type, $names, $dependency_manager);
- $original_dependencies = $dependents;
- $delete_uuids = [];
+ // 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' => [],
];
- // Create a map of UUIDs to $original_dependencies key so that we can remove
- // fixed dependencies.
- $uuid_map = [];
- foreach ($original_dependencies as $key => $entity) {
- $uuid_map[$entity->uuid()] = $key;
- }
-
- // Try to fix any dependencies 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
- // dependencies.
- while ($dependent = array_pop($dependents)) {
+ // 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, $original_dependencies, $type, $names)) {
+ 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 dependents. This will
- // remove entities that are no longer dependent after the recalculation.
- $dependents = $this->findConfigEntityDependentsAsEntities($type, $names, $dependency_manager);
- // Remove any entities that we've already marked for deletion.
- $dependents = array_filter($dependents, function ($dependent) use ($delete_uuids) {
- return !in_array($dependent->uuid(), $delete_uuids);
+ // 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 dependency has actually been fixed. It is possible
- // that the dependent has multiple dependencies that cause it to be in
- // the dependency chain.
+ // 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 as $key => $entity) {
+ foreach ($dependents_to_process as $key => $entity) {
if ($entity->uuid() == $dependent->uuid()) {
$fixed = FALSE;
- unset($dependents[$key]);
+ unset($dependents_to_process[$key]);
break;
}
}
if ($fixed) {
- // Remove the fixed dependency from the list of original dependencies.
- unset($original_dependencies[$uuid_map[$dependent->uuid()]]);
+ $affected_uuids[] = $dependent->uuid();
$return['update'][] = $dependent;
}
}
// If the entity cannot be fixed then it has to be deleted.
if (!$fixed) {
- $delete_uuids[] = $dependent->uuid();
+ $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 lists of UUIDs to filter the original list to work out which
- // configuration entities are unchanged.
- $return['unchanged'] = array_filter($original_dependencies, function ($dependent) use ($delete_uuids) {
- return !(in_array($dependent->uuid(), $delete_uuids));
+ // 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;
// Key the entity arrays by config dependency name to make searching easy.
foreach (['config', 'content'] as $dependency_type) {
$affected_dependencies[$dependency_type] = array_combine(
- array_map(function ($entity) { return $entity->getConfigDependencyName(); }, $affected_dependencies[$dependency_type]),
+ array_map(function ($entity) {
+ return $entity->getConfigDependencyName();
+ }, $affected_dependencies[$dependency_type]),
$affected_dependencies[$dependency_type]
);
}