Last updated July 22, 2013. Created by mikeryan on December 24, 2010.
Edited by ShaunDychko, joachim. Log in to edit this page.

Generally, all you need to do is define a Migration class with a hard-coded source and destination. In this case, there is a one-to-one correspondence between the class implementation, and a migration process (one row in drush migrate-status, one migration that can be run). However, sometimes you may want to be able to migrate more than one set of source data using one implementation - for example, when migrating multiple blogs of the same form into Drupal. In this case, you need to set your migration up as a dynamic migration - a single migration class that can be instantiated multiple times.

Your migration class itself will differ from normal migrations in the following ways:

  1. Its constructor will accept an array of arguments, which are the keys distinguishing each instance of the migration class.
  2. It overrides generateMachineName() to - surprise! - generate a distinct machine name based on the distinct arguments to the instance (the default implementation generates the machine name based only on the class name, which is why we can only have one instance per class).

So, let's look at the migrate_example_baseball module (bundled with the Drupal 7 version of Migrate), highlighting these distinctions:

<?php
class GameBaseball extends DynamicMigration {
  public function
__construct(array $arguments) {
   
$this->arguments = $arguments;
...
   
// Unlike normal Migration classes, the source of the data is not hard-coded - it comes
    // from the arguments
   
$this->source = new MigrateSourceCSV($arguments['source_file'], $this->csvcolumns(), array(), $this->fields());
...
 
/**
   * Construct the machine name from the source file name.
   */
 
protected function generateMachineName($class_name = NULL) {
    return
strtolower(pathinfo($this->arguments['source_file'], PATHINFO_FILENAME));
  }
...
?>

So, from this we will get multiple migration instances, each with a distinct machine name based its source file name. But, how do we generate those instances? migrate_example_baseball does it in hook_enable():

<?php
function migrate_example_baseball_enable() {
 
$path = dirname(__FILE__) . '/data';
  for (
$i=0; $i<=9; $i++) {
   
$file = 'GL200' . $i . '.TXT';
   
Migration::registerMigration('GameBaseball', strtolower(pathinfo($file, PATHINFO_FILENAME)), array('source_file' => $path . '/' . $file));
  }
}
?>

While normal migrations are automatically registered based on their class name, we need to explicitly register dynamic migrations using Migration::registerMigration(). The first argument is the class name to use, the second argument the machine name for the particular instance, and the third the array of arguments that will distinguish the behavior of this instance.

Note that in a typical development scenario, when the migrations which need to be instantiated are changing frequently, you might do the registration in hook_flush_caches() instead - change the code determining what the migrations to register, do a drush cc all, and you're good to go. For example:

/**
* Implements hook_flush_caches().
*/
function mymigration_flush_caches() {
  Migration::registerMigration('MymigrationMigration', 'Mymigration', $migration_arguments);
}

Note that calling registerMigration() on a previously-registered migration is perfectly safe - it will update the arguments if they've changed, but will have no other effect.

For a real-world example, see the WordPress Migrate module, which is built using dynamic migrations.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

In the baseball example, the source csv files are in /data, but this is not specified anywhere in migrate_example_baseball.migrate.inc.

In migrate_example_baseball.install, in the hook_enable() function, there is a Migration::registerMigration() that sets the location and list of file names.

The other Andrew Morton