Accueil / Blog / Métier / 2016 / Utiliser Migrate en Drupal 8

Utiliser Migrate en Drupal 8

Par Simon Georges publié 20/12/2016, édité le 21/12/2016
Trucs, astuces et points d'attention pour l'import de données avec Migrate en Drupal 8.
Utiliser Migrate en Drupal 8

Migrate a été intégré au cœur de Drupal 8, dans l'objectif avoué de devenir un standard pour les migrations de Drupal à Drupal. Du coup, ce module continue de s'imposer comme étant un standard pour les migrations de données, quelles qu'elles soient, dans Drupal. Il est d'ailleurs partie intégrante de notre formation au développement Drupal 8.

Beaucoup de choses ont changé en Drupal 8, et cela manque encore d'exemples très détaillés de migrations permettant de s'y référer, je vais donc partager avec vous quelques astuces tirées d'un projet actuel.

Migrate, une histoire de plugins

Migrate était déjà très orienté objet en Drupal 7, et il bénéficie en Drupal 8 pleinement du concept de Plugin : chaque partie de la migration est en effet un Plugin, que vous pouvez donc brancher / débrancher ou surcharger à volonté.

On trouve des plugins "Source", qui permettent de décrire la source des données, par exemple Migrate Source CSV ; des plugins "Destination", qui indiquent ce que l'on veut créer, donc liés aux objets Drupal : Node, Taxonomy, User, Menu, Block, … ; des plugins "Process", qui permettent d'agir sur le traitement (comme on le verra ci-dessous).

Bien démarrer : utiliser les bons modules

Migrate est dans le cœur de Drupal… mais ce n'est pas exactement le module Migrate que vous connaissiez en Drupal 7, seulement un cœur de ses fonctionnalités. Pour bien développer vos migrations, il faut y ajouter quelques modules issus de la communauté. Ce n'est peut-être que temporaire, il est possible que ces modules soient à terme éventuellement intégrés au cœur de Drupal.

Migrate Tools

Il est beaucoup plus facile et rapide de lancer des migrations depuis Drush, mais les commandes sont toutes dans un module appelé Migrate Tools. Je vous recommande donc d'utiliser ce module et notamment les commandes :

  • drush migrate-status : affiche la liste des migrations (avec le nombre potentiel d'éléments qui vont être migrés) ;
  • drush migrate-import : permet de lancer une migration ;
  • drush migrate-rollback : le contraire, permet de revenir en arrière en supprimant tout ce qui a été créé par la migration ;
  • drush migrate-reset-status : rétablit le statut d'une migration (à utiliser quand une migration échoue) ;
  • drush migrate-stop : arrête une migration en cours.

Migrate Plus

Le module "Migrate Plus" ajoute plusieurs choses aux fonctionnalités du cœur de Migrate :

  • 2 plugins "Process" : EntityLookup (qui permet de chercher une entité pour migrer un champ Entity Reference) et EntityGenerate (qui permet de créer une entité si elle n'existe pas durant la migration) ;
  • La définition de l'entité de configuration "Migration", permettant donc de créer des fichiers *.yml définissant la migration, qui seront ensuite déposés dans le répertoire config/install de votre module et importés dans la gestion de configuration de Drupal à l'installation de votre module.

C'est donc un composant essentiel de la plupart des migrations un peu complexes.

Migrate Source CSV

Enfin, depuis que je fais du migrate, j'ai toujours préféré les CSV aux XMLs, trouvant ces fichiers bien plus commodes à manipuler (et plus faciles à produire par les clients !), notamment dans le cadre des migrations. J'utilise donc le module source associé : Migrate Source CSV.

Structure de la migration

Nous allons maintenant étudier globalement le fichier de la migration. Vous en trouverez un exemple complet ici.

Description de la migration

Ici, on débute le fichier par quelques informations de base, qui permettent au système d'identifier et d'afficher notre migration. Il est possible de regrouper ces migrations dans des "groupes", à utiliser lors de vos migrations très complexes.

id: technologies
label: "Import technologies"
migration_groups:
- default

Source

Il faut maintenant décrire la source de nos données, c'est à dire le chemin du fichier CSV à utiliser, le séparateur des champs, la clé (permettant à Migrate d'éventuellement ne migrer que les nouvelles données ou de faire des mises à jour à partir des bonnes informations) et la liste des colonnes "utiles" du CSV (inutile de décrire les colonnes qui ne serviront pas à la migration).

source:
plugin: csv
delimiter: ,
path: 'news.csv'
header_row_count: 1
keys:
 - Title
column_names:
 0:
 Field1: A field
1:
 Field2: Another awesome field
 2:
 Title: Title of the content

Destination

Cette partie est très sommaire, on indique la donnée Drupal que l'on veut créer.

destination:
 plugin: entity:node

Process

La partie "process" est la plus importante du fichier, car c'est celle qui détermine les traitements éventuels à effectuer sur les champs. On indique donc les champs à migrer, les uns après les autres, avec les plugins de traitement à utiliser. Dans le cas d'une migration très simple, on indique juste la correspondance entre les champs Drupal et les champs issus du CSV (décrits dans la partie "Source") et on précise le type de contenu à créer avec un plugin "default_value".

process:
 title: Title
 field_field1: Field
 field_field2: Field2
 type:
 plugin: default_value
 default_value: news

Dépendances

Cette clé est essentielle, sans sa présence, l'import de la migration ne fonctionnera pas. Ne l'oubliez pas ;-) !

