You are here

entityreference_migration.module in Reference to EntityReference Field Migration 7.2

Same filename and directory in other branches
  1. 7 entityreference_migration.module

File

entityreference_migration.module
View source
<?php

/**
 * Implementation of hook_menu().
 */
function entityreference_migration_menu() {
  $items = array();
  $items['admin/content/migrate-references'] = array(
    'title' => 'Migrate References Fields',
    'description' => 'Migrate References fields to Entity References.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'entityreference_migration_migrate_references_fields',
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer content types',
    ),
  );
  return $items;
}
function entityreference_migration_migrate_references_fields($form, &$form_state) {

  // Load all references fields.
  $node_field_infos = field_read_fields(array(
    'type' => 'node_reference',
  ), array(
    'include_inactive' => TRUE,
    'include_deleted' => TRUE,
  ));
  $user_field_infos = field_read_fields(array(
    'type' => 'user_reference',
  ), array(
    'include_inactive' => TRUE,
    'include_deleted' => TRUE,
  ));
  $term_field_infos = field_read_fields(array(
    'type' => 'taxonomy_term_reference',
  ), array(
    'include_inactive' => TRUE,
    'include_deleted' => TRUE,
  ));
  $field_infos = $node_field_infos + $user_field_infos + $term_field_infos;
  if (count($field_infos) > 0) {
    $field_options = array();
    foreach ($field_infos as $key => $field_info) {
      $translate_array = array(
        '@field_name' => $field_info['field_name'],
      );
      $instances = field_read_instances(array(
        'field_name' => $field_info['field_name'],
      ), array(
        'include_inactive' => TRUE,
        'include_deleted' => TRUE,
      ));
      $options_instances = array();
      foreach ($instances as $instance) {
        $options_instances[] = $instance['entity_type'] . ':' . $instance['bundle'] . ' (' . check_plain($instance['label']) . ')';
      }
      $translate_array['@instances'] = implode(', ', $options_instances);
      $field_options[$key] = t($field_info['type'] . ' @field_name: Appears in [@instances]', $translate_array);
    }
    $form['field_information'] = array(
      '#type' => 'value',
      '#value' => $field_infos,
    );
    $form['field_options'] = array(
      '#type' => 'checkboxes',
      '#title' => t('Which references fields do you wish to migrate?'),
      '#options' => $field_options,
      '#required' => TRUE,
    );
    return confirm_form($form, t('Are you sure you wish to migrate the selected references fields?'), '<front>');
  }
  $form['message'] = array(
    '#markup' => t('There are no references fields that need to be migrated at this time.'),
  );
  return $form;
}
function entityreference_migration_migrate_references_fields_submit($form, &$form_state) {
  $values = $form_state['values'];
  $field_infos = $values['field_information'];

  // Define the batch.
  $batch = array(
    'operations' => array(),
    'finished' => '_entityreference_migration_batches_finished',
    'title' => t('Start migrating reference fields.'),
    'init_message' => t('Preparing to migrate reference fields.'),
    'progress_message' => t('Migrating references fields.'),
    'error_message' => t('Reference field could not migrate content successfully.'),
  );
  foreach ($values['field_options'] as $key => $field_option) {
    if (!empty($field_option)) {
      $field_name = $field_infos[$key]['field_name'];

      // Create table for migration.
      $table_name = _field_sql_storage_tablename($field_infos[$key]);
      $temp_table_name = substr('er_m_' . $table_name, 0, 63);
      $field_instances = field_read_instances(array(
        'field_name' => $field_name,
      ), array(
        'include_inactive' => TRUE,
        'include_deleted' => TRUE,
      ));
      $batch['operations'][] = array(
        '_entity_reference_migration_copy_temporary_table',
        array(
          $key,
          $field_infos[$key],
          $field_name,
          $field_instances,
          $table_name,
          $temp_table_name,
        ),
      );
      $batch['operations'][] = array(
        '_entityreference_migration_purge_references_field',
        array(
          $key,
          $field_infos[$key],
          $field_name,
          $field_instances,
          $table_name,
          $temp_table_name,
        ),
      );
      $batch['operations'][] = array(
        '_entityreference_migration_migrate_temporary_references_field',
        array(
          $key,
          $field_infos[$key],
          $field_name,
          $field_instances,
          $table_name,
          $temp_table_name,
        ),
      );
    }
  }
  batch_set($batch);
}
function _entityreference_migration_batches_finished($success, $results, $operations) {
  drupal_set_message(t('Succesfully migrated requested reference fields!'));
}
function _entity_reference_migration_copy_temporary_table($field_key, $field_info, $field_name, $field_instances, $table_name, $temp_table_name, &$context) {
  if (!db_table_exists($temp_table_name)) {
    $schema = drupal_get_schema($table_name, TRUE);
    $schema['name'] = $temp_table_name;
    db_create_table($temp_table_name, $schema);
  }

  //PRIMARY KEY (`entity_type`, `entity_id`, `deleted`, `delta`, `language`)

  // Make sure we don't stumble over leftovers of broken migrations.
  $deleted_table_name = _field_sql_storage_tablename(array(
    'deleted' => TRUE,
  ) + $field_info);
  $deleted_revision_table_name = _field_sql_storage_revision_tablename(array(
    'deleted' => TRUE,
  ) + $field_info);
  if ($field_key == $field_info['id'] && db_table_exists($table_name)) {
    if (db_table_exists($deleted_table_name)) {
      db_drop_table($deleted_table_name);
    }
    if (db_table_exists($deleted_revision_table_name)) {
      db_drop_table($deleted_revision_table_name);
    }
  }

  // Export data.
  if (db_table_exists($table_name)) {
    $fields = array();
    foreach ($schema['fields'] as $key => $value) {
      if ($key !== 'er_m_id') {
        $fields[] = $key;
      }
    }
    $query = db_select($table_name)
      ->fields($table_name, $fields);
    db_insert($temp_table_name)
      ->from($query)
      ->execute();
  }
}
function _entityreference_migration_purge_references_field($field_key, $field_info, $field_name, $field_instances, $table_name, $temp_table_name, &$context) {
  foreach ($field_instances as $instance) {
    field_delete_instance($instance);
    field_purge_instance($instance);
  }
  field_delete_field($field_name);
  field_purge_field($field_info);
}
function _entityreference_migration_migrate_temporary_references_field($field_key, $field_info, $field_name, $field_instances, $table_name, $temp_table_name, &$context) {
  $context['message'] = t("Processing @field_name", array(
    '@field_name' => $field_info['field_name'],
  ));
  if (!in_array($field_info['type'], array(
    'node_reference',
    'user_reference',
    'taxonomy_term_reference',
  ))) {
    drupal_set_message(t("Field @field is not a references field.", array(
      '@field' => $field_name,
    )), 'error');
  }
  else {
    _entityreference_migration_references_field_to_entityreference_field($field_key, $field_info, $field_name, $field_instances, $table_name, $temp_table_name, $context);
  }
}

