私が現在管理するプロジェクトのほとんどは、Laravelのフレームワーク採用以前から存在したphpのプロジェクトです。嬉しいことにお客様から移行の機会を与えられて、ほとんどLaravelに書き換えることができました。しかし、それらのプロジェクトのDBの管理には、Laravelのmigrationを使用していません。私が開発したオンラインのツールが生成するSQLファイルでDBの変更を行っています。最近になって、プロジェクトのデータベーステストを行う必要が出て、migrationのファイルを用意しなければなくなりました。

どうして、migrationのファイルが必要?

今までは、dbunitなるものを使用してデータベーステストを行っていましたが、これが去年に作者(phpunitの作者でもある)の意向で開発が停止となりました。それゆえに、テストにおいてLaravelのRefreshDatabaseトレイトの使用に変えていくことが突然に必要になったわけです。

RefreshDatabaseは、毎回のテストの実行において、

$ php artisan migrate:fresh

の実行と同様に、migrationファイルで定義されたDBのテーブルをすべて削除し、再度一からそれらを作成します。つまり、データベースのテーブルをすべてゼロレコードの状態としてくれます。それゆえに、既存のDBのすべてのテーブルのmigrationを作成する必要があるのです。

migrationファイル自動生成ツール

既存のDBからmigrationファイルを作成するツールはないかと、探した結果、以下のツールが出てきました。

https://github.com/Xethron/migrations-generator

ツールのインストールには、

$ composer require --dev "xethron/migrations-generator"

をコマンドラインで実行します。

migrationファイルを作成するには、artisanの実行となります。laravel 5.8で新規のプロジェクトを作成して実行してみました。

$ php artisan migrate:generate
Using connection: mysql

Generating migrations for: password_resets, users

 Do you want to log these migrations in the migrations table? [Y/n] :
 > y

 Next Batch Number is: 2. We recommend using Batch Number 0 so that it becomes the "first" migration [Default: 0] :
 > 2

Setting up Tables and Index Migrations
Created: /vol1/usr/www/repos/repos/l58-new/database/migrations/2020_01_08_191742_create_password_resets_table.php
Created: /vol1/usr/www/repos/repos/l58-new/database/migrations/2020_01_08_191742_create_users_table.php

Setting up Foreign Key Migrations


Finished!

上の実行においては、2つ質問が尋ねられます。

最初は、migrationsのDBテーブルにログを作成するか?
2番目は、そのログにおいてのバッチ番号をなんとするか?

上では、yと2と答えたところ、migrationsのデータは以下のようになりました。

mysql> select * from migrations;
+----+------------------------------------------------+-------+
| id | migration                                      | batch |
+----+------------------------------------------------+-------+
|  1 | 2014_10_12_000000_create_users_table           |     1 |
|  2 | 2014_10_12_100000_create_password_resets_table |     1 |
|  3 | 2020_01_08_191742_create_password_resets_table |     2 |
|  4 | 2020_01_08_191742_create_users_table           |     2 |
+----+------------------------------------------------+-------+
4 rows in set (0.00 sec)

すでに、php artisan migrateが実行されていたので、最初の2つのレコードはそのときに生成されていたものです。これらはLaraelのデフォルトのmigrationファイルです。

一方、generateで生成されたのは次の2つのレコードですが、見ての通り既存のものと重複となってしまいました。既存のDBをもとに1からDBテーブルを作成するという目的では、generate実行の前にmigrationsテーブルを空としたほうが良さそうですね。

さて、生成されたものと、デフォルトのmigrationファイルを比べてみましょう。


use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class CreateUsersTable extends Migration {

	/**
	 * Run the migrations.
	 *
	 * @return void
	 */
	public function up()
	{
		Schema::create('users', function(Blueprint $table)
		{
			$table->bigInteger('id', true)->unsigned();
			$table->string('name');
			$table->string('email')->unique();
			$table->dateTime('email_verified_at')->nullable();
			$table->string('password');
			$table->string('remember_token', 100)->nullable();
			$table->timestamps();
		});
	}


	/**
	 * Reverse the migrations.
	 *
	 * @return void
	 */
	public function down()
	{
		Schema::drop('users');
	}

}

やや違いがありますね。例えば、email_verified_atの定義、なぜかtimestampからdateTimeとなっています。
また、bigIncrementやrememberTokenに対応するフィールドも生成では変わっています。しかし、これらは、実行されるDBテーブルでは同じとなります。

ということで、mysqldumpの結果と見比べて、手動での調整が必要となりそうです。しかし、かなりの部分を作成してくれるので十分使えそうです。

By khino