Import des contenus dans Drupal 8

Dans Drupal 7, nous avons Feeds et Migrate qui permettent d’importer les contenus. Feeds met à disposition une interface graphique permettant d’effectuer l'import sans avoir besoin de taper des codes. Quant à Migrate, il faut créer notre propre importateur en code mais qui est très puissant quand on aura besoin des contenus complexes. Il y a beaucoup de changements dans Drupal 8.  Migrate est dans le cœur de Drupal 8. Par contre, Feeds n'a qu'une version dev et n'apporte pas grande chose pour l'instant. Il y a aussi quelques modules contribs qui permettent d'importer des contenus mais chacun a ses limites :

  • Content Import : Importer les nodes. Il est possible d'importer avec les champs d'entité référence avec la dernière version.
  • Taxonomy Import : Importer les termes d'une taxonomie avec hiérarchie.
  • Term CSV Export Import : Importer les termes d'une taxonomie avec hiérarchie et aussi des champs en chaîne de caractères.

En revanche, on a moins de limite avec Migrate et quelques modules de la communauté  (il est possible qu'ils soient intégrés dans le cœur dans les prochaine versions). Dans cet article, nous allons voir ensemble comment importer des contenus via Migrate. Comme tout est en entité dans Drupal 8, Migrate est capable d'importer tous les contenus : que ce soit des nodes, des utilisateurs, des termes de taxo, des fichiers et etc.

Structure des deux vocabulaires dans Drupal

Supposons qu'on ait besoin d'importer des termes de 2 taxonomies avec la structure ci-dessous dans Drupal :

  • Département
    • nom
    • code de département (champ texte)
  • Ville
    • nom
    • code postal (champ text)
    • latitude (décimal)
    • longitude (décimal)
    • département (entité référence : département)

Structure du csv

Voici ci-dessous les 2 fichiers csv à importer :

Name,Code
"Ain",1
"Aisne",2
"Allier",3
"Hautes-Alpes",5
"Alpes-de-Haute-Provence",4
"Alpes-Maritimes",6
"Ardèche",7
"Ardennes",8
"Ariège",9
"Aube",10
"Aude",11
"Aveyron",12
"Bouches-du-Rhône",13
"Calvados",14
"Cantal",15
"Charente",16
"Charente-Maritime",17
"Cher",18
"Corrèze",19
"Corse-du-sud",2a
"Haute-corse",2b
"Côte-d'or",21
"Côtes-d'armor",22
"Creuse",23
"Dordogne",24
"Doubs",25
"Drôme",26
"Eure",27
"Eure-et-Loir",28
"Finistère",29
"Gard",30
"Haute-Garonne",31
"Gers",32
"Gironde",33
"Hérault",34
"Ile-et-Vilaine",35
"Indre",36
"Indre-et-Loire",37
"Isère",38
"Jura",39
"Landes",40
"Loir-et-Cher",41
"Loire",42
"Haute-Loire",43
"Loire-Atlantique",44
"Loiret",45
"Lot",46
"Lot-et-Garonne",47
"Lozère",48
"Maine-et-Loire",49
"Manche",50
"Marne",51
"Haute-Marne",52
"Mayenne",53
"Meurthe-et-Moselle",54
"Meuse",55
"Morbihan",56
"Moselle",57
"Nièvre",58
"Nord",59
"Oise",60
"Orne",61
"Pas-de-Calais",62
"Puy-de-Dôme",63
"Pyrénées-Atlantiques",64
"Hautes-Pyrénées",65
"Pyrénées-Orientales",66
"Bas-Rhin",67
"Haut-Rhin",68
"Rhône",69
"Haute-Saône",70
"Saône-et-Loire",71
"Sarthe",72
"Savoie",73
"Haute-Savoie",74
"Paris",75
"Seine-Maritime",76
"Seine-et-Marne",77
"Yvelines",78
"Deux-Sèvres",79
"Somme",80
"Tarn",81
"Tarn-et-Garonne",82
"Var",83
"Vaucluse",84
"Vendée",85
"Vienne",86
"Haute-Vienne",87
"Vosges",88
"Yonne",89
"Territoire de Belfort",90
"Essonne",91
"Hauts-de-Seine",92
"Seine-Saint-Denis",93
"Val-de-Marne",94
"Val-d'oise",95
"Mayotte",976
"Guadeloupe",971
"Guyane",973
"Martinique",972
"Réunion",974
depart.data.csv
"Id","Name","Depart","CP","Lat","Lon"
1,"Ozan","Ain","1190",46.3833,4.91667
2,"Cormoranche-sur-Saône","Ain","1290",46.2333,4.83333
3,"Plagne","Ain","1130",46.1833,5.73333
4,"Tossiat","Ain","1250",46.1333,5.31667
5,"Pouillat","Ain","1250",46.3333,5.43333
6,"Torcieu","Ain","1230",45.9167,5.4
7,"Replonges","Ain","1620",46.3,4.88333
8,"Corcelles","Ain","1110",46.0333,5.58333
9,"Péron","Ain","1630",46.2,5.93333
65762,"Paris","Paris","75019",48.86,2.34445
65763,"Paris","Paris","75020",48.86,2.34445
ville.data.csv

Modules à utiliser

Pour faire cela, nous auront besoin d'activer les modules ci-dessous :

  •  Migrate (module core)
  • Migrate Plus (module contrib) enhancements du migrate, par exemple, il ajoute le processus 'entity_lookup' et le processus 'entity_generate' qui permettent d'importer les champs d'entité référence et de le créer quand il n'existe pas encore.
  • Migrate Tools (module contrib) : fournir des outils pour gérer la migration via l'interface ou en ligne de commande en drush.
  • Migrate Source CSV (module contrib) : ajouter le support du fichier csv.

Création d'un module custom

Nous allons commencer par créer un module custom :

name: custom_migrate
type: module
description: Import des contenus et des taxos
core: 8.x
package: Custom
dependencies:
  - migrate
  - migrate_source_csv
  - node
  - taxonomy
  - migrate_plus
  - migrate_tools
custom_migrate.info.yml

Config yml

En suite, nous allons créer les profils d'import. Grâce à Migrate Plus et Migrate Tools, nous pouvons gérer les imports par groupe via le backoffice. Il nous faut créer 3 ymls dans custom_migrate/config/install qui seront importé lors de l'installation de module :

  • migrate_plus.migration_group.taxo.yml
  • migrate_plus.migration.depart.yml
  • migrate_plus.migration.ville.yml

Le nom du fichier devrait respecter le syntaxe :  migrate_plus.migration_group.nom_du_group.yml pour un group de migration et migrate_plus.migration.nom_migration.yml pour une migration, cela permet de visualiser et de gérer via BO.

# Le nom de machine du groupe.
id: taxo
label: Import taxo
description: Importer les départements et les villes via csv.
source_type: CSV files
# Quand le module de depenceies est déinstallé, ce groupe sera supprimé automatiquement 
dependencies:
  enforced:
    module:
      - custom_migrate
migrate_plus.migration_group.taxo.yml
# Migration ID.
id: depart
label: Import des termes de département.
# Migration group.
migration_group: taxo
# Migration tags. Cela permet de gérer l'import via tag avec drush
migration_tags:
  - taxo
  - depart
# Source.
source:
  # Plugin de source
  plugin: csv
  # Lien du fichier csv
  path: 'public://import/taxo/depart.data.csv'
  header_row_count: 1
  # ID de chaque item : permet de gérer l'import lors qu'il s'agit de mise à jour ou rollback.
  keys:
    - Name
  # Définitions des champs dans le source.
  fields:
    Name: Nome de département.
    Code: Code de département.
  # Valeur statique.
  constants:
    bool_0: 0
    bool_1: 1
    uid_root: 1
    restricted_html: restricted_html
# Destination.
destination:
  # Import des termes de taxnomie
  plugin: 'entity:taxonomy_term'
  # Préciser la vocabulaire : département
  default_bundle: departement
# Mapping.
process:
  # Key : nom des champs à importer.
  name: Name
  field_code_departement:
    -
      plugin: callback
      callable: strtolower
      source: Code
    -
      plugin: default_value
      default_value: null
# Quand le module de dependencies est déinstallé, cette migration sera supprimée automatiquement 
dependencies:
  enforced:
    module:
      - custom_migrate
migrate_plus.migration.depart.yml
# Migration ID.
id: ville
label: Import des termes de ville.
# Migration group.
migration_group: taxo
# Migration tags. Cela permet de gérer l'import via tag avec drush
migration_tags:
  - taxo
  - ville
# Source.
source:
  # Plugin de source
  plugin: csv
  # Lien du fichier csv
  path: 'public://import/taxo/ville.data.csv'
  header_row_count: 1
  # ID de chaque item : permet de gérer l'import lors qu'il s'agit de mise à jour ou rollback.
  keys:
    - Id
  # Définitions des champs dans le source.
  fields:
    Id: Identifiant de ville.
    Depart: Nom de département.
    Name: Nome de ville.
    CP: CP de ville.
    Lat: Latitude.
    Lon: Logitude.
  # Valeur statique.
  constants:
    bool_0: 0
    bool_1: 1
    uid_root: 1
    restricted_html: restricted_html
# Destination.
destination:
  # Import des termes de taxnomie
  plugin: 'entity:taxonomy_term'
  # Préciser la vocabulaire : ville
  default_bundle: ville
# Mapping.
process:
  # Key : nom des champs à importer.
  name: Name
  field_ville_cp: CP
  field_lat:
      -
        plugin: callback
        callable: strtolower
        source: Lat
      -
        plugin: default_value
        default_value: 0.0
  field_lon:
      -
        plugin: callback
        callable: strtolower
        source: Lon
      -
        plugin: default_value
        default_value: 0.0
  field_departement_de_ville:
    # Champ entité réference 
      plugin: migration
      migration: depart
      source: Depart
# Dépendenceie de cette migration qui sera exécuté avant.
migration_dependencies:
  optional:
  # id de l'import
    - depart
# Quand le module de dependencies est déinstallé, cette migration sera supprimée automatiquement 
dependencies:
  enforced:
    module:
      - custom_migrate
migrate_plus.migration.ville.yml

Ce qui est intéressant c'est la définition de mapping, on pourrait appliquer des plugins pour le traitement de chaque champ de source avant de l'importer, cela pourrait être :

  • Un plugin de filtre (via callback).
  • Un plugin de mettre une valeur par défaut (default_value)
  • Un plugin de chercher une entité référence dans les contenus du site et de le créer quand il n'existe pas encore. (entity_generate, entity_lookup)
  • Un plugin de chercher un entité référence dans les contenus importés par une migration (migrate_lookup)
  • Et des autres plugins qui se trouvent sur la communauté .

Dans l'exemple ci-dessus, le terme ville a un champ field_departement_de_ville en entité référence vers un terme de département. En plus, les termes de département sont importé par la migration 'depart'. Nous avons donc utilisé le plugin migration_lookup pour gérer cette relation.

Une fois le module est installé. Il est visible depuis le BO (Structure > Migrations) :

Il est possible de lancer l'import via le BO directement. Grâce à Migrate Tools, nous avons la possibilité de gérer tout cela en drush qui est plus pratique, voici ci-dessous les résultats de 2 commandes de migrate lancées, l'un pour import et l'autre pour faire un rollback de l'import :

Conclusion

Comme tout est en entité dans D8, ce sera le même principe quand nous souhaitons importer des nodes, des utilisateurs et etc.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *