私が現在管理するプロジェクトのほとんどは、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の結果と見比べて、手動での調整が必要となりそうです。しかし、かなりの部分を作成してくれるので十分使えそうです。