You are here

crm_core_data_import.admin.inc in CRM Core 7

Configuration pages for CRM Core Data Import.

File

modules/crm_core_data_import/crm_core_data_import.admin.inc
View source
<?php

/**
 * @file
 * Configuration pages for CRM Core Data Import.
 */

/**
 * Page callback for data import dashboard.
 */
function crm_core_data_import_dashboard_form($form, &$form_state) {
  $items = array();
  $available = _crm_core_data_import_get_tasks();
  crm_core_ui_ctools_add_dropbutton_files();
  foreach ($available as $key => $importer) {
    $importer = crm_core_data_import_load_importer($key);

    // Operations.
    $links = array();
    $links[] = l(t('Edit source'), 'admin/structure/crm-core/data-import/' . $key . '/source-selection');
    $links[] = l(t('Edit source settings'), 'admin/structure/crm-core/data-import/' . $key . '/source-settings');
    if (!empty($importer->source_plugin->sourceMapping)) {
      $links[] = l(t('Edit source mapping'), 'admin/structure/crm-core/data-import/' . $key . '/source-mapping');
    }
    $links[] = l(t('Edit field mapping'), 'admin/structure/crm-core/data-import/' . $key . '/field-mapping');
    $links[] = l(t('Edit settings'), 'admin/structure/crm-core/data-import/' . $key . '/settings');
    $links[] = l(t('Delete'), 'admin/structure/crm-core/data-import/' . $key . '/delete');
    $stats = _crm_core_data_import_migration_statistic_get($importer);
    $items[$key] = array(
      'title' => $importer->title,
      'description' => $importer->description,
      'lastimport' => empty($importer->lastimport) ? t('Unknown') : format_date($importer->lastimport, 'custom', 'Y-m-d H:i:s'),
      'status' => _crm_core_data_import_migration_status($stats['status']),
      'items' => $stats['total'],
      'imported' => $stats['imported'],
      'unprocessed' => $stats['total'] - $stats['processed'],
      'operations' => theme('crm_core_ui_ctools_dropbutton', array(
        'ops_count' => count($links),
        'links' => $links,
        'index' => $key,
      )),
    );
  }
  $form['operation'] = array(
    '#type' => 'select',
    '#title' => t('With selected:'),
    '#options' => array(
      'import' => t('Start import'),
      'rollback' => t('Rollback'),
      'deregister' => t('Remove migration settings'),
    ),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Go'),
  );
  $form['items'] = array(
    '#type' => 'tableselect',
    '#header' => array(
      'title' => t('Title'),
      'description' => t('Description'),
      'status' => t('Status'),
      'items' => t('Items'),
      'imported' => t('Imported'),
      'unprocessed' => t('Unprocessed'),
      'lastimport' => t('Last imported'),
      'operations' => t('Operations'),
    ),
    '#options' => $items,
    '#empty' => t('No items available'),
  );
  $form['#attached']['css'][] = _crm_core_data_import_css_path();
  return $form;
}

/**
 * Submit handler for data import dashboard.
 */
function crm_core_data_import_dashboard_form_submit(&$form, &$form_state) {
  $importers = $form_state['values']['items'];
  $operation = $form_state['values']['operation'];
  $operations = array();
  $options = array(
    'value' => 0,
    'unit' => 'items',
  );
  foreach ($importers as $importer_id) {
    if (!empty($importer_id)) {
      $importer = crm_core_data_import_load_importer($importer_id);
      switch ($operation) {
        case 'import':

          // If source not configured.
          $source_fields = $importer
            ->getSourceFields();
          if (!empty($source_fields)) {

            // Run import selected operation.
            $mapping = $importer
              ->getMappingSettings();
            if (!empty($mapping)) {
              _crm_core_data_import_build_entity_operations($operations, $mapping, $importer_id, $options);
            }
            else {
              drupal_set_message(t('Mapping is empty. Please configure your !mapping.', array(
                '!mapping' => l(t('mapping'), 'admin/structure/crm-core/data-import/' . $importer->id . '/field-mapping'),
              )), 'error');
            }
          }
          else {
            drupal_set_message(t('Source fields are empty. Please configure your !source.', array(
              '!source' => l(t('source'), 'admin/structure/crm-core/data-import/' . $importer->id . '/source-settings'),
            )), 'error');
          }
          break;
        case 'rollback':

          // Rollback for all registered migrations.
          $registered_migrations = variable_get('crm_core_data_import_migrations_' . $importer->id, array());
          foreach ($registered_migrations as $machine_name) {
            $migration = Migration::getInstance($machine_name);
            if ($migration) {
              $operations[] = array(
                'crm_core_data_import_batch',
                array(
                  'rollback',
                  $machine_name,
                  $options,
                  0,
                ),
              );
            }
          }
          break;
        case 'deregister':

          // Deregister all registered migrations.
          $registered_migrations = variable_get('crm_core_data_import_migrations_' . $importer->id, array());
          foreach ($registered_migrations as $machine_name) {
            $migration = Migration::getInstance($machine_name);
            if ($migration) {
              Migration::deregisterMigration($machine_name);
              drupal_set_message(t('Deregistered "@task_name" task', array(
                '@task_name' => $machine_name,
              )));
            }
          }
          _crm_core_data_import_migration_statistic_reset($importer);
          break;
      }
      if (count($operations) > 0) {
        $batch = array(
          'operations' => $operations,
          'title' => t('Import processing'),
          'file' => drupal_get_path('module', 'crm_core_data_import') . '/crm_core_data_import.admin.inc',
          'init_message' => t('Starting import process'),
          'progress_message' => '',
          'error_message' => t('An error occurred. Some or all of the import processing has failed.'),
          'finished' => 'crm_core_data_import_migration_batch_finish',
        );
        batch_set($batch);

        // Set importer id for finished callback. Might be improved.
        // There no another way to pass variable to finished callback.
        $_SESSION['data_import_batch_importer_id'] = $importer_id;
      }
    }
  }
}

