takaya030の備忘録

PHP、Laravel、Docker などの話がメインです

Laravel のマイグレーションで MySQL の COMMENT を扱う

MySQL は COMMENT 句を使う事でカラムやテーブルにコメントをつけることができます。

CREATE TABLE `user_info`
{
  `id` int(10) unsigned NOT NULL auto_increment COMMENT 'Id of User',
  `name` varchar(20) NOT NULL COMMENT 'Name of User',
  `email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY  (`id`)
} ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='User Infomation';

しかし、Laravel の API リファレンスを見る限り、スキーマビルダー(正確には Bluprint クラス)には COMMENT のメソッドはありません。

↓こちらでスキーマビルダーに comment メソッドの追加が提案されていましたが、重要度が低いという事で却下されていました。
add ->comment($comment) to the Schema builder ・ Issue #93 ・ laravel/framework ・ GitHub

普通なら単なるコメントなので使えなくても特に問題ないのですが、SPIDER ストレージエンジンでは COMMENT を使ってパラメータ指定を行うため深刻な問題になります。

最悪、スキーマファイルで記述する方法もありますが、バージョン管理のことを考えるとマイグレーションで書けた方が望ましいです。

何か方法は無いものかと思いながらググったら、Stack Overflow にこんな記事を見つけました
php - How can I set the default value of a timestamp column to "CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" with Laravel 4 migrations - Stack Overflow

どうやら Schema::create を実行した直後にそのテーブルに対して ALTER TABLE ができるようです。
これなら何とかなりそうです。検証してみます。

検証は以下の環境で行いました。

Windows8 64bit
XAMPP 1.8.2
PHP 5.4.19
MySQL 5.5.14 (Spider 3.0 対応版)
Laravel 4.0.7

ちなみに MySQL はこちらの手順で Spider 3.0 対応版にアップグレードしました。
XAMPP for Windows の MySQL を Spider 3.0 対応版に更新 - takaya030の備忘録

テーブル作成

最初に CREATE TABLE を実行するマイグレーションクラスを作成します。

$ php artisan migrate:make --create --table="user_info" create_user_info

app/database/migrations/yyyy_mm_dd_hhmmss_create_user_info.php の内容です。
(yyyy_mm_dd_hhmmss はファイルが作成された日時になります)

<?php

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

class CreateUserInfo extends Migration {

	/**
	 * Run the migrations.
	 *
	 * @return void
	 */
	public function up()
	{
		Schema::create('user_info', function(Blueprint $table)
		{
			$table->increments('id');

			$table->bigInteger('user_id');
			$table->string('name',16);
			$table->string('email',100);

			$table->timestamps();		// created_at, updated_at 
		});

		// add comments
		DB::statement("ALTER TABLE ".DB::getTablePrefix()."user_info CHANGE user_id user_id BIGINT(20) NOT NULL COMMENT 'Id of User'");
		DB::statement("ALTER TABLE ".DB::getTablePrefix()."user_info CHANGE name name VARCHAR(16) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Name of User'");
		DB::statement("ALTER TABLE ".DB::getTablePrefix()."user_info COMMENT 'User Information Table'");
	}

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

}

migrate コマンドでテーブルを作成します。

$ php artisan migrate

作成されたテーブルを見てみます。

mysql> show create table user_info\G

*************************** 1. row ***************************
       Table: user_info
Create Table: CREATE TABLE `user_info` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL COMMENT 'Id of User',
  `name` varchar(16) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Name of User',
  `email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='User Information Table'

COMMENTを使ったテーブルが作成できました。
次にマイグレーションです。

マイグレーションの実行

COMMENT を変更するマイグレーションクラスを作成します。

$ php artisan migrate:make modify_user_info

app/database/migrations/yyyy_mm_dd_hhmmss_modify_user_info.php の内容です。

<?php

use Illuminate\Database\Migrations\Migration;

class ModifyUserInfo extends Migration {

	/**
	 * Run the migrations.
	 *
	 * @return void
	 */
	public function up()
	{
		// Modify comments
		DB::statement("ALTER TABLE ".DB::getTablePrefix()."user_info CHANGE user_id user_id BIGINT(20) NOT NULL COMMENT 'Mod Id of User'");
		DB::statement("ALTER TABLE ".DB::getTablePrefix()."user_info CHANGE name name VARCHAR(16) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Mod Name of User'");
		DB::statement("ALTER TABLE ".DB::getTablePrefix()."user_info COMMENT 'Mod User Information Table'");
	}

	/**
	 * Reverse the migrations.
	 *
	 * @return void
	 */
	public function down()
	{
		// Rollback comments
		DB::statement("ALTER TABLE ".DB::getTablePrefix()."user_info CHANGE user_id user_id BIGINT(20) NOT NULL COMMENT 'Id of User'");
		DB::statement("ALTER TABLE ".DB::getTablePrefix()."user_info CHANGE name name VARCHAR(16) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Name of User'");
		DB::statement("ALTER TABLE ".DB::getTablePrefix()."user_info COMMENT 'User Information Table'");
	}

}

migrate コマンドでマイグレーションを実行します。

$ php artisan migrate

COMMENT が変更されているか確認します。

mysql> show create table user_info\G

*************************** 1. row ***************************
       Table: user_info
Create Table: CREATE TABLE `user_info` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL COMMENT 'Mod Id of User',
  `name` varchar(16) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Mod Name of User',
  `email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Mod User Information Table'

COMMENT の先頭に "Mod" が追加されているのが確認できます。

マイグレーションロールバック

以下のコマンドでロールバックさせます。

$ php artisan migrate:rollback

COMMENT が戻っているか確認します。

mysql> show create table user_info\G

*************************** 1. row ***************************
       Table: user_info
Create Table: CREATE TABLE `user_info` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL COMMENT 'Id of User',
  `name` varchar(16) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Name of User',
  `email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='User Information Table'

うまく行きました。
ALTER TABLEのときに余計な変更をしないように気を付ける必要がありますが、COMMENTありのテーブルもマイグレーションで管理できる目処がつきました。