Migración de contenidos - Estructura de una migración

18/11/2020
Content migration - Structure of a migration

Introducción

En el post anterior hablamos de como realizar un análisis y un plan de migración para una migración de contenidos en drupal. En este segundo post llevaremos ese análisis al código.

Qué es migrate API

La API de Migrate proporciona servicios para migrar datos desde un sistema de origen a Drupal 8. El conjunto de módulos que componen Migrate API son:

  • Migrate: Es el que proporciona el framework de migración de uso general.
  • Migrate Drupal: Nos ayuda y permite realizar migraciones de D6 y D7 a D8 o posterior.
  • Migrate Drupal ui: Nos proporciona una interfaz de usuario para realizar migraciones.

Migrate API está basado en procesos de extracción, transformación y carga (ETL).

  • La fase de extracción de datos es donde se hace uso de extensiones de origen (source plugin) y con ella referenciamos al soporte y al conjunto de datos de estos. Pueden ser por ejemplo ficheros CSV, MySql,  JSON, XML, etc.
  • La fase de transformación de datos es donde se hace uso de extensiones de transformación (process plugins). La finalidad de esta fase es el tratamiento y procesamiento de datos individuales como pueden ser concatenar, pasar a mayúscula, extraer, saltar un campo si está vacío, añadir un valor por defecto, etc.
  • La fase de carga de datos es donde se hace uso de extensiones de destino (destination plugin) y su finalidad es la creación de entidades en drupal. Estos pueden ser: nodos, tipos de contenidos, taxonomías, usuarios, etc.

Herramientas adicionales

Como herramientas adicionales para facilitar el desarrollo y lanzamiento de migraciones se utilizan los siguientes módulos:

Migrate plus

