You are here

function lingotek_update_8011 in Lingotek Translation 8.2

Migrate Lingotek content metadata from fields to its own entity.

File

./lingotek.install, line 205
Install, update and uninstall functions for the Lingotek module.

Code

function lingotek_update_8011(&$sandbox) {

  // We need a temporary table for storing this data.
  $temp_schema['lingotek_temporary_content_metadata'] = [
    'fields' => [
      'entity_type' => [
        'description' => 'The entity type (node, comment, etc.).',
        'type' => 'varchar',
        'length' => 128,
        'not null' => TRUE,
        'default' => '',
      ],
      'entity_id' => [
        'description' => 'The primary identifier for the entity.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ],
      'document_id' => [
        'description' => 'The Lingotek document identifier.',
        'type' => 'varchar',
        'length' => 128,
        'not null' => FALSE,
        'default' => NULL,
      ],
      'hash' => [
        'description' => 'The Lingotek hash.',
        'type' => 'varchar',
        'length' => 255,
        'not null' => FALSE,
        'default' => NULL,
      ],
      'profile' => [
        'description' => 'The Lingotek profile being used.',
        'type' => 'varchar',
        'length' => 255,
        'not null' => FALSE,
        'default' => NULL,
      ],
      'translation_source' => [
        'description' => 'The Lingotek translation source.',
        'type' => 'varchar',
        'length' => 255,
        'not null' => FALSE,
        'default' => '',
      ],
      'translation_status' => [
        'description' => 'The Lingotek translation status.',
        'type' => 'blob',
        'not null' => TRUE,
      ],
    ],
    'primary key' => [
      'entity_type',
      'entity_id',
    ],
  ];
  if (!isset($sandbox['step'])) {

    // We need the temporary table.
    if (!\Drupal::database()
      ->schema()
      ->tableExists('lingotek_temporary_content_metadata')) {
      \Drupal::database()
        ->schema()
        ->createTable('lingotek_temporary_content_metadata', $temp_schema['lingotek_temporary_content_metadata']);
    }

    // We fetch all the entities we have info about.
    $entities = \Drupal::database()
      ->select('lingotek_content_metadata', 'lcm')
      ->fields('lcm', [
      'entity_id',
      'entity_type',
    ])
      ->execute()
      ->fetchAll();
    \Drupal::logger('lingotek')
      ->debug('Entities to update: %count', [
      '%count' => count($entities),
    ]);

    // We start collecting data.
    $sandbox['step'] = 'collect';

    // Initialize the sandbox.
    $sandbox['entities'] = $entities;
    $sandbox['progress'] = 0;
  }

  // We need to collect all the data.
  if (isset($sandbox['step']) && $sandbox['step'] === 'collect') {
    $entities = $sandbox['entities'];
    $sandbox['max'] = count($entities);
    $count = 0;
    for ($i = $sandbox['progress']; $count < 10 && $i < $sandbox['max']; $i++, $count++) {
      $entity_data = (array) $entities[$i];
      $entity_type_id = $entity_data['entity_type'];

      /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
      $storage = \Drupal::entityTypeManager()
        ->getStorage($entity_type_id);
      $entity = $storage
        ->load($entity_data['entity_id']);
      if ($entity) {
        $lingotek_document_id = $entity->lingotek_document_id->value;
        $lingotek_hash = $entity->lingotek_hash->value;
        $lingotek_profile = $entity->lingotek_profile->entity;
        $lingotek_profile_id = $lingotek_profile !== NULL ? $lingotek_profile
          ->id() : NULL;
        $lingotek_translation_source = $entity->lingotek_translation_source->value;
        $lingotek_translation_status = lingotek_legacy_get_translation_status($entity->lingotek_translation_status);
        \Drupal::logger('lingotek')
          ->debug('Storing temporary data for entity %entity_type %entity_id with document id %document_id', [
          '%entity_type' => $entity
            ->getEntityTypeId(),
          '%entity_id' => $entity
            ->id(),
          '%document_id' => $lingotek_document_id,
        ]);
        \Drupal::database()
          ->merge('lingotek_temporary_content_metadata')
          ->fields([
          'entity_type' => $entity
            ->getEntityTypeId(),
          'entity_id' => $entity
            ->id(),
          'document_id' => $lingotek_document_id,
          'hash' => $lingotek_hash,
          'profile' => $lingotek_profile_id,
          'translation_source' => $lingotek_translation_source,
          'translation_status' => json_encode($lingotek_translation_status),
        ])
          ->keys([
          'entity_type',
          'entity_id',
        ], [
          $entity
            ->getEntityTypeId(),
          $entity
            ->id(),
        ])
          ->execute();
      }
      $sandbox['progress']++;
      $sandbox['#finished'] = empty($sandbox['max']) ? 1 : $sandbox['progress'] / $sandbox['max'];
    }
    if (empty($entities) || $sandbox['#finished'] === 1) {

      // If we are finished, we must store everything now after installing our entity.
      $sandbox['#finished'] = 0;
      $sandbox['progress'] = 0;
      $sandbox['step'] = 'store';
      unset($sandbox['entities']);
      unset($sandbox['max']);
    }
  }

  // We need to store all the data.
  if (isset($sandbox['step']) && $sandbox['step'] === 'store') {

    // First we install the entity.
    if ($sandbox['progress'] === 0 && !isset($sandbox['max'])) {

      /** @var \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface $entity_definition_update_manager */
      $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
      $entity_definition_update_manager
        ->installEntityType(new ContentEntityType([
        'id' => 'lingotek_content_metadata',
        'label' => new TranslatableMarkup("Lingotek Content Metadata"),
        'base_table' => 'lingotek_metadata',
        'data_table' => 'lingotek_metadata_field_data',
        'entity_keys' => [
          'id' => 'id',
        ],
      ]));
      $fields['id'] = BaseFieldDefinition::create('integer')
        ->setLabel(new TranslatableMarkup('ID'))
        ->setReadOnly(TRUE)
        ->setSetting('unsigned', TRUE);
      $fields['content_entity_type_id'] = BaseFieldDefinition::create('string')
        ->setLabel(new TranslatableMarkup('Content entity type ID'))
        ->setDescription(new TranslatableMarkup('The ID of the content entity type this Lingotek status is for.'))
        ->setRequired(TRUE);
      $fields['content_entity_id'] = BaseFieldDefinition::create('integer')
        ->setLabel(new TranslatableMarkup('Content entity ID'))
        ->setDescription(new TranslatableMarkup('The ID of the content entity this Lingotek status is for.'))
        ->setRequired(TRUE);
      $fields['document_id'] = BaseFieldDefinition::create('string')
        ->setLabel(new TranslatableMarkup('Lingotek document id'))
        ->setDescription(new TranslatableMarkup('The Lingotek document id.'));
      $fields['hash'] = BaseFieldDefinition::create('string')
        ->setLabel(new TranslatableMarkup('Lingotek hash'))
        ->setDescription(new TranslatableMarkup('A hash of the Lingotek saved entity data, required for checking for changes.'));
      $fields['profile'] = BaseFieldDefinition::create('entity_reference')
        ->setLabel(new TranslatableMarkup('Lingotek profile'))
        ->setDescription(new TranslatableMarkup('The Lingotek profile defining this translation.'))
        ->setSetting('target_type', 'lingotek_profile');
      $fields['translation_source'] = BaseFieldDefinition::create('language')
        ->setLabel(new TranslatableMarkup('Lingotek translation source'))
        ->setDescription(new TranslatableMarkup('The source language from which this translation was created.'))
        ->setDefaultValue(LanguageInterface::LANGCODE_NOT_SPECIFIED)
        ->setTranslatable(TRUE);
      $fields['translation_status'] = BaseFieldDefinition::create('lingotek_language_key_value')
        ->setLabel(new TranslatableMarkup('Lingotek translation status'))
        ->setDescription(new TranslatableMarkup('The status of the source in case of being the source translation, or the status of the translation.'))
        ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
      foreach ($fields as $name => $storage_definition) {
        $entity_definition_update_manager
          ->installFieldStorageDefinition($name, 'lingotek_content_metadata', 'lingotek', $storage_definition);
      }

      // ToDo: Remove the fields when possible. See https://www.drupal.org/node/2859665
      // We need to keep these until we can purge data.
      // See https://www.drupal.org/node/2282119.
    }
    if (!isset($sandbox['entities'])) {

      // We fetch all the entities we have info about.
      $entities = \Drupal::database()
        ->select('lingotek_temporary_content_metadata', 'lcm')
        ->fields('lcm', [
        'entity_id',
        'entity_type',
        'hash',
        'document_id',
        'profile',
        'translation_source',
        'translation_status',
      ])
        ->execute()
        ->fetchAll();
      if (!$entities) {

        // There are no entity metadata stored. We must be done.
        $sandbox['#finished'] = 1;
        return;
      }
      $sandbox['entities'] = $entities;
      $sandbox['max'] = count($entities);
      $sandbox['progress'] = 0;
    }
    $count = 0;
    for ($i = $sandbox['progress']; $count < 10 && $i < $sandbox['max']; $i++, $count++) {
      $entity_data = (array) $sandbox['entities'][$i];
      $entity = \Drupal::entityTypeManager()
        ->getStorage($entity_data['entity_type'])
        ->load($entity_data['entity_id']);
      if ($entity) {
        $metadata = LingotekContentMetadata::create([
          'content_entity_type_id' => $entity_data['entity_type'],
          'content_entity_id' => $entity_data['entity_id'],
          'document_id' => $entity_data['document_id'],
          'hash' => $entity_data['hash'],
          'profile' => $entity_data['profile'],
          'translation_source' => $entity_data['translation_source'],
        ]);
        lingotek_legacy_set_translation_status($metadata, $entity_data['translation_status']);
        $metadata
          ->save();
      }
      $sandbox['progress']++;
      $sandbox['#finished'] = empty($sandbox['max']) ? 1 : $sandbox['progress'] / $sandbox['max'];
      if ($sandbox['#finished'] === 1) {

        // If we are finished, we must clear the temporary table.
        \Drupal::database()
          ->schema()
          ->dropTable('lingotek_temporary_content_metadata');
        unset($sandbox['step']);
      }
    }
  }
}