Community Documentation

Migration classes

Last updated September 15, 2012. Created by mikeryan on December 24, 2010.
Edited by loopduplicate, radiobuzzer, Vacilando, derhasi. Log in to edit this page.

The Migrate module provides an abstract class named Migration - in most cases, you'll do nearly all your work in extending this class. The Migration class handles the details of performing the migration for you - iterating over source records, creating destination objects, and keeping track of the relationships between them. All you need to do is

  1. Define where the source data is coming from.
  2. Define the destination object type and "bundle" (where appropriate).
  3. Define mappings from source fields to destination fields.

In doing so, you will make use of other classes provided by Migrate - some you can use as-is, some you may have need to override.

Here is an example of a bare-bones (but fully-functional) migration (source data not included). Scroll down to get the detailed explanation of what every piece of code does:

<?php
class ExampleMigration extends Migration {
  public function
__construct() {
   
parent::__construct(MigrateGroup::getInstance('example'));
   
// The example uses a SQL database as source.
   
$query = db_select('example_pages', 'p')
             ->
fields('p', array('pgid', 'page_title', 'page_body'));
   
$this->source = new MigrateSourceSQL($query);
   
// We migrate into "page" nodes.
   
$this->destination = new MigrateDestinationNode('page');

   
// We instantiate the MigrateMap
   
$this->map = new MigrateSQLMap($this->machineName,
        array(
         
'pgid' => array('type' => 'int',
                         
'unsigned' => TRUE,
                         
'not null' => TRUE,
                         )
        ),
       
MigrateDestinationNode::getKeySchema()
      );

   
// Finally we add simple field mappings
   
$this->addFieldMapping('title', 'page_title');
   
$this->addFieldMapping('body', 'page_body');
  }
}
?>

This code can be place in the .module file. A common practice is also to create separate .inc files for different migrations or groups or migrations, so that your code in each file is not too big. All files (with a suffix of .inc or .module) that contain class declarations should be included in the .info file.

Once you have defined this migration class (and created the necessary .info and .module files, and enabled your module), you should be able to see your migration class with the command:

drush migrate-status

As you see, the name of the migration defined by the ExampleMigration is Example (as shown on the first column).
If you have a table in your Drupal database named example_pages, with pgid, page_title, and page_body fields in it,

drush migrate-import Example

will create a Drupal page node for each row in the example_pages table. Then, running

drush migrate-rollback Example

will undo the import, deleting the pages that were initially created. And you accomplished this with 20 lines of code! How did you manage it? Let's take it apart piece by piece:

Class declaration

First, the basic overhead of extending a class and overriding its constructor:

<?php
class ExampleMigration extends Migration {
  public function
__construct() {
   
parent::__construct(MigrateGroup::getInstance('example'));
?>

This says that the class we're declaring, ExampleMigration, will behave exactly like the Migration class except for any behavior we override. Then, we override the class constructor - this is the first method to be called when an instance of the class is instantiated. In almost all cases, you begin a method by calling the parent's implementation of that method - usually, you are adding behavior to the base class, so you want to make sure that the base class does its thing.

Note the parameter to the parent constructor. What we're doing here is saying that ExampleMigration will be part of a group named 'example' (if we had simply called parent::__construct(), it would be part of the 'default' group). We can then run only migrations from this group thusly:

drush migrate-import --group=example

This may be useful if you have many migrations which fall into logical groups - say, a group for importing from a MySQL database, and another group operating off XML feeds. Migration groups may depend on other groups being migrated first. From wine.inc: "The second argument to MigrateGroup::getInstance is an array of groups which should come before this when viewing migration statuses, or running migration operations using --all." See the wine example in migrate_example for more detail.

Define Source

Next, we identify where our source data is coming from:

<?php
    $query
= db_select('example_pages', 'p')
             ->
fields('p', array('pgid', 'page_title', 'page_body'));
   
$this->source = new MigrateSourceSQL($query);
?>

In this case, because our data is (conveniently!) in a table in our Drupal database, we can use the Drupal 7 Database API (on Drupal 6, this is provided by the DBTNG module) to define a query for the data. It is important that this query return one row containing all the data for what will become a single page - dealing with cases where the data might span multiple rows (e.g., if we also joined to a category table with multiple rows per page) is a little more advanced and is discussed here.

Once we've constructed the query, we use it to create a MigrateSourceSQL object and save it in our ExampleMigration object.

Define Destination

Next, we identify what we want to create from the source data:

<?php
    $this
->destination = new MigrateDestinationNode('page');
?>

That was even easier than the sources - we just told the migration module we want to create nodes of type page, or in Drupal 7 parlance: bundle.

Mapping Source and Destination

Next, we tell the migrate module how source and destination records are related.

<?php
    $this
->map = new MigrateSQLMap($this->machineName,
        array(
         
'pgid' => array('type' => 'int',
                         
'unsigned' => TRUE,
                         
'not null' => TRUE,
                         )
        ),
       
MigrateDestinationNode::getKeySchema()
      );
?>

To track migration status, and allow rollback, the migrate module needs to remember what source record resulted in the creation of which destination object. It does this using a MigrateSQLMap class - this class creates database tables which map source and destination keys. To do this, it needs to know what data types the respective keys are. Thus, we pass in schema arrays declaring the respective source and destination keys. For the source key, since the migrate module knows nothing about the source table, you need to explicitly define the schema array (making sure that the key of the array, pgid in this case, matches the field name used in the query passed to MigrateSourceSQL above). On the other hand, since we're using the canned class MigrateDestinationNode, it knows what the correct schema is already and can provide it through the static method getKeySchema().

Oh, and the machineName passed as the first argument? MigrateSQLMap will create a map table and message table for each migration, and will name them by prepending migrate_map_ and migrate_message_ to this parameter. It is a handy convention to pass your migration's machine name here, so that the names are unique and it's easy to identify what migration they're associated with, but you could pass a different suffix here if you prefer.

Note: If you got ambiguous columns for your sourceKey due to multiple joins in the source query, you can set alias in your sourceKey definition to the specific table alias.

<?php
    $this
->map = new MigrateSQLMap($this->machineName,
        array(
         
'pgid' => array('type' => 'int',
                         
'unsigned' => TRUE,
                         
'not null' => TRUE,
                         
'alias' => 'p', //use table alias for ambigous columns.
                        
)
        ),
       
MigrateDestinationNode::getKeySchema()
      );
?>

Field mapping

Finally, we define data mappings:

<?php
    $this
->addFieldMapping('title', 'page_title');
   
$this->addFieldMapping('body', 'page_body');
  }
}
?>

