¿Cómo hacer un Plugin de migración personalizado en Drupal 8?

Author Top
langelhc

En el artículo anterior explicamos que Drupal 8 (D8) trae en el núcleo (core) un sistema de migración automatizada que permite migrar tanto la configuración como el contenido desde Drupal 6/7, en éste articulo explicaremos como migrar sólo el contenido creando un modulo personalizado y un plugin de migración.

Asumiremos que el sitio de D8 ya ha sido desarrollado, es decir que ya tenemos creado los tipos de contenido y sus respectivos campos, pero todavía no se ha creado contenido.

Para este ejemplo tenemos como objetivo migrar el contenido del tipo page que tiene dos campos tipo imagen y enlace desde un sitio desarrollado en D7.

Creación de un módulo personalizado:

Utilizando la Drupal Console creamos un módulo llamado Custom migration:

$ drupal generate:module

Creación de la Plantilla de migración:

Dentro del modulo Custom migration, creamos la carpeta migration_templates, donde ubicaremos el archivo YAML:

Aquí definimos entre otras cosas lo siguiente:

  • El identificador de la migración será: custom_migration_node_page.
  • El source plugin que se utilizara para ésta migración.
  • En process, definimos el mapeo de propiedades y los valores que asumirán:
    • La propiedad type para hacer referencia al nombre del tipo de contenido destino.
    • La propiedad field_image_d8 que asumirá el valor de field_image.
    • La propiedad field_link_d8 que asumirá el valor asignado a field_link.
  • En migration_dependencies, definimos como dependencia obligatoria al Id 'd7_file', que se encarga de la migración de archivos, esto para el campo tipo imagen del tipo de contenido page.
id: custom_migration_node_page
label: Page Nodes
migration_tags:
  - Drupal 7
source:
  plugin: custom_migration_node_page
process:
  nid: nid
  vid: vid
  langcode:
    plugin: default_value
    source: language
    default_value: "und"
  title: title
  uid: node_uid
  type: type 
  status: status
  created: created
  changed: changed
  promote: promote
  sticky: sticky
  revision_uid: revision_uid
  revision_log: log
  revision_timestamp: timestamp
  field_image_d8: field_image
  field_link_d8: field_link
destination:
  plugin: entity:node
migration_dependencies:
  required:
    - d7_file

Ruta: modules/custom/custom_migration/migration_templates/custom_migration_node_page.yml

Creación del Plugin de Migración:

Este archivo debe llevar el mismo nombre que la clase que se define ahi dentro, y debe estar ubicado dentro de la siguiente estructura: /custom_migration/src/Plugin/migrate/source.

Es importante definir el identificador de la migracion en la Anotación @MigrateSource.

En la función query, agregamos una condición para obtener solo el contenido de tipo page, aquí tambien podríamos agregar una condición para que se migre solo el contenido que esta publicado en el sitio de D7.

Ruta: modules/custom/custom_migration/src/Plugin/migrate/source/custom_migration_node_page.php

<?php


namespace Drupal\custom_migration\Plugin\migrate\source;


use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity;


/**
 * Drupal 7 node source from database.
 *
 * @MigrateSource(
 *   id = "custom_migration_node_page",
 *   source_provider = "node"
 * )
 */
class custom_migration_node_page extends FieldableEntity {


  /**
   * The join options between the node and the node_revisions table.
   */
  const JOIN = 'n.vid = nr.vid';


  /**
   * {@inheritdoc}
   */
  public function query() {
    // Select node in its last revision.
    $query = $this->select('node_revision', 'nr')
      ->fields('n', array(
        'nid',
        'type',
        'language',
        'status',
        'created',
        'changed',
        'comment',
        'promote',
        'sticky',
        'tnid',
        'translate',
      ))
      ->fields('nr', array(
        'vid',
        'title',
        'log',
        'timestamp',
      ));
    $query->addField('n', 'uid', 'node_uid');
    $query->addField('nr', 'uid', 'revision_uid');
    $query->innerJoin('node', 'n', static::JOIN);
    $query->condition('n.type', 'page');
    return $query;
  }


  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row) {
    $nid = $row->getSourceProperty('nid');
    $vid = $row->getSourceProperty('vid');
    $row->setSourceProperty('type', 'page'); 
    $image_d7 = $this->getFieldValues('node', 'field_image', $nid, $vid);
    if (!empty($image_d7)) {
      $value_image[] = [
        'target_id' => $image_d7[0]['fid'],
        'alt' => $image_d7[0]['alt'],
        'title' => $image_d7[0]['title'],
        'width' => $image_d7[0]['width'],
        'height' => $image_d7[0]['height'],
      ];
      $row->setSourceProperty('field_image', $value_image);
    }
    $link_d7 = $this->getFieldValues('node', 'field_link', $nid, $vid);
    if (!empty($link_d7)) {
      $link_value[0]['uri'] = $link_d7[0]['url'];
      $link_value[0]['title'] = $link_d7[0]['title'];
      $row->setSourceProperty('field_link', $link_value);
    }
    return parent::prepareRow($row);
  }


  /**
   * {@inheritdoc}
   */
  public function fields() {
    $fields = array(
      'nid' => $this->t('Node ID'),
      'type' => $this->t('Type'),
      'title' => $this->t('Title'),
      'node_uid' => $this->t('Node authored by (uid)'),
      'revision_uid' => $this->t('Revision authored by (uid)'),
      'created' => $this->t('Created timestamp'),
      'changed' => $this->t('Modified timestamp'),
      'status' => $this->t('Published'),
      'promote' => $this->t('Promoted to front page'),
      'sticky' => $this->t('Sticky at top of lists'),
      'revision' => $this->t('Create new revision'),
      'language' => $this->t('Language (fr, en, ...)'),
      'tnid' => $this->t('The translation set id for this node'),
      'timestamp' => $this->t('The timestamp the latest revision of this node was created.'),
    );
    return $fields;
  }


  /**
   * {@inheritdoc}
   */
  public function getIds() {
    $ids['nid']['type'] = 'integer';
    $ids['nid']['alias'] = 'n';
    return $ids;
  }
}

Repasando el código anterior, debemos tener en cuenta que para campos de tipo imagen en D7 se usa el atributo ‘fid’ para hacer referencia al id del archivo, en D8 el atributo es ‘target_id’.

Para campos tipo enlace en D7 se usaba el atributo 'url' ahora en Drupal 8 el atributo es ‘uri’, es por esto que volvemos a definir la estructura el arreglo.

Procedimientos para ejecutar la migración:

Habilitamos el módulo ‘custom_migration’ y sus dependencias:

$ drupal module:install migrate migrate_drupal custom_migration

Cargando migraciones:

$ drupal migrate:setup

Ejecutando la migración:

$ drupal migrate:execute

Luego de ingresar las credenciales de acceso a la base de datos de D7, especificamos los Ids de migración, en este caso debemos ejecutar la migración de archivos ‘d7_file’ y luego ‘custom_migration_node_page’.

Espero les sea útil este artículo. Si buscan más informacion de como ejecutar migraciones con la Drupal Console pueden ver éste artículo (inglés).