新しくv4.0をリリースしたので、解説記事をリニューアルしました!
Laravel × Dacapo データベースマイグレーションサポートツールの使い方
Laravel Advent Calendar 2019 - Qiita の 1日目 の記事です。
去年(Laravel Advent Calendar 2018)の記事
実際に弊社の実務でDacapoを運用し、他の会社さんから使ってもらったフィードバックを活かして去年より大幅アップデートしてます。
リポジトリ
何をするツールか
Laravelのマイグレーションファイル生成をサポートするライブラリです。
困っていること
- 開発中はテーブル構成を変更する頻度が高い
- 不要なマイグレーションファイルが増える
- 似た構成のテーブルをコピペして作るにも変更箇所が多い
- ファイル名、クラス名、テーブル名を直すのがめんどう...
- 手動で直すとオートローダーがバグる
- 最新のテーブル構成は実際のDBを見ないと分からない
- インデックスや外部キーが入るとさらにややこしく...
ダカーポ開発の流れ
-
database/schemas/*.yml
テーブル定義をymlファイルに記述する- 「スキーマ」と呼びます。
-
php artisan dacapo
マイグレーションファイルを生成&マイグレーション実行
スキーマを変更した場合は必ず、 php artisan dacapo
して、マイグレーションファイルを生成し直す流れになります。
ダカーポの注意・留意事項
-
特性上、プロジェクトの初期フェーズに使用するライブラリです。
-
運用フェーズに入ったらダカーポはアンインストールし、通常のマイグレーション運用に戻します。
-
本番のデータが全部消えてしまうので...。。
-
schema.yml の記述を元に常に最新のマイグレーションファイルを生成します。(上書き)
-
php artisan migrate:fresh
で全テーブルの削除し、マイグレーションを実行する運用です。
生成されるマイグレーションファイルの種類
-
1970_01_01_000000_*.php
テーブル作成のマイグレーションファイル -
1970_01_01_000001_*.php
一意制約、インデックスのマイグレーションファイル -
1970_01_01_000002_*.php
外部キー制約のマイグレーションファイル
マイグレーションファイルが database/migrations
に出力されます。
マイグレーションはファイル名順に実行されます。
テーブルを作成したあとに制約を貼るようにしています。
整理整頓されたマイグレーションファイルが出力されます☺️
インストール手順
$ composer require --dev ucan-lab/laravel-dacapo
Laravelの初期マイグレーションを生成(任意)
Laravelでは、標準で下記の3テーブルのマイグレーションが用意されています。
- users
- password_resets
- failed_jobs
これと同じ構成のスキーマファイルを生成するダカーポコマンドを用意しました。
dacapo:init コマンド
$ php artisan dacapo:init
database/schemas/default.yml
ファイルが生成されます。
users:
columns:
id: bigIncrements
name: string
email:
type: string
unique:
email_verified_at:
type: timestamp
nullable:
password: string
rememberToken:
timestamps:
password_resets:
columns:
email:
type: string
index:
token: string
created_at:
type: timestamp
nullable:
failed_jobs:
columns:
id:
uuid:
type: string
unique:
connection: text
queue: text
payload: longText
exception: longText
failed_at:
type: timestamp
useCurrent:
personal_access_tokens:
columns:
id:
tokenable: morphs
name: string
token:
type: string
args: 64
unique:
abilities:
type: text
nullable:
last_used_at:
type: timestamp
nullable
timestamps:
dacap コマンド
先ほどの dacapo:init
で生成した default.yml
がある状態で dacapo
を実行します。
$ php artisan dacapo
1970_01_01_000000_create_users_table.php
<?php
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');
}
}
1970_01_01_000000_create_password_resets_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePasswordResetsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('password_resets', function (Blueprint $table) {
$table->string('email')->index();
$table->string('token');
$table->timestamp('created_at')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('password_resets');
}
}
1970_01_01_000000_create_failed_jobs_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateFailedJobsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('failed_jobs', function (Blueprint $table) {
$table->bigIncrements('id');
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('failed_jobs');
}
}
このように最小限のテーブル構成をymlに記述すればマイグレーションファイルを生成してくれます。
dacapo オプション
# seedオプション
$ php artisan dacapo --seed
# no-migrateオプション
$ php artisan dacapo --no-migrate
マイグレーション生成&マイグレーション実行&シーディング実行をオプション付けて一緒に実行できます。
スキーマの書き方
-
database/schemas/*.yml
と配置します。 - 複数ファイルを配置できます。
スキーマのフォーマット
テーブル名:
columns:
カラム名: カラムタイプ
カラム名:
type: カラムタイプ
args: カラムタイプの引数
カラムタイプの指定
テーブルを構築する時に使用する様々なカラムタイプを指定できます。
how_to_column_types:
columns:
id: bigIncrements
name1: string
name2:
type: string
name3:
type: string
args: 100
name4:
type: string
args: [100]
amount1: decimal
amount2:
type: decimal
amount3:
type: decimal
args: 8
amount4:
type: decimal
args: [8]
amount5:
type: decimal
args: [8, 2]
level:
type: enum
args: ['easy', 'hard']
timestamps:
# timestamps: 0
# timestamps: [0]
softDeletes:
# softDeletes: 'deleted_at'
# softDeletes: ['deleted_at']
# softDeletes: ['deleted_at', 0]
database/migrations/1970_01_01_000000_create_how_to_column_types_table.php
public function up()
{
Schema::create('how_to_column_types', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name1');
$table->string('name2');
$table->string('name3', 100);
$table->string('name4', 100);
$table->decimal('amount1');
$table->decimal('amount2');
$table->decimal('amount3', 8);
$table->decimal('amount4', 8);
$table->decimal('amount5', 8, 2);
$table->enum('level', ['easy', 'hard']);
$table->timestamps();
// $table->timestamps(0); // timestamps: 0
// $table->timestamps(0); // timestamps: [0]
$table->softDeletes();
// $table->softDeletes('deleted_at'); // softDeletes: 'deleted_at'
// $table->softDeletes('deleted_at'); // softDeletes: ['deleted_at']
// $table->softDeletes('deleted_at', 0); // softDeletes: ['deleted_at', 0]
});
}
カラム修飾子
カラム修飾子 |
Laravel 6.x データベース:マイグレーション
上記のカラムタイプに付け加え、カラムを追加するときに使用できる様々な修飾子もあります。たとえばカラムを「NULL値設定可能(nullable
)」にしたい場合は、nullable
メソッドを使います。
また、ダカーポの特性上 after
, first
のカラム修飾子は使用できません。
how_to_column_modifiers:
columns:
id:
type: integer
autoIncrement: true
name:
type: string
charset: utf8
collation: utf8_unicode_ci
comment: my comment
default: test value
nullable: true
price:
type: integer
unsigned: true
count:
type: integer
unsigned: true
total_stored:
type: integer
storedAs: price * count
total_virtual:
type: integer
virtualAs: price * count
total_generated:
type: integer
generatedAs: price * count
created_at:
type: timestamp
useCurrent: true
seq:
type: integer
always: true
database/migrations/1970_01_01_000000_create_how_to_column_modifiers_table.php
Schema::create('how_to_column_modifiers', function (Blueprint $table) {
$table->integer('id')->autoIncrement();
$table->string('name')->charset('utf8')->collation('utf8_unicode_ci')->comment('my comment')->default('test value')->nullable();
$table->integer('price')->unsigned();
$table->integer('count')->unsigned();
$table->integer('total_stored')->storedAs('price * count');
$table->integer('total_virtual')->virtualAs('price * count');
$table->integer('total_generated')->generatedAs('price * count');
$table->timestamp('created_at')->useCurrent();
$table->integer('seq')->always();
});
インデックス
users1:
indexes:
email_index:
columns: name
type: index
columns:
id: bigIncrements
name:
type: string
email:
type: string
users2:
indexes:
email_index:
columns:
- name
- email
type: index
alias: users_name_index
columns:
id: bigIncrements
name:
type: string
email:
type: string
users3:
indexes:
email_index:
columns:
- name
- email
type: index
alias: custom_index
columns:
id: bigIncrements
name:
type: string
email:
type: string
実際に出力されるファイル:
https://github.com/ucan-lab/laravel-dacapo/tree/master/tests/Storage/index
一意制約
users1:
indexes:
email_index:
columns: name
type: unique
columns:
id: bigIncrements
name:
type: string
email:
type: string
users2:
indexes:
email_index:
columns:
- name
- email
type: unique
alias: users_name_unique_index
columns:
id: bigIncrements
name:
type: string
email:
type: string
users3:
indexes:
email_index:
columns:
- name
- email
type: unique
alias: custom_index
columns:
id: bigIncrements
name:
type: string
email:
type: string
実際に出力されるファイル:
https://github.com/ucan-lab/laravel-dacapo/tree/master/tests/Storage/unique_index
外部キー制約
users:
columns:
id: bigIncrements
name: string
tags:
columns:
id: bigIncrements
title: string
tasks:
relations:
- foreign: user_id
references: id
on: users
onUpdate: cascade
onDelete: cascade
columns:
id: bigIncrements
user_id: unsignedBigInteger
content: string
task_tag:
relations:
- name: task_tag_custom_task_id_foreign
foreign: task_id
references: id
on: tasks
- foreign: tag_id
references: id
on: tags
columns:
task_id: unsignedBigInteger
tag_id: unsignedBigInteger
実際に出力されるファイル:
https://github.com/ucan-lab/laravel-dacapo/tree/master/tests/Storage/relation/migrations
ダカーポのアンインストール
開発時は全テーブルドロップしてマイグレーション、シーディング実行で問題ありませんが、
運用開始してしまうと、本番テーブルをドロップする訳にはいきません...
運用フェーズに移行したらダカーポを削除して通常のマイグレーション運用に戻しましょう。
$ php artisan dacapo:uninstall
$ composer remove --dev ucan-lab/laravel-dacapo
Dacapo (ダカーポ) の由来
ライブラリ名の由来ですが、演奏記号のダ・カーポから命名しました。
ダカーポは「最初に戻って繰り返す。」という意味があります。
PHPのパッケージ管理ツールComposerが作曲家という意味なので音楽用語でこれだと思った名前に決めました!
着想
ダカーポライブラリの着想は Laravel/Vue.js勉強会#3 - connpass に参加して @mpyw さんのLTに影響を受けて作成しました。
また、Symfony1.4系の頃にあったDoctrineのDBスキーマ定義も参考にしてます。
Laravel × Dacapo で快適なマイグレーション生活を!