Première utilisation de Migrate

Créé le 23/03/2014

Dernière mise à jour le 05/07/2014

Cet article est un retour d'expérience sur ma première utilisation de Migrate, module permettant de faire des imports de contenu depuis à peu près n'importe quelle source de données vers un site Drupal.

J'ai au passage contribué de la documentation sur ce module ici, car bien qu'elle soit déjà très bien détaillée, je n'ai pas trouvé de point dédié aux traductions.

Modules utilisés :

Dans l'article, je suppose que vous avez une structure comme dans la documentation : https://drupal.org/node/2218843

D'entityreference en entityreference

Types de contenu et données fournies

Type de contenu 1 fr -> Type de contenu 1 en Titre, code type de contenu 1

^

  ^  
Type de contenu 2 fr <--> Type de contenu 2 en Titre, code type de contenu 1, code type de contenu 2
    ^  
Type de contenu 3 fr -> Type de contenu 3 en

Titre, titre type de contenu 2

Type de contenu 2 vers type de contenu 1

Dans le cas de la référence du type de contenu 2 vers le type de contenu 1, comme dans les données fournies il y a le code identifiant le noeud du type de contenu 1, on peut trouver son id grâce à une fonction de callback lors du mapping. Cette fonction va s'appuyer sur un EntityFieldQuery permettant de filtrer sur la langue et la valeur du code.

$this->addFieldMapping('field_contenttype1', 'contenttype1_code')
  ->callbacks(array($this, 'getcontenttype1nid'));

protected function getcontenttype1nid($value) {
  $query = new EntityFieldQuery();
  $node_list = $query->entityCondition('entity_type', 'node')
    ->propertyCondition('type', 'contenttype1')
    ->propertyCondition('language', str_replace('_', '-', $this->arguments['language_prefix']))
    ->fieldCondition('field_contenttype11_code', 'value', $value, '=')
    ->execute();

  if (isset($node_list['node'])) {
    $node_nid_list = array_keys($node_list['node']);
    $value = $node_nid_list['0'];
  }

  return $value;
}

Type de contenu 3 vers type de contenu 2

Ici comme il y a un risque d'incertitude à cause du fait que l'on a que le titre du type de contenu 2 qui est donné et qu'avec les traductions il y a des risques de problèmes dû à des traductions non exactes. Il vaut mieux s'appuyer sur la gestion des traductions du type de contenu 2 comme expliquée sur cette page de documentation.

Comme les traductions au niveau d'un même type de contenu sont maîtrisées et que la gestion des références au niveau de la langue principale (ici l'anglais) entre différent type de contenu est elle aussi maîtrisée. Alors on va faire un détour par cette référence pour trouver les bonnes références dans les autres langues.

Importation d'entités custom

Migrate fonctionne très bien avec des entités du noyau, comme les noeuds, les utilisateurs, les termes de taxonomie, etc. En revanche pour les entités custom là c'est un peu plus compliqué. Pour tout ce qui est commerce, il y a Migrate commerce, pour les entités créées à partir de entity API ça devrait passé mais je n'ai pas encore tester, pour les entités créées à partir de ECK là en revanche ce n'est pas encore au point.

Même si l'import peut se faire, Migrate n'arrive pas à déterminer l'id de l'entité créée et donc (hormis les messages d'erreurs lors de l'import)  il ne peut pas faire de rollback et pour lui les entités n'auront pas été importées. Ce qui fait que l'import est obligatoirement un import que l'on doit faire en un coup.

Voici les modifications à apporter pour créer des entités custom :

$this->destination = new MigrateDestinationEntityAPI('mon_entité', 'bundle_de_mon_entité');
$this->map = new MigrateSQLMap($this->machineName,
  array(
    'csv_id' => array(
      'type' => 'int',
      'unsigned' => TRUE,
      'not null' => TRUE,
    )
  ),
  MigrateDestinationEntityAPI::getKeySchema()
);

Remarques divers

Pré-traitement de données

Dans la fonction prepareRow, il est possible de modifier les données, ce qui est pratique pour concaténer plusieurs données et pour par exemple ajouter des balises HTML.

$row->description = '

' . $row->description . '

' . $row->description_2 . '

';

Ajustement de valeurs

Il est possible de modifier les valeurs à la volée, avec une fonction de callback sur un mapping particulier, ce qui s'avère pratique lorsque les données fournit ne sont pas complètes et se trouve sur le site, on peut ainsi aller les chercher pour les ajuster.

$this->addFieldMapping('champ_drupal', 'donnee')
  ->callbacks(array($this, 'change_donnee'));

Ensuite il faut implémenter une fonction change_donnee qui s'occupera de l'ajustement.

Combinaison de données

Dans la fonction prepareRow, il est possible de créer de nouvelle données à partir d'autres. Par exemple :

$row->nouvelle_donnee = $row->donnee_1 . ' - ' . $row->donnee_2;

Ensuite dans le mapping des champs, on peut s'en servir :

$this->addFieldMapping('champ_drupal', 'nouvelle_donnee');

Conclusion

J'ai vraiment trouvé ce module excellent, car on peut vraiment faire ce qu'on veut avec les données, partir de n'importe quelle source (et même plusieurs simultanément, mais je n'ai pas encore eu ce besoin), faire du traitement avant, pendant, après l'import. Gérer du contenu encore non existant, là aussi pas encore testé. Et gérer plein d'autres cas plus ou moins les compliqués.

Ce n'est pas pour rien qu'il est dans le noyau de Drupal 8.

Ajouter un commentaire