miauのブログ

はてなダイアリー「miauの避難所」をはてなブログに移行しました

cake schema でコメントを取得/設定する(MySQL 限定)

2 月からのプロジェクトは CakePHPアジャイルっぽく進めるという話になっています。後で仕様が変わるのは確実なので、テーブル定義なんかは migration 風に管理したいところです。(※migration というのは Rails なんかで使われている仕組みで、テーブルへのカラム追加等を ALTER TABLE で実行するので、データを消失することなくスキーマ情報を変更できる仕組みです。)

CakePHP では、

にあるように、cake schema upgrade で migration に近いことができますが、どうもテーブルやカラムのコメントを認識してくれないようで。これでは不便なので、コメントを取得/設定できるように dbo_mysql.php を変更してみました。

下調べ

カラムのコメント

あたりにあるように、SHOW FULL COLUMNS FROM <テーブル名> で取得できますよと。

mysql> describe `users`;
+-------+---------+------+-----+---------+----------------+
| Field | Type    | Null | Key | Default | Extra          |
+-------+---------+------+-----+---------+----------------+
| id    | int(11) | NO   | PRI | NULL    | auto_increment |
| name  | text    | NO   |     | NULL    |                |
| email | text    | NO   |     | NULL    |                |
+-------+---------+------+-----+---------+----------------+

mysql> show columns from `users`;
+-------+---------+------+-----+---------+----------------+
| Field | Type    | Null | Key | Default | Extra          |
+-------+---------+------+-----+---------+----------------+
| id    | int(11) | NO   | PRI | NULL    | auto_increment |
| name  | text    | NO   |     | NULL    |                |
| email | text    | NO   |     | NULL    |                |
+-------+---------+------+-----+---------+----------------+

mysql> show full columns from `users`;
+-------+---------+-----------------+------+-----+---------+----------------+---------------------------------+----------------+
| Field | Type    | Collation       | Null | Key | Default | Extra          | Privileges                      | Comment        |
+-------+---------+-----------------+------+-----+---------+----------------+---------------------------------+----------------+
| id    | int(11) | NULL            | NO   | PRI | NULL    | auto_increment | select,insert,update,references | ユーザID       |
| name  | text    | utf8_general_ci | NO   |     | NULL    |                | select,insert,update,references | 氏名           |
| email | text    | utf8_general_ci | NO   |     | NULL    |                | select,insert,update,references | メールアドレス |
+-------+---------+-----------------+------+-----+---------+----------------+---------------------------------+----------------+

別の取得方法もあるみたいで

mysql> select * from information_schema.columns where table_name='users'\G
*************************** 1. row ***************************
           TABLE_CATALOG: NULL
            TABLE_SCHEMA: exam
              TABLE_NAME: users
             COLUMN_NAME: id
        ORDINAL_POSITION: 1
          COLUMN_DEFAULT: NULL
             IS_NULLABLE: NO
               DATA_TYPE: int
CHARACTER_MAXIMUM_LENGTH: NULL
  CHARACTER_OCTET_LENGTH: NULL
       NUMERIC_PRECISION: 10
           NUMERIC_SCALE: 0
      CHARACTER_SET_NAME: NULL
          COLLATION_NAME: NULL
             COLUMN_TYPE: int(11)
              COLUMN_KEY: PRI
                   EXTRA: auto_increment
              PRIVILEGES: select,insert,update,references
          COLUMN_COMMENT: ユーザID
(snip)

という拾い方もできるようですが、元の処理が DESCRIBE を使っているので、SHOW FULL COLUMNS FROM <テーブル名> の方を使うことにします。

テーブルのコメント

SHOW TABLE STATUS で取得できるそうで。

mysql> show table status\G
*************************** 1. row ***************************
           Name: users
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 0
 Avg_row_length: 0
    Data_length: 16384
Max_data_length: 0
   Index_length: 0
      Data_free: 11534336
 Auto_increment: 1
    Create_time: 2010-02-01 13:45:47
    Update_time: NULL
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment: ユーザ

元々 SHOW TABLE STATUS が使われているようなので、Comment 列を取得する処理を追加するだけでよさそうですね。

完成品

とりあえず github に上げました。

今回使う DB が MySQL なので、対応は MySQL のみ(検証環境は 5.1.33)です。また、CakePHP 1.3 のブランチで変更しています。

動作検証

>cake schema generate -f

とすると、

	var $users = array(
		'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'comment' => 'ユーザID', 'key' => 'primary'),
		'name' => array('type' => 'text', 'null' => false, 'default' => NULL, 'comment' => '氏名'),
		'email' => array('type' => 'text', 'null' => false, 'default' => NULL, 'comment' => 'メールアドレス'),
		'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
		'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'InnoDB', 'comment' => 'ユーザ')
	);

こんな感じで comment のデータが含まれた形で schema.php に出力されます。そして、

>cake schema create -dry

とすると、

Dry run for users :
CREATE TABLE `users` (
	`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ユーザID',
	`name` text NOT NULL COMMENT '氏名',
	`email` text NOT NULL COMMENT 'メールアドレス',	PRIMARY KEY  (`id`))	DEFAULT CHARSET=utf8,
	COLLATE=utf8_general_ci,
	ENGINE=InnoDB,
	COMMENT='ユーザ';

こんな感じでコメントつきの CREATE TABLE 文が生成されます。最低限の使い方なら問題ないんじゃないかと。

問題点

この変更を加えると、cake/tests/cases/libs/model/cake_schema.test.php のテストに失敗してしまいます。今回コメントの情報を返すように変更しましたが、これがテストの想定と異なるためです。普段であればテストの想定値を変更してしまえばいいんですが、MySQL 以外の DBO で対応していないので、そうするわけにもいかなくて困っています。ベストなのはすべての dbo_xxxxx.php で comment を返すように変更することですが、そこまでの体力はありませんし。

・・・と悩んでいたところに、ちょうど Twitter

@hiromi2424 誰かmysqlのコメントを論理名とするscaffold view書いてないかな、書いてないなら書くんだけど #cakephp link
@miau_jp @hiromi2424 cake schema でコメントの取得&設定ができるように dbo_mysql.php に手を入れたものなら手元に・・・。これを使えば比較的簡単にview の scaffolding にも利用できる気もします。 link
@hiromi2424 @miau_jp show full colmuns なのでscemaの領域ですか・・・!素晴らしいです。 単純に$db->query()でゴリ押そうと思ってました。 link
@miau_jp @hiromi2424 実は「ちょこちょこ変更してたら動いちゃった」という程度のものなんですけどね・・・。unit test をどう書くか思案してたんですけど、そこは無視して github にでもあげちゃいます。おそらく明日中くらいに。 link
@cakephper @miau_jp @hiromi2424 それかなり便利そう! そのアイディアは良いですね! link
@hiromi2424 @miau_jp 助かります! testは面倒なところがありますが、本家にマージするとしてチケット投げて任せてしまうという手もあります(ぇー link
@miau_jp . @hiromi2424 @cakephper 期待されすぎないように断っておくと、1.3 ベースで対応してます。1.2 にもすんなりマージできればいいんですけど。test はとりあえず忘れます・・・。 link
こんな話題があったので、とりあえず公開したのでした。

改善すべき点があればご意見ください。(すぐに対応できるとも限らないので、github で直接編集していただく形のほうがいいですけど・・・。)