Chris@0: getUnprocessedConfiguration('delete')); Chris@0: // Get the first field storage to process. Chris@0: $field_storage = reset($field_storages); Chris@0: if (!isset($context['sandbox']['field']['current_storage_id']) || $context['sandbox']['field']['current_storage_id'] != $field_storage->id()) { Chris@0: $context['sandbox']['field']['current_storage_id'] = $field_storage->id(); Chris@0: // If the storage has not been deleted yet we need to do that. This is the Chris@0: // case when the storage deletion is staged. Chris@0: if (!$field_storage->isDeleted()) { Chris@0: $field_storage->delete(); Chris@0: } Chris@0: } Chris@14: field_purge_batch($context['sandbox']['field']['purge_batch_size'], $field_storage->getUniqueStorageIdentifier()); Chris@0: $context['sandbox']['field']['current_progress']++; Chris@0: $fields_to_delete_count = count(static::getFieldStoragesToPurge($context['sandbox']['field']['extensions'], $config_importer->getUnprocessedConfiguration('delete'))); Chris@0: if ($fields_to_delete_count == 0) { Chris@0: $context['finished'] = 1; Chris@0: } Chris@0: else { Chris@0: $context['finished'] = $context['sandbox']['field']['current_progress'] / $context['sandbox']['field']['steps_to_delete']; Chris@0: $context['message'] = \Drupal::translation()->translate('Purging field @field_label', ['@field_label' => $field_storage->label()]); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Initializes the batch context sandbox for processing field deletions. Chris@0: * Chris@0: * This calculates the number of steps necessary to purge all the field data Chris@0: * and saves data for later use. Chris@0: * Chris@0: * @param array $context Chris@0: * The batch context. Chris@0: * @param \Drupal\Core\Config\ConfigImporter $config_importer Chris@0: * The config importer. Chris@0: */ Chris@0: protected static function initializeSandbox(array &$context, ConfigImporter $config_importer) { Chris@0: $context['sandbox']['field']['purge_batch_size'] = \Drupal::config('field.settings')->get('purge_batch_size'); Chris@0: // Save the future list of installed extensions to limit the amount of times Chris@0: // the configuration is read from disk. Chris@0: $context['sandbox']['field']['extensions'] = $config_importer->getStorageComparer()->getSourceStorage()->read('core.extension'); Chris@0: Chris@0: $context['sandbox']['field']['steps_to_delete'] = 0; Chris@0: $fields = static::getFieldStoragesToPurge($context['sandbox']['field']['extensions'], $config_importer->getUnprocessedConfiguration('delete')); Chris@0: foreach ($fields as $field) { Chris@0: $row_count = \Drupal::entityManager()->getStorage($field->getTargetEntityTypeId()) Chris@0: ->countFieldData($field); Chris@0: if ($row_count > 0) { Chris@0: // The number of steps to delete each field is determined by the Chris@0: // purge_batch_size setting. For example if the field has 9 rows and the Chris@0: // batch size is 10 then this will add 1 step to $number_of_steps. Chris@0: $how_many_steps = ceil($row_count / $context['sandbox']['field']['purge_batch_size']); Chris@0: $context['sandbox']['field']['steps_to_delete'] += $how_many_steps; Chris@0: } Chris@0: } Chris@0: // Each field possibly needs one last field_purge_batch() call to remove the Chris@0: // last field and the field storage itself. Chris@0: $context['sandbox']['field']['steps_to_delete'] += count($fields); Chris@0: Chris@0: $context['sandbox']['field']['current_progress'] = 0; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the list of fields to purge before configuration synchronization. Chris@0: * Chris@0: * If, during a configuration synchronization, a field is being deleted and Chris@0: * the module that provides the field type is being uninstalled then the field Chris@0: * data must be purged before the module is uninstalled. Also, if deleted Chris@0: * fields exist whose field types are provided by modules that are being Chris@0: * uninstalled their data need to be purged too. Chris@0: * Chris@0: * @param array $extensions Chris@0: * The list of extensions that will be enabled after the configuration Chris@0: * synchronization has finished. Chris@0: * @param array $deletes Chris@0: * The configuration that will be deleted by the configuration Chris@0: * synchronization. Chris@0: * Chris@0: * @return \Drupal\field\Entity\FieldStorageConfig[] Chris@0: * An array of field storages that need purging before configuration can be Chris@0: * synchronized. Chris@0: */ Chris@0: public static function getFieldStoragesToPurge(array $extensions, array $deletes) { Chris@0: $providers = array_keys($extensions['module']); Chris@0: $providers[] = 'core'; Chris@0: $storages_to_delete = []; Chris@0: Chris@0: // Gather fields that will be deleted during configuration synchronization Chris@0: // where the module that provides the field type is also being uninstalled. Chris@0: $field_storage_ids = []; Chris@0: foreach ($deletes as $config_name) { Chris@0: $field_storage_config_prefix = \Drupal::entityManager()->getDefinition('field_storage_config')->getConfigPrefix(); Chris@0: if (strpos($config_name, $field_storage_config_prefix . '.') === 0) { Chris@0: $field_storage_ids[] = ConfigEntityStorage::getIDFromConfigName($config_name, $field_storage_config_prefix); Chris@0: } Chris@0: } Chris@0: if (!empty($field_storage_ids)) { Chris@0: $field_storages = \Drupal::entityQuery('field_storage_config') Chris@0: ->condition('id', $field_storage_ids, 'IN') Chris@0: ->condition('module', $providers, 'NOT IN') Chris@0: ->execute(); Chris@0: if (!empty($field_storages)) { Chris@0: $storages_to_delete = FieldStorageConfig::loadMultiple($field_storages); Chris@0: } Chris@0: } Chris@0: Chris@0: // Gather deleted fields from modules that are being uninstalled. Chris@14: /** @var \Drupal\field\FieldStorageConfigInterface[] $deleted_storage_definitions */ Chris@14: $deleted_storage_definitions = \Drupal::service('entity_field.deleted_fields_repository')->getFieldStorageDefinitions(); Chris@14: foreach ($deleted_storage_definitions as $field_storage_definition) { Chris@14: if ($field_storage_definition instanceof FieldStorageConfigInterface && !in_array($field_storage_definition->getTypeProvider(), $providers)) { Chris@14: $storages_to_delete[$field_storage_definition->id()] = $field_storage_definition; Chris@0: } Chris@0: } Chris@0: return $storages_to_delete; Chris@0: } Chris@0: Chris@0: }