Drupal 8 Migrate APIを利用した画像とノードのマイグレーション
 Studio Umi
Studio Umi
2019年になってから、ありがたいことにたくさんのプロジェクトに参加させていただき、ようやく一段落ついたので久しぶりになってしまいましたがブログを書こうと思います。
前回はDrupal 8 Migrate APIを利用したD6データベースのマイグレーションというのを書かせて頂きました。
それ以降、Drupal 6からDrupal 8のマイグレーションだけでなく、Drupal以外のCMSからDrupal 8への移行、CSVファイルからDrupal 8へのコンテンツ登録などをMigrate APIを用いて実装させて頂きましたので、そこで学んだことをアウトプットの意味も込めてブログにさせて頂きます。
事前準備
今回はMigrate APIを用いてCSVインポートを行いたいと思います。
CSVファイルや画像を置く位置について特に決まりはなく、YAMLファイルの書き方で調整できるのでわかりやすいところに置いてください。
ルートディレクトリ直下
└── migration
 |   └── test-node.csv
 |   └──test-image.csv
└──app
    ├── sites
        └── default
             └── files
                 └──2019-08
                 └──migration_image
test-node.csv
title,body,image
テストコンテンツ,こちらはマイグレーションのテストコンテンツです。,test.jpg
test-image.csv
file_name
test.jpg
マイグレーションを実行するのにYAMLファイルの記載の仕方を理解することが必要不可欠です。
大抵のことはYAMLファイルの記載だけでマイグレーションを実行することが出来ます。
今回は画像のマイグレーションとノードのマイグレーションを実行するYAMLファイルを記載してみました。
そこで特に自分が学んだなということをお伝えできればと思います。
YAMLファイル
マイグレーションする際のYAMLの書き方は以下のようになります
画像のマイグレーション
langcode: ja
status: true
dependencies: {  }
id: migration_image
class: null
field_plugin_method: null
cck_plugin_method: null
migration_tags: null
migration_group: null
label: 画像のマイグレーション
source:
  plugin: csv
  path: ../migration/test-image.csv
  header_row_count: 1
  keys:
    - file_name
  constants:
    source_directory: 'public://migration_image'
    destination_directory: 'public://2019-08'
process:
  uid:
    plugin: default_value
    default_value: 1
  filename: file_name
  source_file_path:
    plugin: concat
    delimiter: /
    source:
      - constants/source_directory
      - file_name
  uri:
    plugin: file_copy
    source:
      - '@source_file_path'
      - constants/destination_directory
destination:
  plugin: 'entity:file'
migration_dependencies: null
画像のマイグレーションのYAMLファイルの記載は基本的には上記のような感じになるかと思います。
idなどにつきましてはDrupal8 Migrate API 事始めで記載してくださっていますので、こちらをご参照ください。
  constants:
    source_directory: 'public://migration_image'
    destination_directory: 'public://2019-08'
このconstantsとはConstant valuesに記載されていますが、固定値を設定しています。
今回の例ではマイグレーションさせたい画像をmigration_imageフォルダーに格納しており、それをpublic:/下に置いていることを仮定して話を進めて行きます。
  source_file_path:
    plugin: concat
    delimiter: /
    source:
      - constants/source_directory // マイグレーションしたい画像の実体があるディレクトリ
      - file_name // ファイル名
上記の記載では、source_file_pathキーにpublic://migration_imageとfile_nameを/でconcatした値が入ります。(例: public://migration_image/test.jpg というような感じ)
次に下記のことについてですが、
  uri:
    plugin: file_copy
    source:
      - '@source_file_path'
      - constants/destination_directory
