データ移行プラグインで対応していないプラグインの移行方法カスタマイズ

EC-CUBE Advent Calendar 2021 15日目の記事です。

EC-CUBE2系や3系からデータ移行する場合、お手軽な方法としてデータ移行プラグインというプラグインが存在しています。

www.ec-cube.net

このプラグインは便利なのですが、

が移行対象となっていません。こちらの移行対応方法を説明します。現在公開されている最新のプラグインバージョン4.1.0を対象に説明します。

今回は2系からのデータ移行を対象としているのでご注意ください。

対象となるプラグインをインストール

今回利用したいプラグインを先にインストールしてください。対象となるプラグインの対比は以下となります。

移行元テーブル 利用プラグイン
dtb_maker メーカープラグイン
dtb_best_products おすすめ商品管理プラグイン
dtb_review 商品レビュープラグイン
dtb_recommend_products 関連商品プラグイン

※利用されていない方はインストールする必要はありません。

また、dtb_news(新着情報)については既存機能のため、プラグインのインストールは不要です。

データ移行プラグインのカスタマイズ

オーナーズストアからデータ移行プラグインをインストール後、以下のファイルに対してカスタマイズを行います。

  • app/Plugin/DataMigration4/Controller/Admin/ConfigController.php
<?php
~
~
~
// 会員・受注のみ移行
if ($form['customer_order_only']->getData()) {
    $this->saveCustomerAndOrder($em, $csvDir);
// 全データ移行
} else {
    $this->saveCustomer($em, $csvDir);
    $this->saveProduct($em, $csvDir);
    $this->saveOrder($em, $csvDir);
    $this->saveOther($em, $csvDir);
    $this->savePlugin($em, $csvDir);
}
~
~
~

138行目にある// 会員・受注のみ移行にのif文に対して$this->saveOther($em, $csvDir)$this->savePlugin($em, $csvDir)という関数を追加します。その後、以下の内容を記述します。

  • app/Plugin/DataMigration4/Controller/Admin/ConfigController.php
<?php
~
~
~
private function saveOther($em, $csvDir)
{
    // プラグイン系
    $em->beginTransaction();

    $platform = $em->getDatabasePlatform()->getName();

    if ($platform == 'mysql') {
        $em->exec('SET FOREIGN_KEY_CHECKS = 0;');
        $em->exec("SET SESSION sql_mode = 'NO_AUTO_VALUE_ON_ZERO'"); // STRICT_TRANS_TABLESを無効にする。
    } else {
        $em->exec('SET session_replication_role = replica;'); // need super user
    }

    $this->saveToOther($em, $csvDir, 'dtb_news');

    if ($platform == 'mysql') {
        $em->exec('SET FOREIGN_KEY_CHECKS = 1;');
    } else {
        $this->setIdSeq($em, 'dtb_news');
    }

    $em->commit();

    $this->addSuccess('その他データを登録しました。', 'admin');
}