/**
 * Batch API item callback.
 */
function crm_core_data_import_batch($operation, $machine_name, $limit, $force, &$context) {
  module_load_include('inc', 'migrate_ui', 'migrate_ui.pages');
  migrate_ui_batch($operation, $machine_name, $limit, $force, $context);
}

/**
 * Batch API finished callback. Trigger controllers for settings.
 */
function crm_core_data_import_migration_batch_finish($success, $results, $operations) {
  if ($success) {
    if (!empty($_SESSION['data_import_batch_importer_id'])) {
      $importer = crm_core_data_import_load_importer($_SESSION['data_import_batch_importer_id']);
      $importer->lastimport = time();
      $importer
        ->save();
      _crm_core_data_import_migration_statistic_reset($importer);
      crm_core_data_settings_batch($_SESSION['data_import_batch_importer_id']);
      unset($_SESSION['data_import_batch_importer_id']);
    }
  }
}

/**
 * Run batch for plugins.
 */
function crm_core_data_settings_batch($importer_id) {

  // Get importer.
  $operations = array();
  $importer = crm_core_data_import_load_importer($importer_id);
  $mapping = $importer
    ->getMappingSettings();
  if (!empty($mapping)) {

    // Collect results.
    foreach ($mapping as $key => $mapping_item) {
      list($entity_controller_type, $entity_bundle, $bundle_delta) = explode(':', $key);
      $entity_type = crm_core_data_import_get_destination_entity_type($entity_controller_type);
      $machine_name = _crm_core_data_import_migration_machine_name($importer_id, $entity_type, $entity_bundle, $bundle_delta);
      $migration = Migration::getInstance($machine_name);
      if ($migration) {
        $map = $migration
          ->getMap();
        $source_key_map = $map
          ->getSourceKeyMap();
        $importer_query = db_select($map
          ->getMapTable(), 'map');
        foreach ($source_key_map as $name => $alias) {
          $importer_query
            ->addField('map', $alias);
        }

        // There is no MigrateMap::getDestinationKeyMap() function. WTF?
        $importer_query
          ->addField('map', 'destid1');
        foreach ($importer
          ->getRelationDestinationEndPoints(implode(':', array(
          $entity_type,
          $entity_bundle,
          $bundle_delta,
        ))) as $key => $ep) {
          $importer_query
            ->addField('map', 'relation_id' . ($key + 1));
        }
        $importer_result = $importer_query
          ->execute();

        // Add to imported entities necessary information.
        $entity_type = $migration
          ->getEntityType();
        $bundle = $migration
          ->getEntityBundle();
        foreach ($importer_result as $row) {
          $data = array(
            'entity_type' => $entity_type,
            'bundle' => $bundle,
            'entity_id' => $row->destid1,
            'delta' => $bundle_delta,
          );
          foreach ($importer
            ->getRelationDestinationEndPoints(implode(':', array(
            $entity_type,
            $entity_bundle,
            $bundle_delta,
          ))) as $key => $endpoint) {
            $name = 'relation_id' . ($key + 1);
            $data[$name] = $row->{$name};
          }
          $source_keys = array();
          foreach ($source_key_map as $name => $alias) {
            $data[$alias] = $row->{$alias};
            $source_keys[$alias] = $row->{$alias};
          }
          $operations[] = array(
            'crm_core_data_run_settings_plugins_for_entity',
            array(
              $machine_name,
              $source_keys,
              $importer,
              $data,
            ),
          );
        }
      }
    }
    if (count($operations) > 0) {

      // Clear static $batch array to run new batch import.
      $batch =& batch_get();
      $batch = array();
      $batch_definition = array(
        'operations' => $operations,
        'title' => t('Processing plugins settings'),
        'file' => drupal_get_path('module', 'crm_core_data_import') . '/crm_core_data_import.admin.inc',
        'init_message' => t('Starting process'),
        'progress_message' => '',
        'error_message' => t('An error occurred. Some or all of the import processing has failed.'),
        'finished' => 'crm_core_data_run_settings_plugins_finish',
      );
      batch_set($batch_definition);
      batch_process('admin/structure/crm-core/data-import');
    }
  }
}

/**
 * Batch operation which trigger plugins for each imported entity.
 *
 * @param array $source_keys
 */
function crm_core_data_run_settings_plugins_for_entity($machine_name, $source_keys, $importer, $data, &$context) {
  $importer_settings = $importer
    ->getSettings();
  if (!empty($importer_settings['settings_controllers'])) {
    foreach ($importer_settings['settings_controllers'] as $controller) {
      $settings_controller = crm_core_data_import_load_plugin_instance('crm_core_data_import_settings', $controller);
      $settings_controller
        ->postImport($importer, $data);
    }
  }
  $context['results'][$machine_name] = t('Processed entities from @instance_name migrate instance.', array(
    '@instance_name' => $machine_name,
  ));

  // While in progress, show the cumulative list of messages.
  $full_message = '';
  foreach ($context['results'] as $message) {
    $full_message .= $message . '<br />';
  }
  $context['message'] = $full_message;
}

/**
 * Batch API finished callback for plugins.
 */
function crm_core_data_run_settings_plugins_finish($success, $results, $operations) {
  drupal_set_message(t('Import successfully completed.'));
}

/**
 * Page callback for source selection page.
 */