/**
 * Migrate a field from references to entityreference.
 */
function _entityreference_migration_references_field_to_entityreference_field($field_key, $field_info, $field_name, $field_instances, $table_name, $temp_table_name, &$context) {
  if (!isset($context['sandbox']['entityreference_table_name'])) {
    $context['message'] = t("Processing @field_name", array(
      '@field_name' => $field_info['field_name'],
    ));
    $entityreference_field = _entityreference_migration_references_field_to_entityreference_field_create_field($field_info);

    // Create the field instances
    foreach ($field_instances as $instance) {
      _entityreference_migration_references_field_to_entityreference_field_create_instance($entityreference_field, $instance);
    }
    $context['sandbox']['entityreference_table_name'] = _field_sql_storage_tablename($entityreference_field);
    $context['sandbox']['entityreference_revision_table_name'] = _field_sql_storage_revision_tablename($entityreference_field);
  }

  // And now migrate data.
  $results = db_select($temp_table_name)
    ->fields($temp_table_name)
    ->range(0, 100)
    ->execute()
    ->fetchAll(PDO::FETCH_ASSOC);
  if ($results) {
    $context['finished'] = 0;
    $insert = db_insert($context['sandbox']['entityreference_table_name']);
    $insert_revision = db_insert($context['sandbox']['entityreference_revision_table_name']);
    foreach ($results as $key => $result) {
      if ($field_info['type'] == 'node_reference') {
        $target_id_field = $field_name . '_nid';
      }
      else {
        if ($field_info['type'] == 'user_reference') {
          $target_id_field = $field_name . '_uid';
        }
        else {
          if ($field_info['type'] == 'taxonomy_term_reference') {
            $target_id_field = $field_name . '_tid';
          }
        }
      }
      $result[$field_name . '_target_id'] = $result[$target_id_field];
      unset($result[$target_id_field]);

      // Ensure the field value is not NULL to avoid MySQL Exceptions
      if ($result[$field_name . '_target_id'] != NULL) {
        if ($key) {
          $insert
            ->values($result);
          $insert_revision
            ->values($result);
        }
        else {
          $insert
            ->fields(array_keys($result), $result);
          $insert_revision
            ->fields(array_keys($result), $result);
        }
      }
      db_delete($temp_table_name)
        ->condition('entity_type', $result['entity_type'])
        ->condition('entity_id', $result['entity_id'])
        ->condition('deleted', $result['deleted'])
        ->condition('delta', $result['delta'])
        ->condition('language', $result['language'])
        ->execute();
    }
    $insert
      ->execute();
    $insert_revision
      ->execute();
  }
  else {
    db_drop_table($temp_table_name);
    $context['finished'] = 1.0;
    drupal_set_message(t("Processed @field_name", array(
      '@field_name' => $field_info['field_name'],
    )));
  }
}

