diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php index c016093..de012e9 100644 --- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php +++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php @@ -830,7 +830,6 @@ public function onFieldUpdate(FieldInterface $field) { */ public function onFieldDelete(FieldInterface $field) { // Mark all data associated with the field for deletion. - $field['deleted'] = FALSE; $table = static::_fieldTableName($field); $revision_table = static::_fieldRevisionTableName($field); $this->database->update($table) @@ -839,9 +838,10 @@ public function onFieldDelete(FieldInterface $field) { // Move the table to a unique name while the table contents are being // deleted. - $field['deleted'] = TRUE; - $new_table = static::_fieldTableName($field); - $revision_new_table = static::_fieldRevisionTableName($field); + $deleted_field = clone $field; + $deleted_field->deleted = TRUE; + $new_table = static::_fieldTableName($deleted_field); + $revision_new_table = static::_fieldRevisionTableName($deleted_field); $this->database->schema()->renameTable($table, $new_table); $this->database->schema()->renameTable($revision_table, $revision_new_table); } diff --git a/core/modules/field/lib/Drupal/field/Entity/Field.php b/core/modules/field/lib/Drupal/field/Entity/Field.php index 8308e28..ed3541b 100644 --- a/core/modules/field/lib/Drupal/field/Entity/Field.php +++ b/core/modules/field/lib/Drupal/field/Entity/Field.php @@ -397,21 +397,22 @@ public function postSave(EntityStorageControllerInterface $storage_controller, $ */ public static function preDelete(EntityStorageControllerInterface $storage_controller, array $fields) { $state = \Drupal::state(); - - // Keep the field definitions in the state storage so we can use them later - // during field_purge_batch(). $deleted_fields = $state->get('field.field.deleted') ?: array(); + foreach ($fields as $field) { if (!$field->deleted) { + // Keep the field definition in the state storage so we can use it later + // during field_purge_batch(). $config = $field->getExportProperties(); $config['deleted'] = TRUE; + $config['bundles'] = $field->getBundles(); $deleted_fields[$field->uuid] = $config; - $deleted_fields[$field->uuid]['bundles'] = $field->getBundles(); // Notify the storage. \Drupal::entityManager()->getStorageController($field->entity_type)->onFieldDelete($field); } } + $state->set('field.field.deleted', $deleted_fields); } @@ -420,26 +421,21 @@ public static function preDelete(EntityStorageControllerInterface $storage_contr */ public static function postDelete(EntityStorageControllerInterface $storage_controller, array $fields) { $instance_controller = \Drupal::entityManager()->getStorageController('field_instance'); - $state = \Drupal::state(); - $deleted_fields = $state->get('field.field.deleted') ?: array(); + + // Delete the associated instances. + $instance_ids = array(); foreach ($fields as $field) { if (!$field->deleted) { - // Delete all non-deleted instances. - $instance_ids = array(); - foreach ($deleted_fields[$field->uuid]['bundles'] as $entity_type => $bundles) { - foreach ($bundles as $bundle) { - $instance_ids[] = "$entity_type.$bundle.$field->id"; - } - } - foreach ($instance_controller->loadMultiple($instance_ids) as $instance) { - // By default, FieldInstance::delete() will automatically try to delete - // a field definition when it is deleting the last instance of the - // field. Since the whole field is being deleted here, pass FALSE as - // the $field_cleanup parameter to prevent a loop. - $instance->delete(); + // Delete all instances. + foreach ($field->getBundles() as $bundle) { + $instance_ids[] = "{$field->entity_type}.$bundle.{$field->name}"; } } } + if ($instance_ids) { + $instances = $instance_controller->loadMultiple($instance_ids); + $instance_controller->delete($instances); + } // Clear the cache. field_cache_clear(); diff --git a/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php b/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php index 9d5eb5b..66bc8f7 100644 --- a/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php +++ b/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php @@ -399,32 +399,42 @@ public static function preDelete(EntityStorageControllerInterface $storage_contr * {@inheritdoc} */ public static function postDelete(EntityStorageControllerInterface $storage_controller, array $instances) { + $field_controller = \Drupal::entityManager()->getStorageController('field_entity'); + + // Clear the cache upfront, to refresh the results of getBundles(). + field_cache_clear(); + + $fields_to_delete = array(); + $displays_to_update = array(); foreach ($instances as $instance) { if (!$instance->deleted) { - // Remove the instance from the entity form displays. - if ($form_display = entity_load('entity_form_display', $instance->entity_type . '.' . $instance->bundle . '.default')) { - $form_display->removeComponent($instance->field->id)->save(); + // The field should be deleted if it has no instances left. + // @todo This will fail if we're deleting several instances of the same field simuultaneously. + if (count($instance->field->getBundles()) == 0) { + $fields_to_delete[] = $instance->getField(); } - // Remove the instance from the entity displays. - $ids = array(); + // Collect entity displays to clean up. $view_modes = array('default' => array()) + entity_get_view_modes($instance->entity_type); foreach (array_keys($view_modes) as $view_mode) { - $ids[] = $instance->entity_type . '.' . $instance->bundle . '.' . $view_mode; - } - foreach (entity_load_multiple('entity_display', $ids) as $display) { - $display->removeComponent($instance->field->id)->save(); + $displays_to_update['entity_display'][$instance->entity_type . '.' . $instance->bundle . '.' . $view_mode][] = $instance->field->name; } + $displays_to_update['entity_form_display'][$instance->entity_type . '.' . $instance->bundle . '.default'][] = $instance->field->name; + } + } - // Delete the field if it doesn't have more instances associated to it. - if (count($instance->field->getBundles()) == 0) { - $instance->field->delete(); + // Delete fields. + $field_controller->delete($fields_to_delete); + + // Remove the components from the entity displays. + foreach ($displays_to_update as $type => $ids) { + foreach (entity_load_multiple($type, array_keys($ids)) as $id => $display) { + foreach ($ids[$id] as $field_name) { + $display->removeComponent($field_name); } + $display->save(); } } - - // Clear the cache. - field_cache_clear(); } /**