function crm_core_data_import_source_selection($form, &$form_state, $importer_id = FALSE) {
  ctools_include('plugins');
  $plugins = ctools_get_plugins('crm_core_data_import', 'crm_core_data_import_source');
  $source_plugins = array();
  foreach ($plugins as $id => $plugin) {
    $source_plugins[$id] = $plugin['label'];
  }
  if ($importer_id) {
    $importer = crm_core_data_import_load_importer($importer_id);
  }
  else {
    $importer = new CRMCoreDataImport();
  }
  $form_state['importer'] = $importer;
  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => t('Data import name'),
    '#required' => TRUE,
    '#default_value' => $importer->title,
  );
  $form['machine_name'] = array(
    '#type' => 'machine_name',
    '#maxlength' => 32,
    '#machine_name' => array(
      'exists' => 'crm_core_data_importer_id_by_machine_name',
      'source' => array(
        'title',
      ),
    ),
    '#default_value' => empty($importer->machine_name) ? '' : $importer->machine_name,
    '#disabled' => empty($importer->machine_name) ? FALSE : TRUE,
  );
  $form['description'] = array(
    '#type' => 'textarea',
    '#title' => t('Description'),
    '#default_value' => $importer->description,
  );
  $form['source_plugin'] = array(
    '#type' => 'radios',
    '#title' => t('Where is your data coming from? Please select a source from the list below.'),
    '#required' => TRUE,
    '#options' => $source_plugins,
    '#default_value' => $importer->source ? $importer->source : key($source_plugins),
  );
  $form['next'] = array(
    '#type' => 'submit',
    '#value' => t('Next'),
  );
  $form['#attached']['css'][] = _crm_core_data_import_css_path();
  crm_core_data_import_attach_pager($form, $importer, __FUNCTION__);
  return $form;
}

/**
 * Submit handler for source selection form.
 */
function crm_core_data_import_source_selection_submit(&$form, &$form_state) {
  $values = $form_state['values'];
  $importer = $form_state['importer'];
  $importer->title = $values['title'];
  $importer->machine_name = $values['machine_name'];
  $importer->description = $values['description'];
  $importer->source = $values['source_plugin'];
  $importer
    ->save();
  $form_state['redirect'] = 'admin/structure/crm-core/data-import/' . $importer->id . '/source-settings';
}

/**
 * Title callback for source settings page.
 */
function crm_core_data_import_source_settings_title_callback($importer_id) {
  $importer = crm_core_data_import_load_importer($importer_id);
  return $importer->title;
}

/**
 * Page callback for source settings page.
 */
function crm_core_data_import_source_settings($form, &$form_state, $importer_id) {
  $importer = crm_core_data_import_load_importer($importer_id);
  $form_state['importer'] = $importer;

  // Attach source config form.
  $importer->source_plugin
    ->configForm($form, $form_state, $importer
    ->getSourceSettings());
  $form['previous'] = array(
    '#type' => 'submit',
    '#value' => t('Previous'),
    '#id' => 'button-previous',
  );
  $form['next'] = array(
    '#type' => 'submit',
    '#value' => t('Next'),
    '#id' => 'button-next',
  );
  $form['#attached']['css'][] = _crm_core_data_import_css_path();
  crm_core_data_import_attach_pager($form, $importer, __FUNCTION__);
  return $form;
}

/**
 * Validation callback for source settings page.
 */
function crm_core_data_import_source_settings_validate(&$form, &$form_state) {
  $importer = $form_state['importer'];

  // Validate source settings.
  $importer->source_plugin
    ->configFormValidate($form, $form_state, $importer
    ->getSourceSettings());
}

/**
 * Submit callback for source settings page.
 */
function crm_core_data_import_source_settings_submit(&$form, &$form_state) {
  $importer = $form_state['importer'];

  // Submit source settings.
  $settings = $importer->source_plugin
    ->configFormSubmit($form, $form_state, $importer
    ->getSourceSettings(), $importer->id);

  // Set source settings.
  $importer
    ->setSourceSettings($settings);
  $importer
    ->save();
  if ($form_state['triggering_element']['#id'] == 'button-previous') {
    $form_state['redirect'] = 'admin/structure/crm-core/data-import/' . $importer->id . '/source-selection';
  }
  elseif ($form_state['triggering_element']['#id'] == 'button-next' && $importer->source_plugin->sourceMapping) {
    $form_state['redirect'] = 'admin/structure/crm-core/data-import/' . $importer->id . '/source-mapping';
  }
  elseif ($form_state['triggering_element']['#id'] == 'button-next') {
    $form_state['redirect'] = 'admin/structure/crm-core/data-import/' . $importer->id . '/field-mapping';
  }
}

/**
 * Mapping for source.
 */
function crm_core_data_import_source_mapping($form, &$form_state, $importer_id) {
  $importer = crm_core_data_import_load_importer($importer_id);
  $form_state['importer'] = $importer;
  if ($importer->source_plugin->sourceMapping) {
  }

  // Attach source config form.
  $importer->source_plugin
    ->sourceMappingForm($form, $form_state, $importer
    ->getSourceSettings());
  $form['previous'] = array(
    '#type' => 'submit',
    '#value' => t('Previous'),
    '#id' => 'button-previous',
  );
  $form['next'] = array(
    '#type' => 'submit',
    '#value' => t('Next'),
    '#id' => 'button-next',
  );
  $form['#attached']['css'][] = _crm_core_data_import_css_path();
  crm_core_data_import_attach_pager($form, $importer, __FUNCTION__);
  return $form;
}

/**
 * Validation callback for source mapping page.
 */
function crm_core_data_import_source_mapping_validate(&$form, &$form_state) {
  $importer = $form_state['importer'];

  // Validate source settings.
  $importer->source_plugin
    ->sourceMappingFormValidate($form, $form_state, $importer
    ->getSourceSettings());
}

