Edited at
DrupalDay 14

Drupal8 Migrate API 事始め

More than 1 year has passed since last update.

D8_Migrate_API.png

この記事は Drupal Advent Calendar 2016 の14日目の記事です。

D8 サイトに Migrate API を使ったコンテンツのインポート機能を実装した時に調べたことなどを紹介。


Drupal8 はマイグレーションのためのモジュール、Migrate モジュール (migrate) がコアに同梱されている。

Migrate モジュールが提供する Migrate API (と、拡張モジュール) を使うことで、例えば以下のようなことが可能になる。


  • D6、D7 のコンテンツを D8 に移行

  • CSV のコンテンツを D8 にインポート

  • プラグインを実装して独自形式のコンテンツを D8 にインポート

など

Migrate モジュールは API を提供するのみで、実際にマイグレーションを行うためには用途に合わせて他のモジュールを組み合わせる必要がある。


Migrate API でマイグレーションを行うまでの流れ


  1. Migrate モジュールを有効化

  2. 最低限必要な contributed モジュールをインストール



  3. マイグレーションの内容に合わせて必要なモジュールを選んでインストール



  4. マイグレーション構成 (configuration) を YAML で作ってインポート

  5. drush migrate-import コマンドでマイグレーション実行


各モジュールの概要


Migrate (migrate)


  • コアモジュール (まだ Experimental でデフォルトでは無効状態)

  • Migrate API -- マイグレーション機能の基盤 を提供


    • プラグイン機構 + 基本的なプラグイン

    • マイグレーションの進捗管理

    • 元データと対応する D8 エンティティの対応付け

    • などなど



  • 管理画面の UI、drush コマンドなどは無い

  • マイグレーションを実行するには他のモジュールが必要


Migrate Plus (migrate_plus)


  • いろいろ追加機能が含まれる (よくわかってない)

  • configuration、source プラグインなどのサンプルもある

  • Migrate Tools を使うのに必要


Migrate Tools (migrate_tools)


  • マイグレーションを実行できる drush コマンドを提供



    • $ drush mi (migrate-import: インポート実行)


    • $ drush ms (migrate-status: ステータス確認)

    • その他ロールバック、エラーメッセージの確認コマンドなど



  • 管理画面からマイグレーションを一覧、管理できる


    • ただし管理画面では実行は行えないので drush コマンドを使う




Migrate API の仕組みとプラグイン

必要なプラグイン (を提供しているモジュール) を選んで configuration を作るためには、Migrate API によるマイグレーションの仕組みを理解する必要がある。

マイグレーションは以下の3種類のプラグインを組み合わせて行う。


  • Migrate source

  • Migrate process

  • Migrate destination

これらの組み合わせとデータの流れを表したのが冒頭にも貼ったこちらの図。

D8_Migrate_API.png

以下のような流れで、読み込まれた元データが D8 のエンティティとして保存される。



  1. source plugin が元データを読み込み


    • source はマイグレーションに1つのみ存在

    • 元データの形式に対応したプラグインを選ぶ




  2. process plugin が読み込まれたデータを変換、destination のフィールドにマッピング


    • process は複数使う

    • ひとつのフィールドの値を複数の process plugin で順に変換することもできる

    • ただの固定値を destination に渡す事も可




  3. destination plugin がマッピングされたデータを D8 エンティティとして保存


    • destination も source と同じく1つだけ使用

    • 保存したい形式に対応したプラグインを選ぶ



このように3種類のプラグインを組み合わせることで、要求に応じた柔軟なマイグレーションができるようになっている。


CSV インポートチュートリアル

Drupal.org に Migrate Source CSV プラグインを使って CSV を D8 の article にインポートするチュートリアルがある。

Using the Migrate Source CSV plugin | Drupal.org

CSV は以下のようなもの。


acme_articles.csv

Id2,title,body 

1,title 1,some body text 1
2,title 2,some body text 2
3,title 3,some body text 3

これをインポートするマイグレーションの YAML。


migrate_plus.migration.basics.yml

id: basics

label: Import articles
migration_groups:
- ACME import

source:
plugin: csv
path: '/path/to/file/acme_articles.csv'
header_row_count: 1
keys:
- Id2

process:
title: title
body: body
type:
plugin: default_value
default_value: article

destination:
plugin: entity:node



実行方法


1. モジュールをインストール


  • Migrate

  • Migrate Plus

  • Migrate Tools

  • Migrate Source CSV


2. YAML をインポート

上記の YAML をインポートする。

管理画面からインポートする場合は admin/config/development/configuration/single/import

構成タイプで Migration を選択し、YAML を貼り付けてインポートする。

config_devel をインストールすれば drush からもインポートできる。

YAML をいじりつつ試す場合は drush からインポートする方が簡単だと思う。

// ファイル名は migrate_plus.migration.<migration_id>.yml の形式になっている必要がある。

// YAML を変更して上書き保存する場合も同様のコマンド。
$ drush cdi1 path/to/migrate_plus.migration.basics.yml

