【Laravel】コマンドアプリケーションで行うデータ移行

さなぽんです。社内ではマッチングサービスを中心とした受託案件のお仕事をしています。
Twitterは例のサングラススパムに乗っ取られて凍結されてしまいました。。。とほほ。


お仕事はCakePHP2や3を中心に、最近はLaravelも使い始めました。
弊社サービス「ITプロパートナーズ」に登録いただいたエンジニアの方とチームで動きディレクション中心に行ったり
自分ひとりであのフレームワークは…こっちだと…などと手を動かしたりもしています。


お客様からシステムのリプレイス案件のお声掛けをいただくことも多々あります。
本当にありがたい限りです。

リプレイスするにあたり、サーバーや言語のバージョンアップ、フレームワークを変更して再コーディングを行う以外に
データベースの再設計を検討することもよくあるお話です。


再設計をして、いざ、データ移行!となるのですが、これが思いの外面倒な作業となる事が多々あります。
SQLを用意し作業をしていると、条件分岐やループはPL/SQLだと便利なのにな、、、なんて思ってしまうこともありますね。


そこで今日紹介するのは、コマンドライン処理を使ってデータ移行を行うやり方です。
この仕組みもITプロパートナーズに登録いただいたエンジニアさんが作っていただいたものになります。


まずはクラスを作成します。以下のコマンドを実行してみましよう。

$ php artisan make:command Migrate

実行後、app/Console/Commands配下に以下のクラスが作成されているはずです。

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class Migrate extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'command:name';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //
    }
}

$signatureには実行時のコマンド名、$descriptionにはコマンドの説明をそれぞれ設定します。
例えば以下のように設定をします。

    protected $signature = 'migrate:exec';
    protected $description = 'データ移行実行';

その後、artisan listを実行すると、、、

$ php artisan list

Laravel Framework 5.6.38

Usage:
  command [options] [arguments]

… 略

 migrate
  migrate:exec           データ移行実行

表示されました!
これで php artisan migrate:exec とコマンドを叩くとMigrateクラスが実行されることになります。


引き続き、処理を書いていきましょう!
処理は handle() に記述していきます。

<?php

namespace App\Console\Commands;

use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

… 略

public function handle()
{
    DB::transaction(function () {
        $this->migrate();
        $this->seed();
    });
    return true;
}

private function migrate()
{
    $this->progress('dropTables');
    $this->progress('callMigrate');
}

private function progress($func, $message = null)
{
    $this->_bar->setMessage($message ?? snake_case($func, ' '));
    $this->$func();
    $this->_bar->advance();
}

private function dropTables()
{
    foreach (\DB::select('SHOW TABLES') as $table) {
        $column_name = 'Tables_in_' . \DB::connection('')->getDatabaseName();
        \DB::statement('DROP TABLE IF EXISTS `' . $table->$column_name . '`');
    }
}

private function callMigrate()
{
    \Artisan::call('migrate');
}

private function seed()
{
    foreach ($this->getSeedFunc() as $item) {
        $this->progress($item);
    }
}

private function getSeedFunc()
{
    return [
        'seedCompany',
    ];
}

private function seedCompany()
{
    foreach (DB::connection('old_db')->table('company')->select()->cursor() as $item) {
        DB::table('companies')->insert([
            'id'                 => $item->id,
            'name'           => $item->name,
            'zipcode'       => $item->zipcode,
            'address'       => $item->address,
            'tel'                 => $item->tel,
        ]);
    }
}

一気に書いてしまいました笑
旧DBのcompanyテーブルから新DBのcompaniesテーブルにデータを移行します。
この中でif文などの制御はもちろん、複雑な処理も行う事ができます。

また、処理の中で旧DBからデータを取得しますので、 config/database.php ファイルに旧DBの情報も記述します。

'old_db' => [
    'driver' => 'mysql',
    'host' => env('DB_OLD_HOST', '127.0.0.1'),
    'port' => env('DB_OLD_PORT', '3306'),
    'database' => env('DB_OLD_DATABASE', 'forge'),
    'username' => env('DB_OLDP_USERNAME', 'forge'),
    'password' => env('DB_OLD_PASSWORD', ''),
    'unix_socket' => env('DB_OLD_SOCKET', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],

DB_OLD_xxx の内容は .env ファイルにて設定します。

これでひとまず動くかと思いますので、是非試してみてください。


ここからは宣伝です。
12月1日(土)に「起業家」と「ITプロフェッショナル」の出会いを創出する
ビジネスコンテスト『HATCH』を行います。
観覧者を大募集していますので、興味のある方は是非お越しください!

itpro.connpass.com


12月18日(火)にSIerやSESからWEBエンジニアへのキャリアチェンジをテーマにしたイベントを開催します。
ワタクシが司会をする予定です。こちらもよろしくお願いします。

itpropartners.connpass.com