/**
 * Submit callback for source settings page.
 */
function crm_core_data_import_source_mapping_submit(&$form, &$form_state) {
  $importer = $form_state['importer'];

  // Submit source settings.
  $settings = $importer->source_plugin
    ->sourceMappingFormSubmit($form, $form_state, $importer
    ->getSourceSettings(), $importer->id);

  // Set source settings.
  $importer
    ->setSourceSettings($settings);
  $importer
    ->save();
  if ($form_state['triggering_element']['#id'] == 'button-previous') {
    $form_state['redirect'] = 'admin/structure/crm-core/data-import/' . $importer->id . '/source-settings';
  }
  elseif ($form_state['triggering_element']['#id'] == 'button-next') {
    $form_state['redirect'] = 'admin/structure/crm-core/data-import/' . $importer->id . '/field-mapping';
  }
}

/**
 * Title callback for field mapping page.
 */
function crm_core_data_import_field_mapping_title_callback($importer_id) {
  $importer = crm_core_data_import_load_importer($importer_id);
  return t('Field mapping for @title', array(
    '@title' => $importer->title,
  ));
}

/**
 * Page callback for field mapping page.
 */
function crm_core_data_import_field_mapping($form, &$form_state, $importer_id) {
  $importer = crm_core_data_import_load_importer($importer_id);
  $form_state['importer'] = $importer;

  // Build form_state from data import settings.
  if (empty($form_state['values']['mapping']) && empty($form_state['triggering_element'])) {
    $mapping_settings = $importer
      ->getMappingSettings();
    foreach ($mapping_settings as $key => $mapping_instance) {
      list($entity_type, $entity_bundle, ) = explode(':', $key);
      $form_state['values']['mapping'][$key]['fields'] = $mapping_instance;
      $entity_key = $entity_type . ':' . $entity_bundle;
      if (empty($form_state['values']['mapping'][$entity_key . '_delta'])) {
        $form_state['values']['mapping'][$entity_key . '_delta'] = 1;
      }
      else {
        $form_state['values']['mapping'][$entity_key . '_delta']++;
      }
    }
  }
  $form['#tree'] = TRUE;

  // Get available source fields.
  $source_fields = $importer
    ->getSourceFields();
  _crm_core_data_import_attach_entity_form($form, $form_state);
  $form['mapping'] = array(
    '#type' => 'container',
    '#prefix' => '<div id="mapping-fieldset-wrapper">',
    '#suffix' => '</div>',
  );
  _crm_core_data_import_attach_fields_form($form, $form_state, $source_fields);
  $form['previous'] = array(
    '#type' => 'submit',
    '#value' => t('Previous'),
    '#id' => 'button-previous',
  );
  $form['next'] = array(
    '#type' => 'submit',
    '#value' => t('Next'),
    '#id' => 'button-next',
  );
  $form['#attached']['css'][] = _crm_core_data_import_css_path();
  crm_core_data_import_attach_pager($form, $importer, __FUNCTION__);
  return $form;
}

/**
 * Submit callback for field mapping page.
 */
function crm_core_data_import_field_mapping_submit(&$form, &$form_state) {

  /** @var CRMCoreDataImport $importer */
  $importer = $form_state['importer'];
  $mapping = array();

  // Build data import settings from form_state.
  if (!empty($form_state['values']['mapping'])) {
    $mapping_values = $form_state['values']['mapping'];
    foreach ($mapping_values as $key => $mapping_instance) {
      if (is_array($mapping_instance)) {
        foreach ($mapping_instance['fields'] as $field_key => $field_value) {
          if (!empty($field_value['remove_field'])) {
            unset($mapping_instance['fields'][$field_key]['remove_field']);
          }
        }
        $mapping[$key] = $mapping_instance['fields'];
      }
    }
    $importer
      ->setMappingSettings($mapping);
  }
  else {
    $importer
      ->setMappingSettings(array());
  }

  // Remove unnecessary entities from settings before save.
  $settings = $importer
    ->getSettings();
  foreach ($settings as $settings_key => $item) {
    if (!empty($item['fields'])) {
      foreach ($item['fields'] as $settings_field_key => $settings_field) {
        $source_conrtoller_key = _crm_core_data_import_controller_key_by_entity_key($settings_field['source']);
        $destination_conrtoller_key = _crm_core_data_import_controller_key_by_entity_key($settings_field['destination']);
        if (!array_key_exists($source_conrtoller_key, $mapping) || !array_key_exists($destination_conrtoller_key, $mapping)) {
          unset($settings[$settings_key]['fields'][$settings_field_key]);
        }
      }
    }
  }
  $importer
    ->setSettings($settings);
  $importer
    ->save();
  if ($form_state['triggering_element']['#id'] == 'button-previous' && $importer->source_plugin->sourceMapping) {
    $form_state['redirect'] = 'admin/structure/crm-core/data-import/' . $importer->id . '/source-mapping';
  }
  elseif ($form_state['triggering_element']['#id'] == 'button-previous') {
    $form_state['redirect'] = 'admin/structure/crm-core/data-import/' . $importer->id . '/source-settings';
  }
  elseif ($form_state['triggering_element']['#id'] == 'button-next') {
    $form_state['redirect'] = 'admin/structure/crm-core/data-import/' . $importer->id . '/settings';
  }
}

/**
 * Entity types and bundles.
 */