migration_dependencies: {}

Les plugins de Process de Migrate, comment ça marche ?

Migrate définit un certain nombre de plugin de process, dont le nom suffit parfois à comprendre leur utilité :

  • default_value : mettre une valeur par défaut ;
  • callback : appeler une fonction ;
  • concat, flatten, extract, explode : quelques traitements simples de données ;
  • skip_on_empty : permet de sauter une ligne de l'import si la valeur est vide

Le plugin par défaut est "get", c'est à dire que si vous écrivez

title: Title

c'est strictement équivalent à

title:
  plugin: get
  source: Title

La bonne nouvelle, c'est qu'il est possible d'enchaîner ces plugins : dans ce cas, la valeur renvoyée par un plugin est passée au plugin suivant, et si certains plugins renvoient des tableaux d'éléments, les plugins peuvent soit traiter ces valeurs multiples, soit appeler le plugin suivant plusieurs fois pour traiter le tableau.

Attention, il y a aujourd'hui un bug dans Migrate où les plugins capables de traiter des valeurs multiples ne s'enchaînaient pas correctement avec les plugins capables de traiter uniquement une seule valeur. J'ai dû utiliser le patch issu du ticket Once a process plugin returns multiple values, all following plugins are expected to handle multiple values (patch commité dans la version 8.2.4 du cœur aujourd'hui disponible).

Quelques exemples concrets

Mapping direct du titre

Rien à faire ;-) :

  title: Title

Récupération d'un champ user, facultatif, à partir du mail

  field_users:
-
plugin: skip_on_empty
      method: process
source: Users
-
plugin: entity_lookup
      entity_type: user
      value_key: 'mail'

Récupération d'un champ de taxonomie multiple, avec création éventuelle

  field_tags:
    -
      plugin: explode
      source: Field
      delimiter: "|"
    -
      plugin: skip_on_empty
      method: process
    -
      plugin: entity_generate
      entity_type: taxonomy_term
      value_key: 'name'

Publier les nœuds par défaut

status:
  plugin: default_value
  value: 1

Récupérer une valeur issue d'une autre migration

  field_picture:
    -
      plugin: skip_on_empty
      method: process
      source: Picture
    -
      plugin: migration
      migration: files
      source: Picture

Attention aux champs médias

Les champs médias cherchent à récupérer le fichier, et ne tolèrent donc pas la valeur NULL, il est impératif d'utiliser un skip_on_empty.

Comment travailler sur votre migration ?

Dans la mesure où un fichier de migration est un fichier de configuration, à la moindre erreur, vous devez désinstaller et réinstaller ce bout de configuration. La méthode est donc de désinstaller et réinstaller votre module… mais ça ne supprimera pas la configuration associée et vous aurez une erreur à la réactivation du module.

Voici donc un bout de code très utile à mettre dans le fichier .install de votre module :

/**
 * Implements hook_uninstall().
 */
function my_module_migrate_uninstall() {
  // Delete this module's migrations.
  $migrations = [
    'articles',
  ];
  foreach ($migrations as $migration) {
    Drupal::configFactory()->getEditable('migrate_plus.migration.' . $migration)->delete();
  }
}

Quelques articles pour aller plus loin

Migrate, c'est toujours un plaisir !

J'ai toujours beaucoup aimé ce module, notamment parce qu'il a dès le début été pensé pour des migrations, avec contrôle facile du rollback, feedback selon le nombre d'éléments ou le temps… Je mettrai à jour cet article dès que je tomberai sur d'autres astuces issues des différents projets que nous mettons en place.

Et si vous rencontrez un problème dans votre migration, n'hésitez pas à !

ABONNEZ-VOUS À LA NEWSLETTER !
Voir aussi
La roadmap Drupal 8 La roadmap Drupal 8 05/04/2017

Que va-t-il se passer dans le cœur du CMS Drupal dans les prochains mois ?

10 modules Drupal que vous n'utilisez (peut-être) pas assez 10 modules Drupal que vous n'utilisez (peut-être) pas assez 10/12/2014

Dans l'équipe Drupal de Makina Corpus, nous avons l'opportunité de travailler sur de nombreux ...

Gérer ses dépendances Drupal 7 avec Composer Gérer ses dépendances Drupal 7 avec Composer 08/12/2016

Drupal.org distribue maintenant les modules et thèmes dans son propre dépôt Packagist, voyons ...

Utiliser des bundles Symfony dans Drupal 7 Utiliser des bundles Symfony dans Drupal 7 19/12/2016

Notre module Drupal Symfony DIC permet d'apporter la puissance de Symfony, dans Drupal, ...

Utiliser le DIC de Symfony dans Drupal 7 Utiliser le DIC de Symfony dans Drupal 7 14/12/2016

Afin de préparer la compatibilité vers Drupal 8, il est possible de créer des composants avec le ...