YAML に問題がない場合は、以下の URL でインポートされる・された件数などを確認できる。

admin/structure/migrate/manage/misumi/migrations

進捗などのステータスは drush コマンドでも確認できる。

// migrate-status (ms)

$ drush ms
Group: Default (default) 状態 Total Imported Unprocessed Last imported
basics Idle 3 0 3


3. 実行

drush migrate-import (mi) コマンドでマイグレーションを実行する。

$ drush mi basics

Processed 3 items (3 created, 0 updated, 0 failed, 0 ignored) - done with 'basics'

// エラーで取り込めないレコードがあった場合は migrate-messages (mmsg) コマンドでエラー内容を確認できる
$ drush mmsg basics

// CSV を修正して再インポートする時は --update を付けて migrate-import する。
// 既にインポート済みのレコードは追加されず、既存のエンティティが更新される。
$ drush mi --update basics

// ※ キーとなる値 (ここでは Id2 カラムの値) を変更すると別レコードと認識されるのでエンティティも新しく追加される。


YAML の各行の意味


id、label

id: basics

label: Import articles

このidを drush migrate-* の引数に指定する。


migration_gorups

migration_groups:

- ACME import

グループを指定しておくと、グループのマイグレーションを一括で実行することもできる。


source

source:

plugin: csv
path: '/path/to/file/acme_articles.csv'
header_row_count: 1
keys:
- Id2

使用する source plugin の指定とそのパラメータ。

keys で指定したカラムの値がその行のキーとして扱われ、インポートされたコンテンツの ID (この場合は article の nid) と紐付けられる。

初回インポート時は新しい article が作成されるが、2回目以降に実行するとマッピングされた既存の article が更新される。

更新時は --update を付けて drush mi --update <migration_id> を実行する。


process

process:

title: title
body: body
type:
plugin: default_value
default_value: article

読み込まれたデータの変換と destination へのマッピング。

title: title の左側 (キー) が destination のフィールド名、右側が source のフィールド名になっている。

destination の title と body (つまり article の title、body プロパティ) には、CSV の同名のフィールドがそのまま保存される。

type フィールドは default_value プラグインを使って固定値 ("article") を設定している。

上記で使用している default_value の他にも十数種類のプラグインが存在している。

https://www.drupal.org/docs/8/api/migrate-api/migrate-process

process の形式は以下のパターンがある。

process:

<destination_field_1>: <source_field>
<destination_field_2>:
- plugin: <process_plugin_id>
- <parameter1>
- <parameter2...>
<destination_field_3>:
-
plugin: <process_plugin_1>
<parameter>
-
plugin: <process_plugin_2>

ひとつのフィールドを複数の process で処理する場合は3つ目の形式で書く。

ちなみに1つ目の書き方は get plugin 用の省略形。


destination

destination:

plugin: entity:node

process でマッピングされたデータを保存する destination plugin の指定。

node として保存したいので entity:node プラグインを使う。

最終的には、CSV の title、body カラム、固定値の type = "article" が node に保存される。

CSV の Id2 は 作成された node とのマッピングに使用されるだけで node のフィールドとしては保存されない。


参考資料

Drupal.org のドキュメントには目を通しておくべきだと思う。 (多いけど)

どのようなプラグインがあるのかを知るのと、プラグインの使い方も参考になる。


YAML の書き方、プラグインの作り方の参考資料

Migrate Plus の example モジュール (migrate_example、migrate_example_advanced) が参考になる。

source プラグインの実装も含まれている。

ちなみに、process で独自の変換処理を書きたくなった時は callback プラグインを使うとお手軽。

モジュールに関数を定義しておくだけで YAML から使えるようになる。

プラグインは役割が細かく分かれているおかげで、それぞれの実装はシンプルなものになっているので、既存のプラグインの実装を読むのが理解も早いと思う。


Migrate API 所感

今回 D8 サイトに実装したインポート機能は、元データが CSV (メタ情報) + 静的ファイル (body データ) に分離しているというちょっと特殊な形だったため、Migrate API でやるか、完全に独自のインポートモジュールを作成するかで迷ったが、あまり迷っている時間もなかったため Migrate API を使った。

結果的には良い選択だったと思う。

独自実装と比較すると、Migrate API には以下のようなメリットがあると思う。


  • プラグインが分離しているおかげで、どのような形式のデータにも対応できる


    • 今回は CSV と静的ファイルを読み込む source プラグインを作って対応した



  • 既存のプラグインと組み合わせられるので実装の手間が省ける

  • 元データとエンティティの紐付けを管理してくれる


    • 元データを編集して更新、などが簡単にできる (キーとなる値は適切に選ぶ必要がある)



  • 進捗を管理してくれる

  • (試してないが) インポートの取り消しもできるらしい

  • 覚えておくと色々応用が効きそう


    • 大抵の事は YAML を書くだけで実現できる

    • 自動テストでテストデータを入れるのにも使えそう