function _crm_core_data_import_attach_entity_form(&$form, &$form_state) {
  ctools_include('plugins');
  $plugins = ctools_get_plugins('crm_core_data_import', 'crm_core_data_import_destination');
  $entity_plugins = array();
  $entity_bundles = array();
  foreach ($plugins as $id => $plugin) {
    $entity_plugins[$id] = $plugin['label'];
  }
  $form['entity_form'] = array(
    '#type' => 'container',
    '#prefix' => '<div id="entity-form-fieldset-wrapper">',
    '#suffix' => '</div>',
  );
  $form['entity_form']['entity_type'] = array(
    '#type' => 'select',
    '#title' => t('Add an:'),
    '#empty_option' => t('- Entity type -'),
    '#options' => $entity_plugins,
    '#ajax' => array(
      'callback' => '_crm_core_data_import_entity_form_entity_type_callback',
      'wrapper' => 'entity-form-fieldset-wrapper',
    ),
  );
  if (!empty($form_state['values']['entity_form']['entity_type'])) {
    $destination = crm_core_data_import_load_plugin_instance('crm_core_data_import_destination', $form_state['values']['entity_form']['entity_type']);
    $entity_bundles = $destination
      ->getBundles();
  }
  $form['entity_form']['entity_bundle'] = array(
    '#type' => 'select',
    '#title' => t('of type:'),
    '#options' => $entity_bundles,
  );
  $form['entity_form']['add_entity'] = array(
    '#type' => 'button',
    '#id' => 'add-entity-button',
    '#value' => t('Add'),
    '#ajax' => array(
      'callback' => '_crm_core_data_import_entity_form_add_entity_callback',
      'method' => 'replace',
      'wrapper' => 'mapping-fieldset-wrapper',
    ),
  );
}

/**
 * Entity fields and bundles.
 */
function _crm_core_data_import_attach_fields_form(&$form, &$form_state, $source_fields) {
  $importer = $form_state['importer'];

  // Button which was triggered.
  $triggering_element = !empty($form_state['triggering_element']) ? $form_state['triggering_element'] : FALSE;

  // If button is remove bundle.
  if (!empty($triggering_element['#parents'][2]) && $triggering_element['#parents'][2] == 'remove_bundle') {
    $key = $triggering_element['#parents'][1];
    if (!empty($form_state['values']['mapping'][$key])) {
      unset($form_state['values']['mapping'][$key]);
    }
  }

  // If buttons are move up or move down.
  if (!empty($triggering_element['#parents'][2]) && ($triggering_element['#parents'][2] == 'move_down' || $triggering_element['#parents'][2] == 'move_up')) {
    $key = $triggering_element['#parents'][1];
    $search = FALSE;
    $swap_mapping = $form_state['values']['mapping'];

    // If move up, reverse array.
    if ($triggering_element['#parents'][2] == 'move_down') {
      $mapping = $form_state['values']['mapping'];
    }
    else {
      $mapping = array_reverse($form_state['values']['mapping']);
    }
    foreach ($mapping as $mapping_key => $mapping_item) {
      if ($mapping_key == $key) {
        $search = TRUE;
      }
      elseif ($search == TRUE && is_array($mapping_item)) {
        $search = FALSE;
        $swap_mapping = _crm_core_data_import_array_swap($swap_mapping, $key, $mapping_key);
      }
    }
    $form_state['values']['mapping'] = $swap_mapping;
  }

  // If button is remove field.
  if (!empty($triggering_element['#parents'][4]) && $triggering_element['#parents'][4] == 'remove_field') {
    $entity_bundle_key = $triggering_element['#parents'][1];
    $field_key = $triggering_element['#parents'][3];
    unset($form_state['values']['mapping'][$entity_bundle_key]['fields'][$field_key]);
  }

  // Build form from form_state.
  if (!empty($form_state['values']['mapping'])) {

    // Attach elements entity fields.
    foreach ($form_state['values']['mapping'] as $key => $mapping) {
      if (is_array($mapping)) {
        list($entity_type, $entity_bundle, $bundle_delta) = explode(':', $key);
        $destination = crm_core_data_import_load_plugin_instance('crm_core_data_import_destination', $entity_type);
        $fields = $destination
          ->getFields($entity_bundle);
        $html_id = drupal_html_id($key);

        // Add field with count of entities.
        $entity_key = $entity_type . ':' . $entity_bundle;
        $form['mapping'][$entity_key . '_delta'] = array(
          '#type' => 'value',
          '#value' => $form_state['values']['mapping'][$entity_key . '_delta'],
        );

        // If was triggered add-more-button, add new field.
        if (strpos($triggering_element['#id'], 'add-more') !== FALSE && $triggering_element['#parents'][1] == $key) {
          $form_state['values']['mapping'][$key]['fields'][] = array(
            'source_field' => '',
            'destination_field' => '',
          );
        }
        foreach ($form_state['values']['mapping'][$key]['fields'] as $delta => $field) {
          $source_fields_values = $source_fields;
          $importer->source_plugin
            ->mappingSourceFieldsAlter($source_fields_values, crm_core_data_import_get_destination_entity_type($entity_type), $entity_bundle, $importer);
          if ($delta === 'primary') {

            // Attach primary field.
            _crm_core_data_import_attach_elements_primary_fieldset($form, $form_state, $entity_type, $entity_bundle, $key, $html_id, $source_fields_values, $bundle_delta);
          }
          else {

            // Attach form elements for fields.
            _crm_core_data_import_attach_elements_field($form, $form_state, $key, $delta, $source_fields_values, $fields);
          }
        }

        // Attach add more button.
        _crm_core_data_import_attach_elements_add_more_button($form, $form_state, $key, $html_id);
      }
    }
  }

  // Add fieldset form new entity.
  if (!empty($form_state['values']['entity_form']['entity_type']) && !empty($form_state['values']['entity_form']['entity_bundle']) && $triggering_element['#id'] == 'add-entity-button') {
    $entity_type = $form_state['values']['entity_form']['entity_type'];
    $entity_bundle = $form_state['values']['entity_form']['entity_bundle'];
    $key = $entity_type . ':' . $entity_bundle;

    // Save count of entity bundle. Need to support multiple bundles.
    if (empty($form_state['values']['mapping'][$key . '_delta'])) {

      // If initial adding.
      $form_state['values']['mapping'][$key . '_delta'] = 1;
      $bundle_delta = 1;
    }
    else {

      // If bundle already exist.
      $form_state['values']['mapping'][$key . '_delta']++;
      $bundle_delta = $form_state['values']['mapping'][$key . '_delta'];
    }
    $form['mapping'][$key . '_delta'] = array(
      '#type' => 'value',
      '#value' => $bundle_delta,
    );
    $key .= ':' . $bundle_delta;
    $html_id = drupal_html_id($key);
    $source_fields_values = $source_fields;
    $importer->source_plugin
      ->mappingSourceFieldsAlter($source_fields_values, crm_core_data_import_get_destination_entity_type($entity_type), $entity_bundle, $importer);
    _crm_core_data_import_attach_elements_primary_fieldset($form, $form_state, $entity_type, $entity_bundle, $key, $html_id, $source_fields_values, $bundle_delta);
    _crm_core_data_import_attach_elements_add_more_button($form, $form_state, $key, $html_id);
  }
  $importer->source_plugin
    ->fieldMappingFormAlter($form, $form_state);
}

