function SqlFieldableEntityTypeListenerTrait::copyData

Same name in other branches
  1. 8.9.x core/lib/Drupal/Core/Entity/Sql/SqlFieldableEntityTypeListenerTrait.php \Drupal\Core\Entity\Sql\SqlFieldableEntityTypeListenerTrait::copyData()
  2. 10 core/lib/Drupal/Core/Entity/Sql/SqlFieldableEntityTypeListenerTrait.php \Drupal\Core\Entity\Sql\SqlFieldableEntityTypeListenerTrait::copyData()
  3. 11.x core/lib/Drupal/Core/Entity/Sql/SqlFieldableEntityTypeListenerTrait.php \Drupal\Core\Entity\Sql\SqlFieldableEntityTypeListenerTrait::copyData()

Copies entity data from the original storage to the temporary one.

Parameters

\Drupal\Core\Entity\EntityTypeInterface $entity_type: The updated entity type definition.

\Drupal\Core\Entity\EntityTypeInterface $original: The original entity type definition.

\Drupal\Core\Field\FieldStorageDefinitionInterface[] $field_storage_definitions: The updated field storage definitions, including possibly new ones.

\Drupal\Core\Field\FieldStorageDefinitionInterface[] $original_field_storage_definitions: The original field storage definitions.

array &$sandbox: The sandbox array from a hook_update_N() implementation.

1 call to SqlFieldableEntityTypeListenerTrait::copyData()
SqlFieldableEntityTypeListenerTrait::onFieldableEntityTypeUpdate in core/lib/Drupal/Core/Entity/Sql/SqlFieldableEntityTypeListenerTrait.php

File

core/lib/Drupal/Core/Entity/Sql/SqlFieldableEntityTypeListenerTrait.php, line 137

Class

SqlFieldableEntityTypeListenerTrait
Helper methods for EntityTypeListenerInterface.

Namespace

Drupal\Core\Entity\Sql

Code

protected function copyData(EntityTypeInterface $entity_type, EntityTypeInterface $original, array $field_storage_definitions, array $original_field_storage_definitions, array &$sandbox) {
    
    /** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */
    $id_key = $entity_type->getKey('id');
    $revision_id_key = $entity_type->getKey('revision');
    $revision_default_key = $entity_type->getRevisionMetadataKey('revision_default');
    $langcode_key = $entity_type->getKey('langcode');
    $default_langcode_key = $entity_type->getKey('default_langcode');
    $revision_translation_affected_key = $entity_type->getKey('revision_translation_affected');
    // If 'progress' is not set, then this will be the first run of the batch.
    if (!isset($sandbox['progress'])) {
        $sandbox['progress'] = 0;
        $sandbox['current_id'] = -1;
    }
    // If the original entity type is revisionable, we need to copy all the
    // revisions.
    $load_revisions = $original->isRevisionable();
    if ($load_revisions) {
        $table_name = $original->getRevisionTable();
        $identifier_field = $revision_id_key;
    }
    else {
        $table_name = $original->getBaseTable();
        $identifier_field = $id_key;
    }
    // Get the next entity identifiers to migrate.
    // @todo Use an entity query when it is able to use the last installed
    //   entity type and field storage definitions.
    // @see https://www.drupal.org/project/drupal/issues/2554235
    $step_size = Settings::get('entity_update_batch_size', 50);
    $entity_identifiers = $this->database
        ->select($table_name, 't')
        ->condition("t.{$identifier_field}", $sandbox['current_id'], '>')
        ->fields('t', [
        $identifier_field,
    ])
        ->orderBy($identifier_field, 'ASC')
        ->range(0, $step_size)
        ->execute()
        ->fetchCol();
    
    /** @var \Drupal\Core\Entity\ContentEntityInterface[] $entities */
    $entities = $load_revisions ? $this->storage
        ->loadMultipleRevisions($entity_identifiers) : $this->storage
        ->loadMultiple($entity_identifiers);
    
    /** @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage $temporary_storage */
    $temporary_storage = $this->entityTypeManager
        ->createHandlerInstance($entity_type->getStorageClass(), $entity_type);
    $temporary_storage->setEntityType($entity_type);
    $temporary_storage->setFieldStorageDefinitions($field_storage_definitions);
    $temporary_storage->setTableMapping($sandbox['temporary_table_mapping']);
    foreach ($entities as $identifier => $entity) {
        try {
            if (!$original->isRevisionable() && $entity_type->isRevisionable()) {
                // Set the revision ID to be same as the entity ID.
                $entity->set($revision_id_key, $entity->id());
                // We had no revisions so far, so the existing data belongs to the
                // default revision now.
                $entity->set($revision_default_key, TRUE);
            }
            // Set the 'langcode' and 'default_langcode' values as needed.
            if (!$original->isTranslatable() && $entity_type->isTranslatable()) {
                if ($entity->get($langcode_key)
                    ->isEmpty()) {
                    $entity->set($langcode_key, \Drupal::languageManager()->getDefaultLanguage()
                        ->getId());
                }
                $entity->set($default_langcode_key, TRUE);
            }
            // Set the 'revision_translation_affected' field to TRUE to match the
            // return value of the case when the field does not exist.
            if ((!$original->isRevisionable() || !$original->isTranslatable()) && $entity_type->isRevisionable() && $entity_type->isTranslatable()) {
                $entity->set($revision_translation_affected_key, TRUE);
            }
            // Finally, save the entity in the temporary storage.
            $temporary_storage->restore($entity);
        } catch (\Exception $e) {
            $this->handleEntityTypeSchemaUpdateExceptionOnDataCopy($entity_type, $original, $sandbox);
            // Re-throw the original exception with a helpful message.
            $error_revision_id = $load_revisions ? ", revision ID: {$entity->getLoadedRevisionId()}" : '';
            throw new EntityStorageException("The entity update process failed while processing the entity type {$entity_type->id()}, ID: {$entity->id()}{$error_revision_id}.", $e->getCode(), $e);
        }
        $sandbox['progress']++;
        $sandbox['current_id'] = $identifier;
    }
    // Reset the cache in order to free memory as we progress.
    \Drupal::service('entity.memory_cache')->deleteAll();
    // Get an updated count of entities that still need to migrated to the new
    // storage.
    $missing = $this->database
        ->select($table_name, 't')
        ->condition("t.{$identifier_field}", $sandbox['current_id'], '>')
        ->orderBy($identifier_field, 'ASC')
        ->countQuery()
        ->execute()
        ->fetchField();
    $sandbox['#finished'] = $missing ? $sandbox['progress'] / ($sandbox['progress'] + (int) $missing) : 1;
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.