Escribe tu primera migración en Drupal

En el artículo anterior, aprendimos que la API de Migraciones en Drupal es una implementación de un framework ETL. También hablamos de las pasos necesarios para escribir y ejecutar migraciones. Ahora, escribamos nuestra primer migración Drupal. Comenzaremos con un ejemplo muy básico: crear nodos a partir de datos predeterminados. Para esto, asumimos que cuentas con una instalación de Drupal usando el perfil de instalación `standard`. Esta incluye el tipo de contenido `Página básica`. A medida que avancemos en la serie, las migraciones se volverán más completas y complejas. Idealmente, se presentará sólo un concepto a la vez. Cuando eso no sea posible, explicaremos como las diferentes partes trabajan juntas. El enfoque de la lección de hoy es aprender la estructura de un archivo de definición de migración y cómo ejecutarlo.

Lista de complementos de migración

Nota de traducción: Aunque los artículos están en español, se utilizarán los mismos ejemplos de la serie en inglés. Por ello, los datos de ejemplo, nombres de sistema de migraciones y otros datos estarán en inglés. Esta serie no aborda la migración de información en múltiples idiomas. Al no especificar un idioma en los archivos de migración, el contenido será importado en el idioma predeterminado del sitio.

Escribe el archivo de definición de migración

El archivo de definición de migración debe pertenecer a un módulo. Por tanto, crea un módulo personalizado llamado `ud_migrations_first` y establece el módulo `migrate` que viene en el núcleo de Drupal como dependencia en el archivo *.info.yml

type: module
name: UD First Migration
description: 'Example of basic Drupal migration. Learn more at <a href="https://understanddrupal.com/migrations" title="Drupal Migrations">https://understanddrupal.com/migrations</a>.'
package: Understand Drupal
core: 8.x
dependencies:
  - drupal:migrate

Ahora crea un directorio llamado `migrations` y dentro de este un archivo llamado `udm_first.yml`. Nota que la extensión del archivo es `yml` no `yaml`. El contenido del archivo será:

id: udm_first
label: 'UD First migration'
source:
  plugin: embedded_data
  data_rows:
    -
      unique_id: 1
      creative_title: 'The versatility of Drupal fields'
      engaging_content: 'Fields are Drupal''s atomic data storage mechanism...'
    -
      unique_id: 2
      creative_title: 'What is a view in Drupal? How do they work?'
      engaging_content: 'In Drupal, a view is a listing of information. It can a list of nodes, users, comments, taxonomy terms, files, etc...'
  ids:
    unique_id:
      type: integer
process:
  title: creative_title
  body: engaging_content
destination:
  plugin: 'entity:node'
  default_bundle: page

La estructura de directorios será:

