CMS

Drupal8 Migrate API, Migrating Nodes From Drupal7 – Part 2

Please See: Drupal8 Migrate API, Migrating Nodes From Drupal7 – Part 1 for Part-1 of this series. This is the continuation of the same.

Earlier in the series, we went through the process of configuration of the migration source and how a migration module can be written. We also configured the migration definition and source plugin for the nodes that were to be migrated. The migration is dependent of two other migrations: migrate_fruit_vitamins and migrate_fruit_images. Let’s us walk-through their implementations.

2.4 Migrating Taxonomy Terms

Let us create a file /config/install/migrate_plus.migration.migrate_fruit_vitamins.yml with the following content, which is the migration definition for terms that we are going to import from the source instance. The default migration template for taxonomy terms is found at /core/modules/taxonomy/migration_templates/d7_taxonomy_term.yml.

id: migrate_fruit_vitamins
label: Migrate Vitamin Terms
#migratio group
migration_group: fruit
dependencies:
  enforced:
    module:
      - fruit_migration
source:
  plugin: migrate_fruit_vitamins
  # drupal7 connection name
  target: db_d7
process:
  tid: tid
  vid: vocbulary_machine_name
  name: name
  description: description
  weight: weight
  #for migrating term heirachy
  parent_id:
    -
      plugin: skip_on_empty
      method: process
      source: parent
    -
      plugin: migration_lookup
      migration: migrate_fruit_vitamins
  parent:
    plugin: default_value
    default_value: 0
    source: '@parent_id'
destination:
  plugin: entity:taxonomy_term

Create a file \src\Plugin\migrate\source\Vitamins.php inside the module and add the following content to it. This will serve as the source plugin for the terms to be migrated. Let us extend the class Drupal\migrate\Plugin\migrate\source\SqlBase to write our own source plugin class for the terms. The particular methods that will be overridden are:

query() defines the basic query used to retrieve data from the source table.

fields() contains an array of the base fields within the source table.

getIds() Defines the source fields uniquely identifying a source row.

prepareRow() Adds additional data to the row. Any property we create using $row->setSourceProperty() will be available in the “process” step.

<?php
/**
 * @file
 * Contains \Drupal\migrate_custom\Plugin\migrate\source\Vitamins.
 */

namespace Drupal\fruit_migration\Plugin\migrate\source;

use Drupal\migrate\Row;
use Drupal\migrate\Plugin\migrate\source\SqlBase;
 
/**
 * Import vitamins terms from Drupal7 instance
 *
 * @MigrateSource(
 *   id = "migrate_fruit_vitamins",
 * )
 */
class Vitamins extends SqlBase {
  /**
   * {@inheritdoc}
   */
  public function query() {
    $query = $this->select('taxonomy_term_data', 'td');
    $query->join('taxonomy_vocabulary', 'tv', 'tv.vid = td.vid');
    $query->fields('td', array('tid', 'vid', 'name', 'description', 'weight', 'format'))
      ->distinct()
      ->condition('tv.machine_name', 'vitamins');
    return $query;
  }
  /**
   * {@inheritdoc}
   */
  public function fields() {
    return array(
      'tid' => $this->t('The term ID.'),
      'vid' => $this->t('Existing term VID'),
      'name' => $this->t('The name of the term.'),
      'description' => $this->t('The term description.'),
      'weight' => $this->t('Weight'),
      'parent' => $this->t("The Drupal term IDs of the term's parents."),
    );
  }
  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row) {
    // Find parents for this row.
    $parents = $this->select('taxonomy_term_hierarchy', 'th')
      ->fields('th', array('parent', 'tid'))
      ->condition('tid', $row->getSourceProperty('tid'))
      ->execute()
      ->fetchCol();
    $row->setSourceProperty('parent', $parents);
    $row->setSourceProperty('vocbulary_machine_name', 'vitamins');
    return parent::prepareRow($row);
  }
  /**
   * {@inheritdoc}
   */
  public function getIds() {
    $ids['tid']['type'] = 'integer';
    return $ids;
  }
}

