Drupal 8 Migrations - Tips and Tricks

Zach Weishar // March 2018

The migration system is now a stable part of Drupal 8 core - hip hip hooray! A lot of hard work from many community members went into this effort, so thank you to them for their hard work and dedication. They are making the lives of Drupal developers everywhere a lot easier.

In this post, I’ll let you in on a few process oriented tricks to make writing your next migration a little smoother. This is not an introduction to writing migrations, if you’re looking for that sort of thing here are some recommended resources:

Configuration Update Manager

This should be one of the first modules that you install before you start writing your migration (after Migrate Tools and Migrate Plus of course). You want this module because the migrate API relies heavily on configuration files. In fact, you’re likely going to be doing the vast majority of your work in files that end with .yml (aka configuration files). These configuration files are imported when your migrate module is first installed. After installation, any subsequent changes to these files will take no effect. So, you can either uninstall and reinstall your module every time you want to test a configuration update, which is slow and tedious, or you can use the drush commands provided by the Configuration Update Manager module.

Let’s say you’re working on a file named migrate_plus.migration.nodes.yml. If you make an update to that file and want to test its effect, you can run drush config-revert migrate_plus.migration.nodes to import the current state of migrate_plus.migration.nodes.yml into the database. Once that’s done you can re-run your migration to test the update.

Programmatically Trigger Migration

You might want to tigger a migration in code for many reasons. For instance if you want to run a recurring migration using hook_cron, you might do so like this:

use Drupal\migrate\MigrateExecutable;
use Drupal\migrate\MigrateMessage;

/**
 * Implements hook_cron().
 */
function example_module_cron() {
  $migration_id = 'your_migration_id';
  $migration = \Drupal::service('plugin.manager.migration')->createInstance($migration_id);
  $executable = new MigrateExecutable($migration, new MigrateMessage());
  $executable->import();
}

Xdebug

Xdebug is a must have for writing a migration. It will be extremely difficult to track down issues with your migration unless you have the ability to set breakpoints and inspect values midway through the migration process. This is especially true now that the Migrate API has moved so heavily towards a configuration based workflow. You can’t set breakpoints in configuration files, but you can set them in the underlying plugins that you call via those configuration files.

If you’re like me, and usually only configure Xdebug to listen to web server requests (as opposed to cli requests), you can save some time by programmatically running your migration based on an event you trigger through the browser. You might do that using hook_preprocess_page() like this:


use Drupal\migrate\MigrateExecutable;
use Drupal\migrate\MigrateMessage;

/**
 * Implements hook_preprocess_page().
 */
function example_module_preprocess_page(&$vars) {
  if ($qs = \Drupal::requestStack()->getCurrentRequest()->getQueryString()) {
   if (strpos($qs, 'start-migration') !== FALSE) {
      $migration_id = 'your_migration_id';
      $migration = \Drupal::service('plugin.manager.migration')->createInstance($migration_id);
      $executable = new MigrateExecutable($migration, new MigrateMessage());
      $executable->import();
    }
  }
}

Now you can trigger your migration like this: https://example.com?start-migration. The hook I chose here is arbitrary; you can use any trigger that you like. The point is that you can trigger a migration through the browser.

If you’re going to be spending a lot of time writing your migration, it’s likely better to configure Xdebug to work with php cli so that you can set breakpoints in Drush triggered migrations, but this will work in a pinch.