/**
 * Attach primary fieldset for entity bundle.
 *
 * @param array $form
 *   Main form.
 * @param array $form_state
 *   Main form state.
 * @param string $entity_type
 *   Entity type.
 * @param string $entity_bundle
 *   Entity bundle.
 * @param string $key
 *   Key of fieldset.
 * @param string $html_id
 *   HTML id for fieldset wrapper.
 * @param array $source_fields
 *   List of available fields from source.
 * @param string $bundle_delta
 *   Delta of bundle.
 */
function _crm_core_data_import_attach_elements_primary_fieldset(&$form, &$form_state, $entity_type, $entity_bundle, $key, $html_id, $source_fields, $bundle_delta) {
  if (empty($source_fields)) {
    $source_key = !empty($form_state['values']['mapping'][$key]['fields']['primary']['source_field_primary']) ? $form_state['values']['mapping'][$key]['fields']['primary']['source_field_primary'] : 0;
    $source_fields = array(
      $source_key => t('Unavailable'),
    );
  }
  $form['mapping'][$key] = array(
    '#type' => 'container',
    '#prefix' => '<div id="' . $html_id . '-wrapper">',
    '#suffix' => '</div>',
    '#attributes' => array(
      'class' => array(
        'entity-fieldset-wrapper',
      ),
    ),
  );
  $form['mapping'][$key]['text'] = array(
    '#markup' => '<h3>' . crm_core_data_import_get_destination_label($entity_type, $entity_bundle, $bundle_delta) . '</h3>',
  );
  $form['mapping'][$key]['move_up'] = array(
    '#type' => 'button',
    '#value' => t('Move Up'),
    '#name' => $html_id . '-move-up-button',
    '#ajax' => array(
      'callback' => '_crm_core_data_import_entity_type_action_callback',
      'method' => 'replace',
      'wrapper' => 'mapping-fieldset-wrapper',
    ),
  );
  $form['mapping'][$key]['move_down'] = array(
    '#type' => 'button',
    '#value' => t('Move Down'),
    '#name' => $html_id . '-move-down-button',
    '#ajax' => array(
      'callback' => '_crm_core_data_import_entity_type_action_callback',
      'method' => 'replace',
      'wrapper' => 'mapping-fieldset-wrapper',
    ),
  );
  $form['mapping'][$key]['remove_bundle'] = array(
    '#type' => 'button',
    '#value' => t('Remove'),
    '#name' => $html_id . '-remove-button',
    '#ajax' => array(
      'callback' => '_crm_core_data_import_entity_type_action_callback',
      'method' => 'replace',
      'wrapper' => 'mapping-fieldset-wrapper',
    ),
  );
  $form['mapping'][$key]['fields'] = array(
    '#type' => 'container',
  );
  $form['mapping'][$key]['fields']['primary'] = array(
    '#type' => 'container',
    '#attributes' => array(
      'class' => array(
        'field-fieldset-wrapper',
      ),
    ),
  );
  $form['mapping'][$key]['fields']['primary']['source_field_primary'] = array(
    '#type' => 'select',
    '#options' => $source_fields,
    '#default_value' => !empty($form_state['values']['mapping'][$key]['fields']['primary']['source_field_primary']) ? $form_state['values']['mapping'][$key]['fields']['primary']['source_field_primary'] : FALSE,
  );
  $form['mapping'][$key]['fields']['primary']['destination_field_primary'] = array(
    '#type' => 'select',
    '#options' => array(
      'primary_field' => t('Primary field'),
    ),
    '#default_value' => 'primary_field',
    '#disabled' => TRUE,
  );
}

/**
 * Attach add more button to entity bundle fieldset.
 *
 * @param array $form
 *   Main form.
 * @param array $form_state
 *   Main form state.
 * @param string $key
 *   Key of fieldset.
 * @param string $html_id
 *   HTML id for fieldset wrapper.
 */
function _crm_core_data_import_attach_elements_add_more_button(&$form, &$form_state, $key, $html_id) {
  $form['mapping'][$key]['add_more'] = array(
    '#type' => 'button',
    '#default_value' => t('Add Another Field'),
    '#name' => $html_id . '-button',
    '#ajax' => array(
      'callback' => '_crm_core_data_import_add_another_field_callback',
      'method' => 'replace',
      'wrapper' => $html_id . '-wrapper',
    ),
  );
}

