La migration des contenus vers Drupal est rendue facile grâce au module « Migrate ». Quelles que soient les sources, le module est très souple, complet et simple d’utilisation. Nous pouvons faire la migration des nœuds, des utilisateurs, des taxonomies, des fichiers, des menus, des commentaires etc. Une interface en Back Office, facile à manipuler, nous guide pour tout type d’action. Importer, annuler l’import, réinitialiser, stopper la migration en cours sont des actions possibles dans cette interface. Il y a même plusieurs modules spécialisés pour des sources précises, comme « drupal_d2d » pour une source Drupal (version 5, 6 ou 7), « commerce_migrate » pour Drupal commerce, « wordpress_migrate » pour wordpress, « g2migrate » pour les photos et données relatives au Gallery package (version 2), « typo3_migrate » pour TYPO3, « phpbb2drupal » pour phpBB2.
Nous n’allons pas entrer en détail sur ces dernières, qui d’ailleurs sont déjà riches en documentation sur chacun de leur site officiel. Nous allons plutôt mettre en relief les problèmes assez classiques rencontrés lors d’une migration drupal vers drupal, à savoir :
- Migration des champs personnalisés
- Migration des « fields collections »
- Migration des fichiers/images
- Migration des books
Vue générale :
Bien entendu il y a déjà le module « drupal_d2d » pour migrer les contenus d’une source drupal vers une destination drupal. Après activation de ce module, nous observons un bouton « Import from Drupal » dans l’onglet « MIGRATE » du menu « Contents ». Ce bouton redirige vers une page de configuration à 6 étapes (configuration de la base de données source, configuration des utilisateurs à migrer, des taxonomies, des fichiers, des types de contenus, un résumé des paramètres avec des actions « save configurations » et « run import »).
En revenant au menu « MIGRATE » nous avons aussi le bouton « Tableau de bord » qui redirige vers une page de suivi et gestion des migrations. Si nous avons enregistré les 6 étapes mentionnées plus haut, nous aurons une nouvelle ligne insérée dans le tableau de bord. Pour lancer la migration, il suffit de cocher cette nouvelle entrée et cliquer sur « Exécuter ».
Problèmes :
Une fois la migration achevée, nous observerons dans l’édition d’un des contenus que seules les données des champs natifs sont importées (nid, title, uid, created, changed, status, language, body, etc.). Si nous avons des champs personnalisés (exemple : field_image_media, field_document_associe, etc.), ces champs sont vides. Pour mieux comprendre, regardons dans le détail de chaque contenu à migrer.
Il y a des problèmes de mapping entre la source et la destination. Les champs à fond rouge ne sont pas mappés correctement.
Dans l’onglet « Modifier », nous pouvons voir que les champs correspondants à la source sont vides.
Il faut choisir dans la liste de sélection le champ correspondant. Malheureusement, après sauvegarde de ces paramètres, les données ne sont toujours pas importées.
Proposition de solutions :
Le plus conseillé est de créer une classe spécifique pour importer chaque type de contenu. Là, nous avons l’assurance de réussir sans aucun problème. Nous allons voir cela étape par étape.
Tout d’abord, il nous faut créer un module custom pour contenir les classes spécifiques. Ce module doit suivre la convention de nommage suivante : « migrate_{modulename} ». Comme tout module, il doit y avoir les fichiers de base « migrate_{modulename}.info », « migrate_{modulename}.module », ainsi que les classes spécifiques « migrate_{classname}.inc ». Un autre fichier indispensable à créer est le « migrate_{modulename}.migrate.inc ». Ce fichier est essentiel pour contenir l’implémentation du « hook_migrate_api() », c’est là que seront déclarées les classes spécifiques nouvellement ajoutées. En principe, le fichier « .module » ne contient aucune ligne de code parce que les classes pour la migration sont déjà dans le hook du fichier « .migrate.inc ».
Une illustration pour simplifier :
La structure de la classe :
Le nom de la classe doit suivre la règle suivante : « {NomClasse}Migration ».
Elle doit hériter la classe abstraite « Migration » du module migrate.
Supposons un type de contenu « Article ».
Exemple :
Maintenant nous définissons la source, la destination, le mapping.
Voici le code complet :
Le contenu du fichier « .migrate.inc » :
Migration des champs personnalisés :
Ce qu’il faut bien préciser est le type d’entité de destination. Dans notre exemple, il s’agit d’un champ personnalisé pour un type de contenu. Donc nous utilisons, pour la destination, la classe « MigrateDestinationNode ».
Code :
Vient ensuite le mapping du champ personnalisé. Pour notre exemple, nous avons un champ de type « lien », donc il ne faut pas oublier le titre du lien, les attributs.
Code :
Migration des « fields collections » :
Les « fields collections » sont des entités à part, liées à une autre entité. De ce fait, nous devons créer une autre classe spécifique pour les migrer. Il y a donc une notion de dépendance, d’ordre d’import. L’entité hôte doit être importée avant de lancer la migration des « fields collections ».
Supposons que nous avons un champ field collection « bloc_video » rattaché au type de contenu article. Celui-ci a 3 champs « titre_video », « description_video » et « lien_video ».
Spécification de la dépendance :
Ici la destination est un field collection, donc :
Et le mapping :
Le code complet sera donc:
Ne pas oublier d'ajouter cette classe dans migrate_example_migrate_api().
Migration des fichiers/images :
Le principe est le même que celui mentionné plus haut, dans la migration des champs personnalisés.
Il faut préciser le répertoire de destination. Comme les « liens », les images ont des attributs « title », « alt », etc.
Le code sera comme suit :
Avant de lancer la migration des fichiers/images, il faut que les fichiers physiques soient synchronisés d’avance dans le bon répertoire.
Migration des books :
Garder la structure des livres lors de l’import des contenus est plutôt difficile, voire impossible, vu qu’on ne pourra pas maitriser l’ordre hiérarchique lors de l’import. Il se peut que des contenus de nième niveau soient importés avant même que leurs parents ou grands-parents ne soient déjà importés. L'idée est donc de d'abord terminer toutes les migrations sans se soucier de la hiérarchie.
Ensuite on crée un batch qui reconstruit le livre en se référant de la source. Il s’agit donc de travailler directement dans la table source « book » et la table de destination « menu_links ».
Structure de la table book:
Table menu_links:
Le travail consiste à reconstruire la nouvelle table book, image de l’ancienne et refaire une sauvegarde des contenus livre avec leur parent respectif.
Notons que dans la table « menu_links », le champ « plid » indique le nid parent direct du contenu concerné, le champ « depth » indique son niveau hiérarchique (Ex : deph = 3, le contenu est au 3è niveau), les champs « p1 p2 à p9 » sont respectivement les parents de niveau 1, 2 à 9.
Heureusement, une table stocke la correspondance des « ids » source et destination. Par exemple, pour le type de contenu « Article », on a une table « migrate_map_article » créée automatiquement lors de l’import.
Une simple requête permet d’obtenir les nouveaux « nid » et « bid » pour la table « book », en jouant sur les champs « sourceid1 » et « destid1 ».
De même pour obtenir le nouveau « plid » à partir de l’ancien « mlid ».
Une fois qu’on a le nouveau nid, bid et plid, on fait une mise à jour du contenu.
Code :
Note :
Il faut bien noter que si le type de notre champ personnalisé est un « entity reference », les « ids » pourraient être faussés. Nous devons faire une requête qui cherche la correspondance de l’ancien « id » dans la nouvelle table pour avoir l’id exact de l’entité liée. Pour cela il suffit de passer par les tables « migrate_map_{entityname} ». Si par exemple nous avons un champ « node reference » qui remonte un type de contenu « Mise en avant » dans le type de contenu « Article », il faut impérativement que les contenus « Mise en avant » soient importés avant les « Articles ». Ensuite, lors de l’import des « Articles », il faut faire référence aux nouveaux « ids » des « Mise en avant ».