/**
 * Create a new entityreference field based off the old field information.
 */
function _entityreference_migration_references_field_to_entityreference_field_create_field($field_info) {
  $field_name = $field_info['field_name'];

  // Recreate fields by using entityreference.
  $target_bundles = array();
  $field_type = $field_info['type'];
  if ($field_type == 'node_reference') {
    $target_type = 'node';
    if (isset($field_info['settings']['referenceable_types'])) {
      $target_bundles = array_filter($field_info['settings']['referenceable_types']);
    }
  }
  else {
    if ($field_type == 'user_reference') {
      $target_type = 'user';
      if (isset($field_info['settings']['referenceable_types'])) {
        $target_bundles = array_filter($field_info['settings']['referenceable_types']);
      }
    }
    else {
      if ($field_type == 'taxonomy_term_reference') {
        $target_type = 'taxonomy_term';
        $bundle = $field_info['settings']['allowed_values'][0]['vocabulary'];
        $target_bundles[$bundle] = $bundle;
      }
    }
  }
  $entityreference_field = array(
    'field_name' => $field_name,
    'type' => 'entityreference',
    'module' => 'entityreference',
    'entity_types' => array(),
    'foreign keys' => array(),
    'indexes' => array(
      'target_entity' => array(
        '0' => 'target_id',
      ),
    ),
    'settings' => array(
      'handler' => 'base',
      'handler_settings' => array(
        'target_bundles' => $target_bundles,
      ),
      'handler_submit' => 'Change handler',
      'target_type' => $target_type,
    ),
    'cardinality' => $field_info['cardinality'],
    'locked' => $field_info['locked'],
    'active' => $field_info['active'],
    'translatable' => $field_info['translatable'],
  );
  $entityreference_field = field_create_field($entityreference_field);
  return $entityreference_field;
}

/**
 * Create the bundle instances of entityreference fields.
 */
function _entityreference_migration_references_field_to_entityreference_field_create_instance($entityreference_field, $instance) {
  $entityreference_instance = array(
    'label' => $instance['label'],
    'required' => $instance['required'],
    'description' => $instance['description'],
    'default_value' => $instance['default_value'],
    'field_name' => $instance['field_name'],
    'entity_type' => $instance['entity_type'],
    'bundle' => $instance['bundle'],
    'deleted' => $instance['deleted'],
  );

  // Add in the widget and appropriate settings (TODO for more flexibility)
  if (isset($instance['widget'])) {
    $widget_type = 'entityreference_autocomplete';
    $widget_module = 'entityreference';
    if ($instance['widget']['module'] == 'options') {
      $widget_type = $instance['widget']['type'];
      $widget_module = $instance['widget']['module'];
    }
    $entityreference_instance['widget'] = array(
      'weight' => $instance['widget']['weight'],
      'type' => $widget_type,
      'module' => $widget_module,
      'active' => 1,
      'settings' => array(
        'match_operator' => 'CONTAINS',
        'size' => 60,
        'path' => '',
      ),
    );
  }

  // Add in the display and appropriate settings
  if (isset($instance['display'])) {
    foreach ($instance['display'] as $display_name => $instance_display) {
      $entityreference_instance['display'][$display_name] = array(
        'label' => $instance_display['label'],
        'weight' => $instance_display['weight'],
        'module' => 'entityreference',
      );
      if ($instance_display['type'] == 'hidden') {
        $entityreference_instance['display'][$display_name]['type'] = 'hidden';
      }
      else {
        if ($instance_display['type'] == 'node_reference_node' || $instance_display['type'] == 'user_reference_user') {
          $entityreference_instance['display'][$display_name]['type'] = 'entityreference_entity_view';
          $entityreference_instance['display'][$display_name]['settings'] = array(
            'view_mode' => $instance_display['settings'][$instance_display['module'] . '_view_mode'],
          );
        }
        else {
          if ($instance_display['type'] == 'node_reference_default' || $instance_display['type'] == 'user_reference_default') {
            $entityreference_instance['display'][$display_name]['type'] = 'entityreference_label';
            $entityreference_instance['display'][$display_name]['settings'] = array(
              'link' => TRUE,
            );
          }
          else {
            $entityreference_instance['display'][$display_name]['type'] = 'entityreference_label';
            $entityreference_instance['display'][$display_name]['settings'] = array(
              'link' => TRUE,
            );
          }
        }
      }
    }
  }
  $entityreference_instance = field_create_instance($entityreference_instance);
  return $entityreference_instance;
}