コアのプラグインfile_copyを利用して、'@source_file_path'(上記のsource_file_pathを別の場所で利用したい場合先頭に
@をつける)からconstants/destination_directory(public://2019-08)にファイルがコピーされ、uriはpublic://2019-08/test.jpgとしてファイルエンティティが登録されます。
実際にlsコマンドを使ってapp/sites/default/files/2019-08/ を確認するとtest.jpgが存在していることが分かるかと思います。
DBの方も確認してみましょう。
マイグレーションを実行するとmigrate_map_migration_imageテーブルが新たに作成されているかと思います。
その中身を確認すると、 というようなものが確認できるかと思います。
というようなものが確認できるかと思います。
sourceid1はkeysに指定したもの(今回はfile_name)の値が入ります。
destid1はDrupal 8にファイルエンティティとして登録したので、この場合はfidの値になります。
つまりtest.jpgはDrupal 8ではfid: 6で登録されていますよということが明示されています。
では本当にそうなのかfile_managedテーブルで確認してみましょう。

fid: 6、filename: test.jpg、uri: public://2019-08/test.jpgとなっていることが分かると思います。
destid1はnodeならnid、userならuid、taxonomyならtidということになります。
これが大まかな画像のマイグレーションです。
ノードのマイグレーション
langcode: ja
status: true
dependencies: {  }
id: migration_node
class: null
field_plugin_method: null
cck_plugin_method: null
migration_tags: null
label: ノードのマイグレーション
source:
  plugin: csv
  path: ../migration/test-node.csv
  header_row_count: 1
  delimiter: ','
  keys:
    - title
process:
  type: 
    plugin: default_value
    default_value: article
  langcode:
    plugin: default_value
    default_value: ja
  title: title
  uid: 
    plugin: default_value
    default_value: 1
  body/value: body
  body/format:
    plugin: default_value
    default_value: basic_html
  field_image:
    plugin: migration_lookup
    migration: migration_image
    source: image
destination:
  plugin: 'entity:node'
migration_dependencies:
  optional:
    - migration_image
次に、ノードのマイグレーションですが、基本的なことはDrupal8 Migrate API 事始めで記載してくださっています。ここでご紹介したいのはmigration_lookupについてです。
このpluginは非常に便利ですので、覚えておいて損は無いと思います。
これはどういう機能を提供するプラグインかと言いますと、指定されたmigrationのidから同一の値があるかを検索し、存在すればエンティティ同士を紐付けてくれます。
今回の例でいうと
  field_image:
    plugin: migration_lookup
    migration: migration_image
    source: image
migrationでid(マイグレーション時に設定したid)を記載します。そうすると事前にid: migration_imageで画像のマイグレーションを行っていたのでimageの値と同様のものがmigrate_map_migration_imageのsourceid1にあるか確認し、存在していればそれをdestidに変換してfield_imageにdestid1の値が入ります。
流れは以下のようになります。
CSVのimageヘッダーからtest.jpgという値を取得
                               ↓
migration_imageでsourceid1にtest.jpgというものが存在するかチェック
                               ↓
存在していたので、test.jpgを6という値に変換
                               ↓
field_imageには6という値を入れる。
こうして、テストコンテンツというノードはマイグレーションと同時にfid: 6の画像が紐付けられ、ノードの詳細ページを確認すると、マイグレーションした画像が閲覧出来るかと思います。
以上が画像とノードのマイグレーションの説明になります。
おわり
Migrate APIを利用してみて感じたこと
- pluginなどが豊富なので形さえ覚えられれば、YAMLファイルを書くだけで基本的にはマイグレーション実行できる。
- YAMLファイルだけでは対応できないこともカスタムプラグインを作成すればカバーできることが増えるので応用が効く。
- コントリビュートモジュールなどでのインポートではエンティティの紐付けを行うのは難しいが、migration_lookupを使用することでエンティティ同士の紐付けも同時に出来るのはすごく便利。
- コマンド1つでインポートやロールバックなども可能。
注意点
- sourceid1が重複したものがマイグレーションされていると、migration_lookupを使用した際に意図しない動きになるのでそこは注意が必要になります。重複しないものをキーとして設定することを心がけなくてはいけません。
- migration_lookupは事前にMigrate APIを用いてマイグレーションしているものが対象になるため、事前に登録されている画像やコンテンツなどを紐付ける事はできないため、そこはカスタムプラグインなどを作成して対応する必要があります。
以上Migrate APIを用いた画像やノードのマイグレーションをご紹介させて頂きました。
CSVからのインポートや、他のCMSからDrupal 8への移行などは基本的にMigrate APIを使うことで出来るので、ぜひ利用してみてください。