private function saveToOther($em, $tmpDir, $csvName, $tableName = null, $allow_zero = false, $i = 1)
{
    $tableName = ($tableName) ? $tableName : $csvName;
    $this->resetTable($em, $tableName);

    if (file_exists($tmpDir.$csvName.'.csv') == false) {
        // 無視する
        //$this->addDanger($csvName.'.csv が見つかりませんでした' , 'admin');
        return;
    }
    if (filesize($tmpDir.$csvName.'.csv') == 0) {
        // 無視する
        return;
    }

    if (($handle = fopen($tmpDir.$csvName.'.csv', 'r')) !== false) {
        // 文字コード問題が起きる可能性が高いので後で調整が必要になると思う
        $key = fgetcsv($handle);
        $keySize = count($key);

        $columns = $em->getSchemaManager()->listTableColumns($tableName);
        foreach ($columns as $column) {
            $listTableColumns[] = $column->getName();
        }

        $builder = new BulkInsertQuery($em, $tableName, 20);
        $builder->setColumns($listTableColumns);

        $batchSize = 20;

        while (($row = fgetcsv($handle)) !== false) {
            $value = [];

            // 1行目をkeyとした配列を作る
            $data = array_combine($key, $row);

            // Schemaにあわせた配列を作成する
            foreach ($listTableColumns as $column) {
                if ($column == 'id' && $tableName == 'dtb_news') {
                    $value[$column] = $data['news_id'];
                } elseif ($column == 'name') {
                    $value[$column] = $data['name'];
                } elseif ($column == 'product_id') {
                    $value[$column] = $data['product_id'];
                } elseif ($column == 'publish_date') {
                    $value[$column] = $data['news_date'];
                } elseif ($column == 'title' && $tableName == 'dtb_news') {
                    $value[$column] = isset($data['news_title'])
                        ? mb_substr($data['news_title'], 0, 255)
                        : null;
                } elseif ($column == 'description') {
                    $value[$column] = $data['news_comment'];
                } elseif ($column == 'url') {
                    $value[$column] = empty($data['news_url']) ? null : $data['news_url'];
                } elseif ($column == 'link_method') {
                    $value[$column] = empty($data['link_method']) ? null : $data['link_method'];
                } elseif ($column == 'eyecatch_image') {
                    $value[$column] = isset($data['main_large_image'])
                        ? $data['main_large_image']
                        : null;
                } elseif ($column == 'creator_id') {
                    $value[$column] = !empty($data[$column]) ? $data[$column] : 1;
                } elseif ($column == 'sort_no') {
                    $value[$column] = $data['rank'];
                } elseif ($column == 'visible') {
                    $value[$column] = ($data['del_flg']) ? 0 : 1;
                } elseif ($column == 'create_date' || $column == 'update_date') {
                    $value[$column] = (isset($data[$column]) && $data[$column] != '0000-00-00 00:00:00') ? self::convertTz($data[$column]) : date('Y-m-d H:i:s');
                } elseif ($column == 'discriminator_type') {
                    $search = ['dtb_', 'mtb_', 'plg_', '_'];
                    $value[$column] = str_replace($search, '', $tableName);
                } elseif ($allow_zero) {
                    $value[$column] = isset($data[$column]) ? $data[$column] : null;
                } else {
                    $value[$column] = !empty($data[$column]) ? $data[$column] : null;
                }
            }

            $builder->setValues($value);

            if (($i % $batchSize) === 0) {
                $builder->execute();
            }

            $i++;
        }

        if (count($builder->getValues()) > 0) {
            $builder->execute();
        }

        fclose($handle);

        return $i; // indexを返す
    }
}


private function savePlugin($em, $csvDir)
{
    // プラグイン系
    $em->beginTransaction();

    $platform = $em->getDatabasePlatform()->getName();

    if ($platform == 'mysql') {
        $em->exec('SET FOREIGN_KEY_CHECKS = 0;');
        $em->exec("SET SESSION sql_mode = 'NO_AUTO_VALUE_ON_ZERO'"); // STRICT_TRANS_TABLESを無効にする。
    } else {
        $em->exec('SET session_replication_role = replica;'); // need super user
    }

    $this->saveToPlugin($em, $csvDir, 'dtb_maker', 'plg_maker');
    $this->saveToPlugin($em, $csvDir, 'dtb_best_products', 'plg_recommend_product');
    $this->saveToPlugin($em, $csvDir, 'dtb_review', 'plg_product_review');
    $this->saveToPlugin($em, $csvDir, 'dtb_recommend_products', 'plg_related_product');

    if ($platform == 'mysql') {
        $em->exec('SET FOREIGN_KEY_CHECKS = 1;');
    } else {
        $this->setIdSeq($em, 'plg_maker');
        $this->setIdSeq($em, 'plg_recommend_product');
        $this->setIdSeq($em, 'plg_product_review');
        $this->setIdSeq($em, 'plg_related_product');
    }

    $em->commit();

    $this->addSuccess('各種プラグインデータを登録しました。', 'admin');
}

