You are here

function multiversion_update_8007 in Multiversion 8

Create missing revisionable fields in the revision table.

File

./multiversion.install, line 301

Code

function multiversion_update_8007() {
  $connection = Database::getConnection();
  if ($connection instanceof Connection) {
    $schema = $connection
      ->schema();
    $entity_type_manager = \Drupal::entityTypeManager();
    $manager = \Drupal::service('multiversion.manager');

    // Find all supported entities.
    $entity_types = $manager
      ->getSupportedEntityTypes();

    // Loop through each one.
    foreach ($entity_types as $entity_type_id => $entity_type) {
      $id_key = $entity_type
        ->getKey('id');

      /** @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage $storage */
      $storage = $entity_type_manager
        ->getStorage($entity_type_id);

      // Get the tables name used for base table and revision table.
      $table_base = $entity_type
        ->isTranslatable() ? $entity_type
        ->getDataTable() : $entity_type
        ->getBaseTable();
      $table_revision = $entity_type
        ->isTranslatable() ? $entity_type
        ->getRevisionDataTable() : $entity_type
        ->getRevisionTable();

      // Block content definition doesn't include the revision field table.
      // So get it.

      /** @var \Drupal\Core\Entity\Sql\TableMappingInterface $table_mapping */
      $table_mapping = $storage
        ->getTableMapping();
      $tables = $table_mapping
        ->getTableNames();
      if (!$table_revision && in_array($entity_type_id . '_field_revision', $tables)) {
        $table_revision = $entity_type_id . '_field_revision';
      }
      elseif (!$table_revision && in_array($entity_type_id . '_revision', $tables)) {
        $table_revision = $entity_type_id . '_revision';
      }
      if ($schema
        ->tableExists($table_base) && $table_revision) {

        // Get data from base table.
        $table_base_results = $connection
          ->select($table_base)
          ->fields($table_base)
          ->execute()
          ->fetchAll();

        // Get data from revision table.
        $table_revision_results = $connection
          ->select($table_revision)
          ->fields($table_revision)
          ->execute()
          ->fetchAll();
        if (in_array($table_revision, $tables)) {
          $table_revision_fields = $table_mapping
            ->getFieldNames($table_revision);
          $entity_field_manager = \Drupal::service('entity_field.manager');
          $fields = $entity_field_manager
            ->getBaseFieldDefinitions($entity_type_id);
          $new_field_storage_definitions = [];

          // Loop through all the fields, if the field exists in the new
          // revision table mapping and it doesn't exist in the database,
          // create the new field.
          foreach ($fields as $field_name => $field) {
            if (in_array($field_name, $table_revision_fields) && !$schema
              ->fieldExists($table_revision, $field_name)) {
              $new_field_storage_definitions[] = $field
                ->getFieldStorageDefinition($field
                ->getName(), $entity_type_id);
            }
          }
          if (!empty($new_field_storage_definitions)) {

            // Remove all data from revision table before adding new fields.
            $connection
              ->truncate($table_revision)
              ->execute();
            foreach ($new_field_storage_definitions as $storage_definition) {
              \Drupal::service('field_storage_definition.listener')
                ->onFieldStorageDefinitionCreate($storage_definition);
            }
          }

          // If the revision table has been updated (new field has been added),
          // complete new fields with data from base table.
          if (!empty($new_field_storage_definitions)) {
            $table_base_results_keyed = [];
            foreach ($table_base_results as $result) {
              if (isset($result->{$id_key})) {
                $data = (array) $result;
                $table_base_results_keyed[$result->{$id_key}] = $data;

                // Add data for fields with multiple columns, like link__title,
                // link__description, ...
                foreach ($data as $field_column_name => $value) {
                  if ($field_name = strstr($field_column_name, '__', TRUE)) {
                    if (in_array($field_name, $table_revision_fields) && !in_array($field_column_name, $table_revision_fields)) {
                      $table_base_results_keyed[$result->{$id_key}][$field_column_name] = $data[$field_column_name];
                      $table_revision_fields[] = $field_column_name;
                    }
                  }
                }
              }
            }

            // For the new created revisionable fields take data from base table.
            foreach ($table_revision_results as $result) {
              $data = (array) $result;
              foreach ($table_revision_fields as $field_name) {
                if (!isset($data[$field_name]) && isset($table_base_results_keyed[$result->{$id_key}][$field_name])) {
                  $data[$field_name] = $table_base_results_keyed[$result->{$id_key}][$field_name];
                }
              }

              // Save the information in the revision table.
              $connection
                ->insert($table_revision)
                ->fields($data)
                ->execute();
            }
          }
        }
      }
    }
  }
}