現状の課題
PowerCMS XのComponentBlocksで編集表示を「画像」「アセット」「リレーション」とした時、保存されるのは選択したオブジェクトのIDです。ただ、開発環境と本番環境がある場合、両環境でオブジェクトのIDが完全一致していることはまずありません。よって、記事を開発環境でCSVエクスポートし、本番環境でインポートしても、同じ画像が表示できないことになります。
カラムでタイプを「数値」、編集表示を「リレーション」としてアセットを選択できるようにしている場合(例えばog:image用画像)、CSVエクスポート時に保存されているIDを画像パスに変換し、インポート時に画像パスからIDに戻しているようなので、エクスポート・インポートを行っても紐付けは維持されます。ただ、ComponentBlocksは動作基盤が「カスタム編集タイプ」なので、そのような処理が行われていません。
製品として考えられる対策は、
- 通常のカラム同様にIDをパス等に置き変える
- ComponentBlocksでオブジェクトのIDではなくモデル名とUUIDを保存する
等が考えられますが、互換性等も考えるとなかなかすぐに開発の目処が立ちません。カスタム編集タイプが増える度に処理のバリエーションも増えていきそうです。(カスタム編集タイプ毎にクラス化すれば良いか…)
暫定の対策案
プラグインを利用してpre_importコールバックに対する処理を書き、インポート時に自動でオブジェクトIDを置換します。具体的には、ComponentBlocksのデータを解析し、アセット等のオブジェクトIDがあるカラムの値を置き変えを行います。開発環境と本番環境のID突き合わせ方法は手動・自動で色々考えられますが、一番簡易で間違いがなさそうなのはRESTful APIの利用です。
まず、ComponentBlocksのデータ中にあるアセットIDから開発環境のオブジェクトにアクセスし、オブジェクトのUUIDを取得します。そのUUIDを利用して本番環境のオブジェクトを特定しオブジェクトIDを書き換えます。事前にアセットをCSVインポートしておく必要があります。
public function pre_import_entry(&$cb, $app, &$obj, $original) {
$client = ClientBuilder::create()
->setApplicationUrl('https://開発環境のURL/powercmsx/api/index.php');
$block_edit_json_str = $obj->block_edit; // 保存データを取得
if ($block_edit_json_str && $block_edit_json_str !== '[]') {
$block_data = json_decode($block_edit_json_str);
foreach ($block_data as &$block) {
if ($block->type === 'Image') { // ブロックを判定
$dev_env_asset = $client->getObject('asset', 1, (int) $block->asset_id, false, ['id', 'uuid']);
$asset_uuid = $dev_env_asset->uuid; // UUIDを取得
if (!$asset_uuid) continue;
$prod_env_asset = $app->db->model('asset')->load(['uuid' => $asset_uuid], [], 'id');
if (count($prod_env_asset) === 1) {
$block->asset_id = (int) $prod_env_asset[0]->id; // 現環境のオブジェクトIDに置き変え
}
}
}
$obj->block_edit(json_encode($block_data));
}
}
PHPからRESTful APIにアクセスする際は、記事「RESTful APIを用いたユーザー認証とPHP Clientのご紹介」で紹介しているPHP Clientを使用しています。シンプルな例を紹介しましたが、マルチブロックを使用しているとJSONデータを深くたどっていく必要があるため少々手間がかかります。