6. Stand alone migrations - nuvoleweb/integration GitHub Wiki

The Integration Consumer module is built leveraging the popular Migrate module. Still all Migrate-related components are part of an independent Integration Migrate module, on which the Integration Consumer module depends upon.

In order to user stand-alone migration components we need to enable the Integration Migrate module:

$ drush en integration_migrate
The following extensions will be enabled: integration_migrate, registry_autoload, migrate
Do you really want to continue? (y/n): y

The Integration Migrate module provides two classes that can be used to migrate a set of data exchange documents without relying on any specific module configuration:

AbstractMigration class

The Drupal\integration_migrate\AbstractMigration class extends Migrate's Migration class and must be extended by all custom migration classes that wish to import a set of data exchange documents:

use Drupal\integration_migrate\AbstractMigration;

/**
 * Custom article migration class.
 */
class ArticleMigration extends AbstractMigration {
	...
}

MigrateItemJSON class

The Drupal\integration_migrate\MigrateItemJSON class extends Migrate's MigrateItemJSON class and must be used as Migrate item class when setting migration source in all custom migration classes that wish to import a set of data exchange documents:

use Drupal\integration_migrate\MigrateItemJSON;
use Drupal\integration_migrate\AbstractMigration;

/**
 * Custom article migration class.
 */
class ArticleMigration extends AbstractMigration {

  /**
   * Constructor.
   */
  public function __construct($arguments) {
    parent::__construct($arguments);

    ...

    $list_class = new \MigrateListJSON('/path/to/documents/list.json');
    $item_class = new MigrateItemJSON('/path/to/documents/:id.json');    
    $this->setSource(new MigrateSourceList($list_class, $item_class));
  }

}

This will ensure support for multilingual content and standard JSON data exchange format.

A stand alone migration example

Let's walk through a step-by-step guide to build a stand alone migration using the classes introduced above.

Say we have our data stored in our local file-system with the following structure:

$ tree /path/to/documents
/path/to/documents/
└── articles
    ├── document-1.json
    ├── document-2.json
    ├── document-3.json
    └── list.json

Each of the document-*.json contains a separate document having the same numeric id as specified in the file name, so document-1.json would look like:

{
  "_id": "1",
  "type": "news",
  "default_language": "en",
  "languages": ["fr", "en"],
  "fields": {
    "title": {
      "en": ["English title"],
      "fr": ["French title"]
    },
    "abstract": {
      "en": ["English abstract"],
      "fr": ["French abstract"]
    }
  }
}

While list.json just contains an array of document IDs in JSON format, so it will look like:

[
  "1",
  "2",
  "3"
]

Given the setup above say we want to import the JSON documents as Drupal articles using the default "article" content type.

Step 1: Create custom migration class

Our custom class lives in ``custom_module/articles_migration.inc``` and it would look like the following:

use Drupal\integration_migrate\MigrateItemJSON;
use Drupal\integration_migrate\AbstractMigration;

/**
 * Custom article migration class.
 */
class ArticleMigration extends AbstractMigration {

  /**
   * Constructor.
   */
  public function __construct($arguments) {
    parent::__construct($arguments);

    // Set source id and destination entity type.
    $this->setMap(new MigrateSQLMap(
      $this->getMachineName(),
      [
      '_id' => [
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
      ],
      MigrateDestinationNode::getKeySchema()
    ));

    // Import data as "article" content type.
    $this->setDestination(new MigrateDestinationNode('article'));

    // Entity translation requires that both title fields are mapped.
    $this->addFieldMapping('title', 'title');
    $this->addFieldMapping('title_field', 'title');
    $this->addFieldMapping('body', 'abstract');

    $list_class = new \MigrateListJSON('/path/to/documents/list.json');
    $item_class = new MigrateItemJSON('/path/to/documents/document-:id.json');    
    $this->setSource(new MigrateSourceList($list_class, $item_class));
  }

}

Step 2: Expose migration class to Migrate

In order for Migrate to be aware of our custom migration class we would first need to declare it in our custom_module/custom_module.info file as follows:

name = Custom module
description = Custom module importing articles
core = 7.x
...
files[] = articles_migration.inc

And then implement hook_migrate_api() hook.

/**
 * Implements hook_migrate_api().
 */
function custom_module_migrate_api() {
  return [
    'api' => 2,
    'groups' => [
      'CustomModule' => [
        'title' => t('Custom Module'),
      ],
    ],
    'migrations' => [
      'ArticleMigration' => [
        'class_name' => 'ArticleMigration',
        'group_name' => 'CustomModule',
      ],
    ],
  ];
}
Step 3: Run import

In order to run the import we would need to first register our statically defined migration by visiting admin/content/migrate/configure and clicking on "Register statically defined classes". We can then visit the Migrate dashboard at admin/content/migrate and run our migration.