.
|-- core
|-- index.php
|-- modules
|   `-- custom
|       `-- ud_migrations
|           `-- ud_migrations_first
|               |-- migrations
|               |   `-- udm_first.yml
|               `-- ud_migrations_first.info.yml

YAML es un formato clave-valor que permite la anidación de elementos. Este es muy sensible a los espacios en blanco e indentación. Por ejemplo, este requiere al menos un carácter de espacio después del símbolo de dos puntos (:) que separa la clave del valor. También, cada nivel en de anidación debe estar indentado por dos espacios exactamente. Una fuente común de errores cuando se escriben migraciones es el uso inadecuado de espacios o indentación en los archivos YAML.

Un vistazo rápido al archivo revela las tres partes principales: fuente (source), proceso (process) y destino (destination). Otras claves proveen información adicional sobre la migración. Hay más claves que las que se muestran arriba. Por ejemplo, es posible definir dependencias entre migraciones. Otra opción es etiquetar migraciones para que se ejecuten juntas. Vamos aprender más sobre estas opciones en el futuro.

Analicemos cada par clave-valor en el archivo. Para la clave `id` es común establecer su valor al nombre del archivo que contiene la migración, pero sin la extensión `yml`. Esta clave sirve como identificador interno que Drupal y la API de Migraciones usa para ejecutar y llevar registro de la migración. El valor `id` debe ser caracteres alfanuméricos, opcionalmente usando guiones bajos (`_`) para separar palabras. Por su parte, la clave `label` es una cadena de lectura amigable usada para nombrar a la migración en varias interfaces.

En este ejemplo, se utiliza el plugin `embedded_data`. Este permite definir los datos a migrar directamente en el archivo de definición. Para configurarlo, se define una clave `data_rows` cuyo valor es un arreglo de todos los elementos que deseas migrar. Cada elemento puede contener un número arbitrario de pares clave-valor representando “columnas” de datos a importar.

Un caso de uso común para el plugin `embedded_data` es realizar pruebas de la propia API de Migraciones. Otro ejemplo válido es crear contenido predeterminado cuando los datos se conocen por adelantado. Frecuentemente presento talleres sobre construcción de sitios con Drupal. Para ahorrar tiempo, uso este plugin para crear nodos que luego se utilizan cuando se explica cómo crear Vistas. Revisa este repositorio para un ejemplo de esto. Toma en cuenta que el repositorio utiliza una estructura de directorio distinta para almacenar las migraciones. Esto se explicará en un artículo futuro.

Para el destino, se utiliza el plugin `entity:node` que permite crear nodos de cualquier tipo de contenido. La clave `default_bundle` indica que todos los nodos a crear serán del tipo “Página básica”, por defecto. Es importante notar que el valor de la clave `default_bundle` es el nombre de sistema del tipo de contenido. Esto se indica en `/admin/structure/types/manage/page`. En general, la API de Migraciones usa nombres de sistema para los valores. A medida que exploremos el sistema, indicaremos cuándo se usan y cómo encontrar los valores correctos.

El la sección de proceso, se mapean las columnas de la fuente a propiedades y campos de nodos. Las claves son nombres de propiedades de entidad o nombres de sistema de campos. En este caso, se establecen valores para el título del nodo (`title`) y el campo cuerpo (`body`). Los nombres de sistema se pueden encontrar en la página de configuración del tipo de contenido: `/admin/structure/types/manage/page/fields`. Durante la migración, los valores pueden copiarse directamente desde la fuente o transformados mediante plugins de proceso. Este ejemplo realiza una copia exacta de la fuente al destino. No es necesario que los nombres de las columnas en la fuente sean los mismos de el nombre de la propiedad de entidad o nombre de sistema. En este ejemplo, los nombres son deliberadamente distintos para hacerlos más fácil de identificar.

El repositorio, que se usará en varios ejemplos de la serie, está disponible en https://github.com/dinarcon/ud_migrations Colócalo en el directorio `./modules/custom` de la instalación Drupal. El ejemplo mostrado arriba es parte del submódulo “UD First Migration” así que asegúrate de habilitarlo.

Ejecuta la migración

Se usarán los comandos Drush provistos por el módulo Migrate Run para ejecutar las migraciones. Abre una terminal, cambia de directorios a la webroot de Drupal y ejecuta los siguientes comandos:

  • $ drush pm:enable -y migrate migrate_run ud_migrations_first
  • $ drush migrate:status
  • $ drush migrate:import udm_first

Nota: Se asume que el módulo Migrate Run ha sido descargado vía composer o de alguna otra manera.

Importante: Todos los snippets de código que muestran comandos Drush asumen la versión 10 a menos que se indique lo contrario. En Drush 8 e inferior, los nombres y aliases de los comandos son diferentes. Usualmente, un guion (-) se usaba como delimitador en los nombres de campo. Por ejemplo, `pm-enable` en Drush 8 en lugar de `pm:enable` en Drush 10. Ejecuta `drush list –filter=migrate` para verificar los comandos apropiados para la versión de Drush en uso.

El primer comando habilita el módulo `migrate` de Drupal core, el lanzador `migrate_run` y el módulo personalizado que contiene el archivo de definición de migración. El segundo comando muestra una lista de todas las migraciones disponibles en el sistema. Por ahora, sólo una debe aparecer listada con  `udm_first` como `Migration ID`. El tercer comando ejecuta la migración. Si todo marcha bien, al visitar la página de listado de contenido en `/admin/content` se listarán dos páginas básicas. ¡Felicidades, tu primer migración en Drupal se ha ejecutado exitosamente!

O tal vez no? Las migraciones en Drupal pueden fallar de muchas maneras. En ocasiones los mensajes de error no son muy descriptivos. En artículos futuros se presentarán flujos de trabajo recomendados y estrategias para depurar migraciones. Por ahora, estas son algunas cosas que pudieron haber salido mal en este ejemplo. Estás usando Drush 8 o inferior el cual utiliza diferentes nombres de comando. Si después de ejecutar el comando `drush migrate:status` no ver la migración `udm_first`, asegúrate que el módulo `ud_migrations_first` esté habilitado. Si está habilitado y aún no aparece, reconstruye la caché ejecutando el comando `drush cache:rebuild`.

Si la migración aparece, pero se produce un error al procesar el archivo YAML cuando se ejecuta el comando `migrate:import` verifica la indentación. Copiar y pegar de GitHub a tu IDE/editor puede producir cambios en el espaciado. Un espacio extra puede quebrar toda la migración así que hay que estar atento. Si el comando indica que se crearon nodos, pero al tratar de visualizarlos se produce un error fatal, el tipo de contenido no se estableció correctamente. Cabe destacar que el nombre de sistema del tipo de contenido “Página básica” es `page`, no `basic_page`. Este error no se puede corregir desde la interfaz de administración. Lo que se debe hacer es revertir la migración usando el comando `drush migrate:rollback udm_first`, luego corregir el valor de `default_bundle`, reconstruir la caché e importar nuevamente.

Nota: El módulo Migrate Tools se puede usar para ejecutar las migraciones. Este depende del módulo Migrate Plus. Por ahora, se mantendrán las dependencias de módulos al mínimo para enfocarse en la funcionalidad que el núcleo de Drupal provee por defecto. Además, al no utilizar estos módulos se demuestra que aunque son muy útiles, estos nos son requisitos indispensables para trabajar en proyectos de migraciones. Si decides utilizar Migrate Tools, es necesario desinstalar Migrate Run. Ambos proveen los mismos comandos Drush y se producen conflictos si ambos están habilitados.

¿Qué aprendiste en el artículo de hoy? ¿Sabías que Migrate Plus y Migrate Tools no son requisitos indispensables para proyectos de migraciones en Drupal? ¿Sabías que puedes colocar los archivos de definición de migraciones en un directorio `migrations`? ¿Qué consejos le darías a alguien que está escribiendo su primer migración? Favor comparte tus respuestas dejando un comentario. También te agradecemos compartas este artículo con tus amigos y colegas.