/**
 * Attach mapping field to entity bundle fieldset.
 *
 * @param array $form
 *   Main form.
 * @param array $form_state
 *   Main form state.
 * @param string $key
 *   Key of fieldset.
 * @param int $delta
 *   Delta in the current fieldset.
 * @param array $source_fields
 *   List of available fields from source.
 * @param array $fields
 *   List of available fields from destination.
 */
function _crm_core_data_import_attach_elements_field(&$form, &$form_state, $key, $delta, $source_fields, $fields) {
  if (empty($source_fields)) {
    $source_key = !empty($form_state['values']['mapping'][$key]['fields'][$delta]['source_field']) ? $form_state['values']['mapping'][$key]['fields'][$delta]['source_field'] : 0;
    $source_fields = array(
      $source_key => t('Unavailable'),
    );
  }
  else {
    $source_fields = array(
      'default_value' => t('(provide value)'),
    ) + $source_fields;
  }
  $form['mapping'][$key]['fields'][$delta] = array(
    '#type' => 'container',
    '#attributes' => array(
      'class' => array(
        'field-fieldset-wrapper',
      ),
    ),
  );
  $form['mapping'][$key]['fields'][$delta]['source_field'] = array(
    '#type' => 'select',
    '#options' => $source_fields,
    '#default_value' => !empty($form_state['values']['mapping'][$key]['fields'][$delta]['source_field']) ? $form_state['values']['mapping'][$key]['fields'][$delta]['source_field'] : FALSE,
  );
  $form['mapping'][$key]['fields'][$delta]['destination_field'] = array(
    '#type' => 'select',
    '#options' => $fields,
    '#default_value' => !empty($form_state['values']['mapping'][$key]['fields'][$delta]['destination_field']) ? $form_state['values']['mapping'][$key]['fields'][$delta]['destination_field'] : FALSE,
  );
  $form['mapping'][$key]['fields'][$delta]['default_value'] = array(
    '#type' => 'textfield',
    '#default_value' => !empty($form_state['values']['mapping'][$key]['fields'][$delta]['default_value']) ? $form_state['values']['mapping'][$key]['fields'][$delta]['default_value'] : FALSE,
  );
  $form['mapping'][$key]['fields'][$delta]['remove_field'] = array(
    '#type' => 'button',
    '#default_value' => t('Remove'),
    '#name' => 'remove-field-button-' . drupal_html_id($key . $delta),
    '#ajax' => array(
      'callback' => '_crm_core_data_import_entity_type_action_callback',
      'method' => 'replace',
      'wrapper' => 'mapping-fieldset-wrapper',
    ),
  );
}

/**
 * Callback for entity type select.
 */
function _crm_core_data_import_entity_form_entity_type_callback($form, &$form_state) {
  return $form['entity_form'];
}

/**
 * Callback for entity fieldset submit.
 */
function _crm_core_data_import_entity_form_add_entity_callback($form, &$form_state) {
  _crm_core_data_import_theme_mapping_form($form);
  return $form['mapping'];
}

/**
 * Callback for add another field button.
 */
function _crm_core_data_import_add_another_field_callback($form, &$form_state) {
  _crm_core_data_import_theme_mapping_form($form);
  $elemets = $form_state['triggering_element']['#parents'][1];
  return $form['mapping'][$elemets];
}

/**
 * Callback for actions for entity bundle.
 */
function _crm_core_data_import_entity_type_action_callback($form, &$form_state) {
  _crm_core_data_import_theme_mapping_form($form);
  return $form['mapping'];
}

/**
 * Page callback for settings page.
 */
function crm_core_data_import_settings_page($form, &$form_state, $importer_id) {
  $importer = crm_core_data_import_load_importer($importer_id);
  $form_state['importer'] = $importer;
  $form['#tree'] = TRUE;
  $form['form_header'] = array(
    '#markup' => '<p>' . t('Use the settings on this screen to refine the data being imported into the system.') . '</p>',
    '#weight' => -50,
  );
  $plugins = ctools_get_plugins('crm_core_data_import', 'crm_core_data_import_settings');
  foreach ($plugins as $plugin) {
    $data_import_settings = crm_core_data_import_load_plugin_instance('crm_core_data_import_settings', $plugin['name']);
    if ($data_import_settings
      ->displayConditions($importer)) {
      $data_import_settings
        ->configForm($form, $form_state, $importer, $plugin['label']);
    }
  }
  $form['previous'] = array(
    '#type' => 'submit',
    '#value' => t('Previous'),
    '#id' => 'button-previous',
  );
  $form['next'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
    '#id' => 'button-next',
  );
  $form['#attached']['css'][] = _crm_core_data_import_css_path();
  crm_core_data_import_attach_pager($form, $importer, __FUNCTION__);
  return $form;
}

/**
 * Validation callback for settings page.
 */
function crm_core_data_import_settings_page_validate(&$form, &$form_state) {
  $importer = $form_state['importer'];
  ctools_include('plugins');
  $plugins = ctools_get_plugins('crm_core_data_import', 'crm_core_data_import_settings');
  foreach ($plugins as $plugin) {
    $data_import_settings = crm_core_data_import_load_plugin_instance('crm_core_data_import_settings', $plugin['name']);
    $data_import_settings
      ->configFormValidate($form, $form_state, $importer);
  }
}

/**
 * Submit callback for settings page.
 */
