Migrate/Migrated2d: Linking Migrated Nodes To Non-migrated Terms
Migrate and Migrate d2d modules expose a powerful API to developers who have the task to migrate a part or an entire website to Drupal 7; these two modules come in handy whenever the migration task is subject to complex business rules. One short article is far from being enough to offer an in-depth look at the countless opportunities offered by these two modules. Therefore, this article will explain how to solve a specific migration issue, hoping in the process, to help grasp what can be done with these two modules.
For more information regarding the migrate/migrated2d API, click here.
The title of the article is self-explanatory, so here is a description of the design approach before diving in.
- Identifying unmigrated terms that are mapped to the node.
- Unlinking the node and the terms before the node migration.
- Saving the IDs of the terms in a static variable.
- Relinking the node and the terms right after persisting the node.
Also, I need to mention that prepareRow() and complete() belong to the migration base classes; prepareRow() is called very early in the process before importing each node and complete() is called right after persisting each node.
To start, create a method to unlink terms from node and then call it in prepareRow() right after saving terms per vocabulary in separate arrays. Since this process will be repeated for each nodes, creating a getter/setter for taxonomy related processes will prove helpful.
Term IDs Getter/Setter
public function tids_getter_setter ($voc = null ,$term_to_add = null, $resetting = false, $returning = false, $assigning = false) {
static $term_ids = array();
if (!empty($assigning)) {
$term_ids[$voc][] = $term_to_add;
} elseif ($resetting) {
$term_ids[$voc] = null;
} elseif ($returning) {
return $term_ids[$voc];
}
}
Function unlinking terms and node
public function rm_unmigrated_terms($ids_to_check, $migrate_map_table, $row, $vocab_var_name, $migration_class, $field_vocab) {
if (!empty($ids_to_check)) {
$query = db_select($migrate_map_table, 'commkeys')
->condition('commkeys.sourceid1', $ids_to_check, 'IN')
->isNull('destid1')
->fields('commkeys', array('sourceid1', 'destid1'));
$result = $query->execute()->fetchAll();
}
if (!empty($result)) {
foreach ($result as $term_tids) {
if (empty($term_tids->destid1)) {
// trick to get the key of the tid to remove from $row
if (($key = array_search($term_tids->sourceid1, $ids_to_check)) !== false) {
// save the source tid in a static variable then remove it from $row. the tid from static variable will be used in complete()
$migration_class->tids_getter_setter($vocab_var_name, $ids_to_check[$key], false, false, true);
unset($row->{$field_vocab}[$key]);
}
}
}
}
return $row;
}
The above function is called below, in prepareRow()
public function prepareRow($row) {
if (parent::prepareRow($row) === FALSE) {
return FALSE;
}
$keywords_ids_to_check = $row->field_keywords;
$topics_ids_to_check = $row->field_topicterms;
$migration_class = $this;
// remove unmigrated tags from $row
$row = $this->rm_unmigrated_terms($tags_ids_to_check, 'migrate_map_twtags', $row, 'migrate_tags_tids', $migration_class, 'field_tags');
// remove unmigrated keywords from $row
$row = $this->rm_unmigrated_terms($keywords_ids_to_check, 'migrate_map_twkeywords', $row, 'migrate_keywords_tids', $migration_class, 'field_keywords');
}
Function relinking terms and node
public function linking_stories_to_unmigrated_terms($terms_ids, $vocab_id, $vocab_var_name, $migration_class, $node) {
//getting names of terms to map
if (!empty($terms_ids)) {
$query = db_select('d7_techwell.taxonomy_term_data', 'twttd')
->condition('twttd.tid', $terms_ids)
->fields('twttd', array('name'))
->execute()
->fetchAll();
// reset static variable to avoid that the value for current story migration be used during next node migration
$migration_class->tids_getter_setter($vocab_var_name, 0, true, false, false);
if (!empty($query)) {
foreach ($query as $term_name) {
$query2 = db_select('d7_sqe_communities.taxonomy_term_data', 'comttd')
->condition('comttd.vid', $vocab_id)
->condition('comttd.name', $term_name->name)
->distinct()
->fields('comttd', array('tid'))
->execute()->fetchAll();
// adding mapping between nodes and terms
$query3 = db_insert('d7_sqe_communities.taxonomy_index')
->fields(array(
'nid' => $node->nid,
'tid' => $query2[0]->tid,
'sticky' => 0,
'created' => REQUEST_TIME
)
)
->execute();
}
}
}
}
Finally, in complete(), gathering the information needed to relink node and terms then calling the above function to do it
function complete($node, stdClass $row) {
$migration_class = $this;
// linking node to unmigrated topic terms in target
$topics_to_link = $migration_class->tids_getter_setter('migrate_topics_tids', 0, false, true, false);
$tags_to_link = $migration_class->tids_getter_setter('migrate_tags_tids', 0, false, true, false);
$keywords_to_link = $migration_class->tids_getter_setter('migrate_keywords_tids', 0, false, true, false);
if (!empty($topics_to_link)) {
$this->linking_stories_to_unmigrated_terms($topics_to_link, '2', 'migrate_topics_tids', $migration_class, $node);
}
// linking node to unmigrated keywords terms in target
if (!empty($tags_to_link)) {
$this->linking_stories_to_unmigrated_terms($tags_to_link, '11', 'migrate_keywords_tids', $migration_class, $node);
}
// linking node to unmigrated tags terms in target
if (!empty($keywords_to_link)) {
$this->linking_stories_to_unmigrated_terms($keywords_to_link, '17', 'migrate_tags_tids', $migration_class, $node);
}
}