Este módulo contribuido (https://www.drupal.org/project/migrate_plus) nos proporciona extensiones en el marco central de nuestra migración. Las características de este módulos son:

  • Definición de migraciones y sus complementos como entidades de configuración, lo que permite cargar, modificar y guardar de manera flexible.
  • Nos permite crear grupos de migración para organizar nuestras migraciones de manera que estas se agrupen para lanzarlas posteriormente.
  • Nuevo evento PREPARE_ROW el cual nos permite modificar los datos de origen antes de que comience el procesamiento.
  • Plugins para el procesado de datos en los ficheros de configuración: entity_lookup, entity_generate, file_blob, merge, skip_on_value, str_replace o transliteration.
  • Plugins para el destino de los datos en los ficheros de configuración:
         - Table: permite migrar datos directamente a una tabla SQL.
  • Plugins para el origen en los ficheros de configuración.
         - SourcePluginExtension: una clase abstracta que proporciona un mecanismo estándar para especificar los ids y los campos de una fuente a través de la configuración.
         - Url: un complemento de origen que admite contenido basado en archivos.

Las relaciones o el mapa de origen y destino se guardan a nivel de tablas en base de datos al igual que ocurre con los mensajes de posibles problemas encontrados en el lanzamiento de la migración.

Migrate tools

Este módulo contribuido (https://www.drupal.org/project/migrate_tools) nos proporciona herramientas para ejecutar y administrar migraciones. Nos provee de una serie de comandos drush para interactuar con las migraciones tales como migrate:status, migrate-import, etc.

En los siguientes post veremos como administrar migraciones con este módulo.

Otros módulos

Existen otros módulos contribuidos que ofrecen funcionalidades extras a las migraciones de drupal. A continuación se listan algunos de ellos:

  • Migrate Source CSV: Permite utilizar ficheros CSV como soporte de datos.
  • Migrate Google Sheets: Para realizar migraciones desde hojas de cálculo de Google.
  • WordPress Migrate: Para realizar migraciones desde un cms wordpress.
  • Migrate Process S3: Ofrece el process plugin 2s3_download” para extraer archivos de S3 a la migración.
  • ...

Estructura de una migración

Módulo de una migración

Como se ha comentado en el anterior post sobre migración de contenidos, las migraciones automáticas tienen bastantes limitaciones, por esta razón nos vamos a centrar en migraciones personalizadas. Para ello, debemos de crear un módulo custom que definirá las dependencias de este en el fichero .info (migrate, migrate_plus, migrate_tools, etc.), los archivos de configuración .yml y la definición de plugins en caso de necesitarlos.

Structure of a migration - Image 00
Estructura de nuestro módulo

Conexión a la base de datos de origen

En caso de que el origen tenga como soporte de datos una base de datos, por ejemplo en el caso de un sistema drupal 6 ó 7, se debe añadir la conexión en el fichero settings.php de drupal:

Structure of a migration - Image 01
Conexión a la base de datos de origen

La clave (database_origin) de la conexión a la base de datos será la referenciada en el fichero de configuración del grupo de la migración, si en el caso de que la key se llame migrate, no habría que especificarla en dicho fichero.

Ficheros de configuración

Dentro del directorio config/install irán los ficheros de configuración de cada una de las migraciones que se van a realizar y los de grupo de migración.

Fichero de configuración del grupo

Tal y como estandariza migrate plus, las nomenclaturas de estos ficheros debe ser: migrate_plus.migration_group.[my_migration].yml.

Structure of a migration - Image 02
Fichero yml de configuración para el grupo de migración my_migration_group.

Fichero de configuración de una migración

Tal y como estandariza migrate plus, las nomenclaturas de este tipo de ficheros debe ser migrate_plus.migration.[my_migration]_[entity].yml.

Structure of a migration - Image 03
Fichero yml de una migración de noticias (my_migration_news) dentro del grupo (my_migration_group)

La mayoría de los ficheros de configuración ya vienen definidos en drupal, ya sea en el core o en módulos contribuidos que necesiten de migraciones para el traspaso de información. Simplemente debemos de buscar dentro de cada módulo el directorio migrations y lo encontraremos. A continuación se muestran algunos de estos:

  • Migración de usuarios: core/modules/user/migrations/d7_user.yml
  • Migración de tipos de contenido: core/modules/node/migrations/d7_node.yml
  • Términos de taxonomías: core/modules/taxonomy/migrations/d7_taxonomy_term.yml
  • Google analytics: modules/contrib/google_analytics/migrations/d7_google_analytics_settings.yml
  • Pathauto: modules/contrib/pathauto/migrations/d7_pathauto_patterns.yml

Si tenemos la necesidad de por ejemplo migrar usuarios simplemente duplicamos el d7_user.yml y modificamos lo que necesitemos para adaptarlo al nuevo modelo de datos de la entidad que corresponda. El tiempo y la experiencia harán lo demás.

Una vez instalado nuestro módulo, por cada uno de estos ficheros encontraremos a nivel de base de datos dos tablas:

  • migrate_map_ [id_migration]: Contiene la relación de identificadores de origen (sourceid) con identificadores de destino (destid).
  • migrate_message_ [id_migration]: Contiene los posibles mensajes de errores que surjan en la migración.

Las secciones y la organización que componen estos ficheros de configuración son las que veremos a continuación.

Información base

Información e identificación sobre una migración concreta. Identificador de la migración, label a mostrar, grupo de migración son algunas de las propiedades que componen esta sección.

Structure of a migration - Image 04
Ejemplo de información base de una migración

Orígenes de datos (Source key)

Son los responsables de obtener los datos de la fuente u origen. Esta sería la entidad de origen que vamos a importar a nuestro sistema drupal, un tipo de contenido, una taxonomía, usuarios, etc.

Existen plugins definidos que extienden de SourcePluginBase:

  • Migración de ficheros: /core/modules/file/src/Plugin/migrate/source/d7/File.php
  • Migración de usuarios: /core/modules/user/src/Plugin/migrate/source/d7/User.php
  • Migración de taxonomías: /core/modules/taxonomy/src/Plugin/migrate/source/d7/Term.php
  • Migración de nodos: /core/modules/node/src/Plugin/migrate/source/d7/Node.php

Existen módulos que extienden para otros orígenes de datos:

  • Migrate Source CSV
  • Migrate Google Sheets
  • WordPress Migrate
  • ...

Otras propiedades:

  • track_changes: al ejecutar una migración, esta propiedad actualiza los nodos migrados con anterioridad que se hayan actualizado en origen con posterioridad a la migración. No confundir con el  el flag --update, este último actualizará cualquier nodo migrado.
  • translations: Para migraciones multi idioma.
  • constants: Constantes para su uso en la migración.

Todos estos plugin se localizan dentro de cada módulo en el directorio “src/Plugin/migrate/source” y se pueden declarar nuevos o extender existentes.

En el siguiente enlace se puede encontrar más información acerca de esa sección: https://www.drupal.org/docs/8/api/migrate-api/migrate-source-plugins

A continuación se muestra una serie de ejemplos para entender mejor el origen de datos:

Structure of a migration - Image 05
Migración de noticias utilizando el plugin d7_node. Este trozo de código refleja la migración de las traduciones de las noticias. Se está haciendo uso de constantes y de la propiedad track_changes explicada anteriomente.

 

Structure of a migration - Image 06
Migración de usuarios mediante el plugin d7_user.

 

Structure of a migration - Image 07
Migración de los términos del vocabulario “tags” mediante el plugin d7_taxonomy_term.

 

Structure of a migration - Image 08
Migración de ficheros mediante el plugin d7_file.

 

Structure of a migration - Image 09
Migración de contactos mediante el plugin csv del módulo Migrate Source CSV. En él se ve el mapa de campos con el nombre y la descripción de cada columna de la primera fila del csv.

Procesamiento de datos (Process key)

Describe propiedad por propiedad cómo se construirá el destino a partir de los datos de origen. El valor de la clave de proceso es una matriz asociativa, donde cada clave es una propiedad de destino. Los valores asociados con cada clave describen cómo se crea el valor de destino. En resumen es el donde se procesan y se tratan los datos de origen y por consiguiente donde mayor carga de trabajo tiene la migración.

Existen plugins definidos que extienden de ProcessPluginBase:

  • Get (por defecto)
  • Callback
  • migration_lookup
  • sub_process
  • concat
  • ...

Otros atributos:

  • Copia de valores '@var': Definición de variables para utilizar dentro la sección process.
  • Pipelines o tuberías - - - - -: Encadena plugins para procesar el dato con un fin.
  • no_stub:

    Resuelve el problema a quién nace antes, el huevo o la gallina?. Esta propiedad se utiliza para relaciones o referencias circulares. Por ejemplo, si tenemos un nodo artículo que tiene relacionado el mismo tipo de contenido artículo, podemos utilizar la propiedad no_stub: false. Para el mismo caso, si al migrar un artículo con identificador 1 que tiene relacionado un artículo con identificador 3 y este último aún no ha sido migrado y por consiguiente no existe en el destino, migrate API añade este contenido en el destino como stub, creando así un nodo en drupal del tipo que corresponda en destino y reservando un identificador que asignará como relacionado al nodo con identificador 1. En el momento que la migración pase por el nodo artículo 3, actualizará las referencias en el nodo que ha reservado como stub.

Todos estos plugin se localizan o deben localizarse dentro de cada módulo en el directorio “src/Plugin/migrate/process” y se pueden declarar nuevos o extender existentes.

En el siguiente enlace se puede encontrar más información acerca de esa sección: https://www.drupal.org/docs/8/api/migrate-api/migrate-process-plugins

A continuación se muestra una serie de ejemplos para entender mejor el procesado de los datos:

Structure of a migration - Image 10
Para el caso de querer asociar un field a otro, podemos hacerlo con el plugin get o directamente propiedad a propiedad puesto que este plugin es el que se utiliza por defecto.

 

Structure of a migration - Image 11
Se está utilizando el plugin static_map para el mapeo de roles de origen, en caso de que no tenga valor se pone el valor por defecto “editor”.

 

Structure of a migration - Image 12
Se está utilizando el plugin migration_lookup para asociar un término de taxonomía proveniente de dicha migración. Se le envía el campo field_tag_tournaments de origen y el plugin devuelve el identificador de destino creado por la migración de términos (my_migration_tax_term_tags_tour).

 

Structure of a migration - Image 13
Se utiliza el plugin migration_lookup para asociar un nodo del tipo noticia sobre la misma migración que se está realizando (referencia circular). Nótese que no_stub está a false. Si el nodo no existe lo crea como stub y cuando este sea migrado lo actualiza.

 

Structure of a migration - Image 14
Uso de variables para que alt y el title de la imagen sean el título del nodo.

Destino (Destination plugins)

El complemento de destino de la API de migración indica qué tipo de entidades Drupal se crean. Estas pueden ser de dos tipos:

  • Entidades de contenido: nodos, usuarios, términos de taxonomía, archivos, etc.
  • Entirades de configuración: tipos de contenido, definiciones de campo, etc.

El tipo de entidad de destino normalmente se suele definir como, por ejemplo entity:entity_type y entity:node

Existen plugins definidos que extienden de DestinationBase:

  • entity:entity_type
  • entity:taxonomy_term
  • entity:user
  • entity:file
  • entity:media
  • ...

Una propiedad para la migración de traducciones de contenido es “translations: true” en el cual estamos indicando que lo que vamos a crear en destino es una traducción.

Structure of a migration - Image 15
Sección destino de una migración para crear un contenido de tipo document.

 

Structure of a migration - Image 16
Sección destino de una migración para crear una traducción de contenido de tipo new.

 

Structure of a migration - Image 17
Sección destino de una migración para crear términos de taxonomía del vocabulario tags_news.

Dependencias

En la clave migration_dependencies irán las dependencias que existan dentro del process key del fichero de migración. Estas hacen alusión a migraciones relacionadas que pueden ser opcionales o requeridas y serán ejecutadas antes que las que tienen la dependencia. Por lo tanto, habrá tantas dependencias como migraciones existan en esta sección. Si las dependencias son opcionales podemos lanzar la migración independientemente de que la dependencia esté migrada, en caso de que sea requerida, la dependencia debe estar migrada.

En relación a la propiedad “dependencies”, se añade el nombre del propio módulo de migración al fichero para que cuando sea desinstalado, elimine la configuración a nivel de base de datos.

Structure of a migration - Image 18
Ejemplo de dependencias de una migración.

Conclusiones

Concluimos con que lo más importante de este post atiende a lo siguiente:

  1. Dependencias y módulos necesarios.
  2. Estructura del módulo de migración.
  3. Ficheros de configuración para el grupo y para migraciones.
  4. Secciones de una migración.
  5. Uso de plugins.

En el siguiente post veremos como funciona el ETL mediante plugins y como crear nuevos y extender estos.