This tells the migration that, for each source row processed, to take the page node title from the source row's page_title field, and the node body from the page_body field. When looking at an addFieldMapping() call, remember that the destination field is the first parameter and the source field is the second parameter. Think of it like an assignment statement:

<?php
    $title
= $page_title;
?>

Comments

CSV Migration Example

Any one know where I can find sample code to import from a CSV file?

If you are still looking for

If you are still looking for an example CSV migrate profile I'm almost done working the kinks out of one myself I will be sharing. Process not as migrate newbie friendly as I'd hoped so will be sharing my experience and code.

Gene Bernier
gene@cheekymonkeymedia.ca
COO, Top Monkey Wrencher
Cheeky Monkey Media
http://cheekymonkeymedia.ca

Migrate CSV

I am very interested on your CSV Class, would post it please so I may get an idea where to start?
thanks
patrick

migrate module

Dear Sir

I'm trying to use this module to import a big inventory into my ubercart store./nodes.

can you help me . I see many detailed explanation but i'm getting lost . I've created a tab example with my inventory , now what's the next step?

not clear what DRUSH does.
I have no clear how to create

MAPPING OF SOURCE : created a tab called "migrate_example_inventory"
MAPPING OF DESTINATION ??
matching Source wityh Destination nodes: I guess this is what the module Import shall do.

Cannot get the list of the Source "inventory" listed into the Migrate Status to be selected.

thanks

Now go read their example, beer.inc

These docs are excellent, but now you should follow their advice and go read their example, beer.inc.
It's heavily commented, and includes tips like converting a date/time string into a UNIX timestamp that Drupal understands. Print it out and take notes. :)

Here's the git version of 6.x-2.0:
http://drupalcode.org/project/migrate.git/blob/836109b2c3098109d6ed8ff77...

beer.inc

So true ^^ Really helpful doc. Thanks!

- @geografa

CSV import example

Here is an example import from a CSV file:

<?php
class ImportExampleCSVMigration extends Migration {
      public function
__construct() {
       
parent::__construct();
       
       
//The defintion of the collumns. Keys are integers. values are array(field name, description).
       
$columns[0] = array('id_csv', 'Id');
       
$columns[1] = array('title_csv', 'Title');
       
$columns[2] = array('body_csv', 'Body');
       
$columns[3] = array('another_field_csv', 'Just another field');
   
       
//The Description of the import. This desription is shown on the Migrate GUI
       
$this->description = t('A CSV sample import ');

       
//The Source of the import
       
$this->source = new MigrateSourceCSV(drupal_get_path('module', 'module_name').'/import_file_name.csv', $columns);

       
//The destination CCK (boundle)
       
$this->destination = new MigrateDestinationNode('cck_maschine_name');

       
//Source and destination relation for rollbacks
       
$this->map = new MigrateSQLMap(
           
$this->machineName,
            array(
               
'id_csv' => array(
                   
'type' => 'int',
                   
'unsigned' => TRUE,
                   
'not null' => TRUE,
                   
'alias' => 'import'
               
)
            ),
           
MigrateDestinationNode::getKeySchema()
        );

       
//Field ampping
       
$this->addFieldMapping('title', 'title_csv');
       
$this->addFieldMapping('body', 'body_csv');
       
$this->addFieldMapping('another_field', 'another_field_csv');
    }
}
?>

It took me a while to find

It took me a while to find out that: #982694: Uppercase letters in column names not supported.
This caused strange error when used in the MigrateSQLMap source key schema definition.

Node type uses underscores

When defining your destination node type, hyphens should be replaced with underscores e.g.

$this->destination = new MigrateDestinationNode('my_custom_content_type');

where to put this code?

hi
I am new to migrate module. i have seen the implementation of migrate module in beer and wine examples. however i couldn't understand the complete examples. In beer and wine examples, there are two files namely "beer.inc" and "beer.install.inc". now having read the migrate_example.install file, the part of code responsible for making the beer and wine visible in the user interface is written in the "beer.install.inc" and "wine.install.inc". In those examples the data import and mapping is done in the"beer.inc" file and the content and node generation code alongwith schema definition is written in "beer.install.inc". Please guide me as to , how do i use the code provided above.
Thanx in advance.

Rishi

Rishi

Pls reply

I would like to get some help regarding my post above. Anyone who has knowledge about this , please share it.
Thanx

Rishi

Try the issue queue

Larger/general support requests are better suited for the Migrate module's issue queue. Posting there gets the attention of the module maintainer and others watching it, while posting here does not.

Page status

No known problems

Log in to edit this page

About this page

Drupal version
Drupal 6.x, Drupal 7.x
Audience
Programmers

Administration & Security Guide

Drupal’s online documentation is © 2000-2013 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License. Comments on documentation pages are used to improve content and then deleted.
nobody click here