function crm_core_data_import_settings_page_submit(&$form, &$form_state) {
  $importer = $form_state['importer'];
  ctools_include('plugins');
  $plugins = ctools_get_plugins('crm_core_data_import', 'crm_core_data_import_settings');
  foreach ($plugins as $plugin) {
    $data_import_settings = crm_core_data_import_load_plugin_instance('crm_core_data_import_settings', $plugin['name']);
    if ($data_import_settings
      ->displayConditions($importer)) {
      $settings = $data_import_settings
        ->configFormSubmit($form, $form_state, $importer);
      $current_settings = $importer
        ->getSettings();
      if (!empty($settings)) {
        $result_settings = array_merge($current_settings, $settings);
      }
      else {
        $result_settings = $current_settings;
      }
      $controller = get_class($data_import_settings);
      if (empty($result_settings['settings_controllers']) || !in_array($controller, $result_settings['settings_controllers'])) {
        $result_settings['settings_controllers'][] = $controller;
      }
      $importer
        ->setSettings($result_settings);
    }
  }
  $importer
    ->save();
  if ($form_state['triggering_element']['#id'] == 'button-previous') {
    $form_state['redirect'] = 'admin/structure/crm-core/data-import/' . $importer->id . '/field-mapping';
  }
  elseif ($form_state['triggering_element']['#id'] == 'button-next') {
    $form_state['redirect'] = 'admin/structure/crm-core/data-import';
  }
}

/**
 * Page to delete data import task.
 */
function crm_core_data_import_delete_page($form, &$form_state, $importer_id) {
  $importer = crm_core_data_import_load_importer($importer_id);
  $form_state['importer'] = $importer;
  return confirm_form($form, t('Are you sure you want to delete data import task %title?', array(
    '%title' => $importer->title,
  )), 'admin/structure/crm-core/data-import', t('This action cannot be undone.'), t('Delete'), t('Cancel'));
}

/**
 * Submit callback to delete data import task.
 */
function crm_core_data_import_delete_page_submit($form, &$form_state) {
  $importer = $form_state['importer'];

  // Remove all registered migrations.
  $registered_migrations = variable_get('crm_core_data_import_migrations_' . $importer->id, array());
  foreach ($registered_migrations as $machine_name) {
    $migration = Migration::getInstance($machine_name);
    if ($migration) {
      Migration::deregisterMigration($machine_name);
    }
  }
  variable_del('crm_core_data_import_migrations_' . $importer->id);
  db_delete('crm_core_data_import')
    ->condition('id', $importer->id)
    ->execute();
  $form_state['redirect'] = 'admin/structure/crm-core/data-import';
}

/**
 * Build operations for queue of import.
 */
function _crm_core_data_import_build_entity_operations(&$operations, $mapping, $importer_id, $options) {
  foreach ($mapping as $key => $mapping_item) {
    list($entity_controller_type, $entity_bundle, $bundle_delta) = explode(':', $key);
    $entity_type = crm_core_data_import_get_destination_entity_type($entity_controller_type);
    crm_core_data_import_register_migration($importer_id, $entity_type, $entity_bundle, $bundle_delta);
    $machine_name = _crm_core_data_import_migration_machine_name($importer_id, $entity_type, $entity_bundle, $bundle_delta);
    $operations[] = array(
      'crm_core_data_import_batch',
      array(
        'import',
        $machine_name,
        $options,
        0,
      ),
    );
  }
}

Functions

Namesort descending Description
crm_core_data_import_batch Batch API item callback.
crm_core_data_import_dashboard_form Page callback for data import dashboard.
crm_core_data_import_dashboard_form_submit Submit handler for data import dashboard.
crm_core_data_import_delete_page Page to delete data import task.
crm_core_data_import_delete_page_submit Submit callback to delete data import task.
crm_core_data_import_field_mapping Page callback for field mapping page.
crm_core_data_import_field_mapping_submit Submit callback for field mapping page.
crm_core_data_import_field_mapping_title_callback Title callback for field mapping page.
crm_core_data_import_migration_batch_finish Batch API finished callback. Trigger controllers for settings.
crm_core_data_import_settings_page Page callback for settings page.
crm_core_data_import_settings_page_submit Submit callback for settings page.
crm_core_data_import_settings_page_validate Validation callback for settings page.
crm_core_data_import_source_mapping Mapping for source.
crm_core_data_import_source_mapping_submit Submit callback for source settings page.
crm_core_data_import_source_mapping_validate Validation callback for source mapping page.
crm_core_data_import_source_selection Page callback for source selection page.
crm_core_data_import_source_selection_submit Submit handler for source selection form.
crm_core_data_import_source_settings Page callback for source settings page.
crm_core_data_import_source_settings_submit Submit callback for source settings page.
crm_core_data_import_source_settings_title_callback Title callback for source settings page.
crm_core_data_import_source_settings_validate Validation callback for source settings page.
crm_core_data_run_settings_plugins_finish Batch API finished callback for plugins.
crm_core_data_run_settings_plugins_for_entity Batch operation which trigger plugins for each imported entity.
crm_core_data_settings_batch Run batch for plugins.
_crm_core_data_import_add_another_field_callback Callback for add another field button.
_crm_core_data_import_attach_elements_add_more_button Attach add more button to entity bundle fieldset.
_crm_core_data_import_attach_elements_field Attach mapping field to entity bundle fieldset.
_crm_core_data_import_attach_elements_primary_fieldset Attach primary fieldset for entity bundle.
_crm_core_data_import_attach_entity_form Entity types and bundles.
_crm_core_data_import_attach_fields_form Entity fields and bundles.
_crm_core_data_import_build_entity_operations Build operations for queue of import.
_crm_core_data_import_entity_form_add_entity_callback Callback for entity fieldset submit.
_crm_core_data_import_entity_form_entity_type_callback Callback for entity type select.
_crm_core_data_import_entity_type_action_callback Callback for actions for entity bundle.