I am using the migrate module to import full names that are in a single field in a CSV source file. The migration destination is a Profile2 field bundle that has a Name Field. Can you tell me how to migrate the full name text csv column, e.g. "Mr. John A. Smith, Jr." into the Name Field?

In the past I have used something like:

$this->addFieldMapping('profile2_name','first_name')
->arguments(array(
'family' => array('source_field' => 'last_name'),
));

which worked when the CSV file had separate first and last name fields.

CommentFileSizeAuthor
#2 name-1734922-2-migrate-support.patch2.01 KBAlan D.
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Alan D.’s picture

If this is a one off, could you simple concat the name columns into one and do a one to one mapping?

Alan D.’s picture

Title: Migrate support/full name separated / split into the individual name parts / fields » Name Field Migrate support with import example (single full name text field separated and split into the individual components)
Version: 7.x-1.5 » 7.x-1.x-dev
Status: Active » Needs review
FileSize
2.01 KB

Right, I just had to do this myself from a single profile D6 field to a D7 user name field. This is the first time that I have used Migrate, so this may be wrong...

This is a best guess data mining from a single text field. If the fields were already separated, then this would be much easier.

In a nutshell, htmigrateUserMigration::prepareRow() simple tries to create an array of name components. All enabled components would be:

$current_row->source_name_field = array(
  0 => array(
    'title' => 'Mr',
    'given' => 'John',
    'middle' => NULL,
    'family' => 'Doe',
    'generational' => NULL,
    'credentials' => 'OAM',
  ),
);

This was our migration class.

class htmigrateUserMigration extends Migration {
  public function __construct() {
    parent::__construct();
    ...
    // Profile fields to User fields
    $this->addFieldMapping('field_name', 'profile_name');
  }

  public function prepareRow($current_row) {
    ...
    // Map the profile data.
    $profile = htmigrate_user_profile_data($current_row->uid);

    // If the profile field is empty, populate with the user name.
    if (empty($profile['profile_name'])) {
      $profile['profile_name'] = $current_row->name;
    }
    
    // Data mining from "xxx xxx xxx xxx" type strings into title, first & last names
    $parts = explode(' ', $profile['profile_name']);

    // Using just first name is more common than just last name in the data set.
    if (count($parts) == 1) {
      $current_row->profile_name[0]['given'] = $profile['profile_name'];
    }
    else {
      // Test to see if the user has a known title prefixed.
      $title_options = array(
        t('Mr.') => t('Mr'),
        t('Mrs.') => t('Mrs'),
        t('Miss') => t('Miss'),
        t('Ms.') => t('Ms'),
        t('Dr.') => t('Dr'),
        t('Prof.') => t('Prof'),
        t('Mr') => t('Mr'),
        t('Mrs') => t('Mrs'),
        t('Ms') => t('Ms'),
        t('Dr') => t('Dr'),
        t('Prof') => t('Prof'),
      );
      if (array_key_exists($parts[0], $title_options)) {
        $current_row->profile_name[0]['title'] = array_shift($parts);
      }
      if (count($parts) > 1) {
        // We are not using credentials, so append these (if known) to the surname.
        // 'AC', 'AO', 'AM', 'OAM' are Australian honours system,
        // http://www.itsanhonour.gov.au/honours/awards/medals/order_of_australia.cfm
        $surname = array();
        do {
          $last = array_pop($parts);
          $surname[] = $last;
        }
        while (in_array($last, array('AC', 'AO', 'AM', 'OAM')));
        // We are not using middle names nor generational suffixes.
        $current_row->profile_name[0]['given'] = implode(' ', $parts);
        $current_row->profile_name[0]['family'] = implode(' ', $surname);
      }
      else {
        // There were two components until title removed, so "TITLE XXX" suggest title and surname.
        $current_row->profile_name[0]['family'] = array_shift($parts);
      }
    }
  }
}

/**
 * Helper function to retrieve profile data.
 */
function htmigrate_user_profile_data($uid) {
  $data = array();
  $query = db_select(variable_get('htmigrate_database', '') . '.profile_fields', 'f')
      ->fields('f', array('name', 'type'));
  $query->join(variable_get('htmigrate_database', '') . '.profile_values', 'v', 'f.fid = v.fid');
  $query->condition('v.uid', $uid)
      ->fields('v', array('uid', 'value'));
  $result = $query->execute();
  foreach ($result as $record) {
    if (empty($data[$record->name])) {
      $data[$record->name] = $record->value;
    }
  }
  return $data;
}

Out of the box, the Name field module has no support for the Migrate module, so I had to write this MigrateFieldHandler class to get it to work (see patch).

Alan D.’s picture

Status: Needs review » Fixed

Pushed to dev. Reopen if you find any issues.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

Jelle_S’s picture

Status: Closed (fixed) » Active

This kind of clashes with #1463476: Migrate integration and #1468010: Name field support where a migrate field handler was added to Migrate Extras, where Migrate Extras seems to be doing a 'better' job (Following the Migrate standards) at it. Maybe this patch should be reverted again, and mention on the project page that if you want to use Migrate with this module, Migrate Extras should be used?

Dane Powell’s picture

Issue summary: View changes
Status: Active » Closed (fixed)

Instead of re-opening old issues, let's continue the discussion at #2221717: Improve and de-dupe migrate handler