2.5 Migrating Images

Create a file /config/install/migrate_plus.migration.migrate_fruit_images.yml inside the module with the following content, which would be the migration definition for images to be migrated.

id: migrate_fruit_images
label: Fruit Images
migration_group: fruit
#Migration Sourec
source:
  plugin: migrate_fruit_image
  constants:
    # Full path to the drupal7 installation directory.
    source_base_path: 'C:xampp\htdocs\drupal7'
  target: db_d7
process:
  fid: fid
  filename: filename
  source_full_path:
    -
      plugin: concat
      delimiter: /
      source:
        - constants/source_base_path
        - filepath
    -
      plugin: urlencode
  uri:
    plugin: file_copy
    source:
      - '@source_full_path'
      - uri
  filemime: filemime
  status: status
  created: timestamp
  changed: timestamp
  uid: uid
destination:
  plugin: entity:file

Create another file \src\Plugin\migrate\source\FruitImages.php and with the following content. This is the source plugin class for migration of the images. Here, the base plugin class Drupal\file\Plugin\migrate\source\d7\File is extended to implement the plugin.

<?php
/**
 * @file
 * Contains \Drupal\fruit_migration\Plugin\migrate\source\FruitImages.
 */
namespace Drupal\fruit_migration\Plugin\migrate\source;
use Drupal\file\Plugin\migrate\source\d7\File;
use Drupal\Core\Database\Query\Condition;
use Drupal\migrate\Row;
/**
 * Import fruit images form d7
 *
 * @MigrateSource(
 *   id = "migrate_fruit_image"
 * )
 */
class FruitImages extends File {
  /**
   * {@inheritdoc}
   */
  public function query() {
    $query = $this->select('file_managed', 'fm');
    $query->join('field_data_field_fruit_image', 'fi', 'fi.field_fruit_image_fid = fm.fid');
    $query->join('node', 'n', 'n.nid = fi.entity_id');
    $query->fields('fm', ['fid', 'uid', 'filename', 'uri', 'filemime', 'status', 'timestamp'])
      ->distinct()
      ->condition('fi.bundle', 'fruit')
      ->orderBy('n.changed', 'DESC');

    // Filter by scheme(s), if configured.
    if (isset($this->configuration['scheme'])) {
      $schemes = array();
      // Accept either a single scheme, or a list.
      foreach ((array) $this->configuration['scheme'] as $scheme) {
        $schemes[] = rtrim($scheme) . '://';
      }
      $schemes = array_map([$this->getDatabase(), 'escapeLike'], $schemes);

      // uri LIKE 'public://%' OR uri LIKE 'private://%'
      $conditions = new Condition('OR');
      foreach ($schemes as $scheme) {
        $conditions->condition('uri', $scheme . '%', 'LIKE');
      }
      $query->condition($conditions);
    }
    return $query;
  }
}

In the last step, create a fruit_migration.install file and implement the hook_uninstall function to remove the migration definitions upon uninstalling the module from the database.

/*
 * implements hook_uninstall
 */
function fruit_migration_uninstall() {
  \Drupal::entityManager()->getStorage('migration')->load('migrate_fruits')->delete();
  \Drupal::entityManager()->getStorage('migration')->load('migrate_fruit_vitamins')->delete();
  \Drupal::entityManager()->getStorage('migration')->load('migrate_fruit_images')->delete();
  \Drupal::entityManager()->getStorage('migration_group')->load('fruit')->delete();
}

Voila! We have successfully created our migration module. The structure of the module should look like the one below:

3. Running the migration

Once the module is successfully enabled, navigate to the drupal8(destination) installation directory in the command prompt and execute the command drush migrate-status. This will list all the migrations available and their statuses.

Run the command drush migrate-import –group=fruit from the command prompt to process all the migrations in the group fruit and import the corresponding data from the source.

Migrations can be run individually using the command drush migrate-import <migration_name>. More information about the Drush migrate commands can be found here

Happy Migrating!!

About The Author

Malay Nayak

Acquia Certified Drupal8 Developer

Leave a Reply

*