The Migration class is built on the fundamental assumption that there is a one-to-one correspondence between source rows coming in and destination objects going out.

If however your source data corresponds to more than one Drupal object or entity, there are several ways to deal with this depending on the complexity of the different destination objects.

Create dependent objects on the fly

If you have simple objects as dependencies of a more complex one, you can create these on the fly in your migrate class's prepareRow() or prepare() methods. This is particularly suitable if your dependent object's data is only one field in your source data.

The downside however is that these dependent objects are not cleaned up on rollback, and depending on how you make them, you may not be able to implement cleaning them up yourself (as once you've created the missing objects, you can't tell which ones were missing before).

A special case is taxonomy term reference fields, where the 'create_term' field option lets you create taxonomy terms for source data that doesn't match an existing term.

Even if your destination object requires more than one source field, it can be useful to take this approach. For example, here we create taxonomy terms on the fly by taking their term name from one source field and set a field value on them based on another source field:

// in prepareRow():
// Make a new term object to save.
$names = taxonomy_vocabulary_get_names();
$edit = array(
  'name' => trim($row->term),
  'description' => '',
  'parent' => array(0),
  // Note the vocab machine name must be converted to a vid.
  'vid' => $names[$vocabulary_machine_name]->vid,
);
$term = (object) $edit;
// Set the field value from the row data.
$term->field_myfield['und'][0]['value'] = $row->term_myfield;
taxonomy_term_save($term);

// Put the new tid into the row's pseudofield.
// This field needs to have been declared in the source's $fields parameter.
// Remember also to set this field's 'source_type' to 'tid'.
// The row now has the tid of a term that's just been created ready for the
// taxonomy term reference field handler to work with.
$row->term_tid = $term->tid;

Run multiple dependent migrations

For more complex cases, you can define more than one migration based on the same source data. The first migration creates the dependent objects, ready for the field(s) in the second migration to refer to. For example, you may want to create both users and Profile2 profile entities from the same CSV file.

There are two components that make this work.

Declare dependency

First, the second migration is declared as being dependent on the first.

// Declare migration 'MyMigration_Step1' a dependency in migration 'MyMigration_Step2' to have them run in the right order, if needed:
$this->dependencies = array('MyMigration_Step1');

Declare dependent field mapping

Second, the reference to the dependent object or entity needs to be obtained from the first migration's mapping, using that migration's map (this is the record of the relationship between Drupal IDs and your source's unique IDs). With users and profiles, this means that when the profile is created, its uid field is mapped from our source unique ID to the uid of the user created in the first migration.

This is declared by setting a sourceMigration on the field mapping, thus:

// Connecting the profile2 to the user.
// We map from our source ID field to the uid, by way of Migrate's internal map.
$this->addFieldMapping('uid', 'SOURCE_ID')
  ->sourceMigration('MyMigration_Step1')
  ->description(t('The assignment of profile2-items to the respective user'));

There is an example of this in action in the cookbook section of this documentation.

Comments

Laz5530’s picture

hi,
i want to migrate nodes with comments.

  • I have two MigrationClasses: TodosNodeMigration and TodosCommentMigration(see unter).
  • In drupal DB in "comment" table is a reference field to parent node(nid). And this nid must be the same during my NodeMigration and CommentMigration, because nodes will have a new nid in new db, so old referces will not work
  • so i set a dependency on the NodeMigration in the CommentMigration
  • than i map the nid from NodeMigration to nid (in destination table)

But when i run the two Migration, the CommentMigration will be skipped:
-Processed 3 (3 created, 0 updated, 0 failed, 0 ignored) in 1.6 sec (115/min) - done with 'TodosNode'
-Skipped TodosComment due to unfulfilled dependencies: TodosNode

I do not understand why. Plz help. And do i think that right with the nid?

class TodosNodeMigration extends BasicTodosMigration {
  public function __construct() {
    parent::__construct();
    $this->description = t('Old Todo-s');

  // Define Key(ID) in source table
    $this->map = new MigrateSQLMap($this->machineName,
      array(
        'nid' => array(
          'type' => 'int',
          'not null' => TRUE,
          'description' => 'Node ID.',
		  'alias' => 'n',
        )
      ),
      MigrateDestinationNode::getKeySchema()
    );
    ...
class TodosCommentMigration extends BasicTodosMigration {
  public function __construct() {
    parent::__construct();
    $this->description = t('Comments about Todo-s');
// I set the dependency hier !!
    $this->dependencies = array('TodosNode');
    $this->map = new MigrateSQLMap($this->machineName,
      array('cid' => array(
            'type' => 'int',
            'not null' => TRUE,
           )
         ),
      MigrateDestinationComment::getKeySchema()
   );
   ...
   $this->addFieldMapping('nid', 'nid')
		 ->sourceMigration('TodosNode');
   ...