private function saveToPlugin($em, $tmpDir, $csvName, $tableName = null, $allow_zero = false, $i = 1)
{
    $tableName = ($tableName) ? $tableName : $csvName;
    $this->resetTable($em, $tableName);

    if (file_exists($tmpDir.$csvName.'.csv') == false) {
        // 無視する
        //$this->addDanger($csvName.'.csv が見つかりませんでした' , 'admin');
        return;
    }
    if (filesize($tmpDir.$csvName.'.csv') == 0) {
        // 無視する
        return;
    }

    if (($handle = fopen($tmpDir.$csvName.'.csv', 'r')) !== false) {
        // 文字コード問題が起きる可能性が高いので後で調整が必要になると思う
        $key = fgetcsv($handle);
        $keySize = count($key);

        $columns = $em->getSchemaManager()->listTableColumns($tableName);
        foreach ($columns as $column) {
            $listTableColumns[] = $column->getName();
        }

        $builder = new BulkInsertQuery($em, $tableName, 20);
        $builder->setColumns($listTableColumns);

        $batchSize = 20;

        while (($row = fgetcsv($handle)) !== false) {
            $value = [];

            // 1行目をkeyとした配列を作る
            $data = array_combine($key, $row);

            // Schemaにあわせた配列を作成する
            foreach ($listTableColumns as $column) {
                if ($column == 'id' && $tableName == 'plg_maker') {
                    $value[$column] = $data['maker_id'];
                } elseif ($column == 'recommend_id' && $tableName == 'plg_recommend_product') {
                    $value[$column] = $data['best_id'];
                } elseif ($column == 'id' && $tableName == 'plg_product_review') {
                    $value[$column] = $data['review_id'];
                    // } elseif ($column == 'id' && $tableName == 'plg_related_product') {
                    //     $value[$column] = $data['recommend_product_id'];
                } elseif ($column == 'name') {
                    $value[$column] = $data['name'];
                } elseif ($column == 'product_id') {
                    $value[$column] = $data['product_id'];
                } elseif ($column == 'child_product_id') {
                    $value[$column] = $data['recommend_product_id'];
                } elseif ($column == 'comment') {
                    $value[$column] = $data['comment'];
                } elseif ($column == 'sex_id') {
                    $value[$column] = empty($data['sex']) ? null : $data['sex'];
                } elseif ($column == 'customer_id') {
                    $value[$column] = empty($data['customer_id']) ? null : $data['customer_id'];
                } elseif ($column == 'status_id') {
                    $value[$column] = empty($data['status']) ? null : $data['status'];
                } elseif ($column == 'reviewer_name') {
                    $value[$column] = empty($data['reviewer_name']) ? null : $data['reviewer_name'];
                } elseif ($column == 'reviewer_url') {
                    $value[$column] = empty($data['reviewer_url']) ? null : $data['reviewer_url'];
                } elseif ($column == 'title' && $tableName == 'plg_product_review') {
                    $value[$column] = isset($data['title'])
                        ? mb_substr($data['title'], 0, 50)
                        : null;
                } elseif ($column == 'recommend_level') {
                    $value[$column] = empty($data['recommend_level']) ? null : $data['recommend_level'];
                } elseif ($column == 'content') {
                    $value[$column] = isset($data['comment'])
                        ? mb_substr($data['comment'], 0, 3999)
                        : null;
                } elseif ($column == 'sort_no') {
                    $value[$column] = $data['rank'];
                } elseif ($column == 'visible') {
                    $value[$column] = ($data['del_flg']) ? 0 : 1;
                } elseif ($column == 'create_date' || $column == 'update_date') {
                    $value[$column] = (isset($data[$column]) && $data[$column] != '0000-00-00 00:00:00') ? self::convertTz($data[$column]) : date('Y-m-d H:i:s');
                } elseif ($column == 'discriminator_type') {
                    $search = ['dtb_', 'mtb_', 'plg_', '_'];
                    $value[$column] = str_replace($search, '', $tableName);
                } elseif ($allow_zero) {
                    $value[$column] = isset($data[$column]) ? $data[$column] : null;
                } else {
                    $value[$column] = !empty($data[$column]) ? $data[$column] : null;
                }
            }

            $builder->setValues($value);

            if (($i % $batchSize) === 0) {
                $builder->execute();
            }

            $i++;
        }

        if (count($builder->getValues()) > 0) {
            $builder->execute();
        }

        fclose($handle);

        return $i; // indexを返す
    }
}

一部不要なコードが含まれていますが、上記関数を追加することでデータ移行が可能となります。 3系からの移行については少しカスタマイズする事で対応可能になると思います。

以上で各種必要となるデータが移行されるようになります。もし他のテーブルもデータ移行を行いたい方はカスタマイズ内容は簡単なので適宜修正して試してください。