私のようにデータベース設計をテキストエディタでやる人にとってschemaの記述がYAMLで書けるようになったのは嬉しい限りですが、単純に書き方が替わっただけではありません。schema.ymlを使うといろいろ楽できます。もちろん従来通りschema.xmlも利用できます。今日はYAMLを使うことでどれくらい楽にデータベースの設計ができるかを試してみます。
何も書かないとどうなるか
テーブルが無い場合
まず、以下のように、最低限のみを書いたYAMLを用意します。
propel:
これをXMLに変換します。
<?xml version="1.0" encoding="UTF-8"?> <database name="propel" defaultIdMethod="native" noXsd="true" package="lib.model"> </database>
これだけ書くだけでも一苦労ですね。(決まり文句なんでコピペすれば良い訳ですが)
カラムが無い場合
次に、カラムが無いテーブルを作ってみます。
propel: table1:
<?xml version="1.0" encoding="UTF-8"?> <database name="propel" defaultIdMethod="native" noXsd="true" package="lib.model"> <table name="table1"> <column name="id" type="integer" required="true" primaryKey="true" autoincrement="true" /> </table> </database>
なんとautoincrementなプライマリキーidが自動的に足されました。便利便利。
テーブル名+”_i18n”
アプリケーションの国際化対応用のテーブルも_i18nをつけるだけで自動生成されます。
propel:
table1:
name: varchar(255)
table1_i18n:
name: varchar(255)<?xml version="1.0" encoding="UTF-8"?> <database name="propel" defaultIdMethod="native" noXsd="true" package="lib.model"> <table name="table1" isI18N="true" i18nTable="table1_i18n"> <column name="name" type="varchar" size="255" /> <column name="id" type="integer" required="true" primaryKey="true" autoincrement="true" /> </table> <table name="table1_i18n"> <column name="name" type="varchar" size="255" /> <column name="id" type="integer" required="true" primaryKey="true" /> <foreign-key foreignTable="table1" onDelete="cascade"> <reference local="id" foreign="id" /> </foreign-key> <column name="culture" isCulture="true" type="varchar" size="7" required="true" primaryKey="true" /> </table> </database>
特殊なカラム名
次にカラム名で特殊な処理しているものを見ていきます。
テーブル名+”_id”
propel:
table1:
table2:
table1_id:すると。
<?xml version="1.0" encoding="UTF-8"?> <database name="propel" defaultIdMethod="native" noXsd="true" package="lib.model"> <table name="table1"> <column name="id" type="integer" required="true" primaryKey="true" autoincrement="true" /> </table> <table name="table2"> <column name="table1_id" type="integer" /> <foreign-key foreignTable="table1"> <reference local="table1_id" foreign="id" /> </foreign-key> <column name="id" type="integer" required="true" primaryKey="true" autoincrement="true" /> </table> </database>
自動的にForign-Keyが張られます。すごい。
created_at / updated_at
symfonyではcreated_at,updated_atというフィールド名は特殊な意味を持ちます。これらのフィールドが存在すると、symfonyはinsert/update時に自動的にcreated_at/updated_atを更新します。
propel:
table1:
created_at:
updated_at:これを変換します。
<?xml version="1.0" encoding="UTF-8"?> <database name="propel" defaultIdMethod="native" noXsd="true" package="lib.model"> <table name="table1"> <column name="created_at" type="timestamp" /> <column name="updated_at" type="timestamp" /> <column name="id" type="integer" required="true" primaryKey="true" autoincrement="true" /> </table> </database>
と、自動的にtimestamp型にしてくれます。期待通りです。
インデックス
インデックスを作るには以下のようにします。
propel:
table1:
name: varchar(255)
_indexes:
name_idx: [name]<?xml version="1.0" encoding="UTF-8"?> <database name="propel" defaultIdMethod="native" noXsd="true" package="lib.model"> <table name="table1"> <column name="name" type="varchar" size="255" /> <column name="id" type="integer" required="true" primaryKey="true" autoincrement="true" /> <index name="name_idx"> <index-column name="name" /> </index> </table> </database>
複数のキー
propel:
table1:
name: varchar(255)
name2: varchar(255)
_indexes:
name_idx: [name, name2]<?xml version="1.0" encoding="UTF-8"?> <database name="propel" defaultIdMethod="native" noXsd="true" package="lib.model"> <table name="table1"> <column name="name" type="varchar" size="255" /> <column name="name2" type="varchar" size="255" /> <column name="id" type="integer" required="true" primaryKey="true" autoincrement="true" /> <index name="name_idx"> <index-column name="name" /> <index-column name="name2" /> </index> </table> </database>
ユニーク制約
propel:
table1:
name: varchar(255)
_uniques:
name_uniq: [name]<?xml version="1.0" encoding="UTF-8"?> <database name="propel" defaultIdMethod="native" noXsd="true" package="lib.model"> <table name="table1"> <column name="name" type="varchar" size="255" /> <column name="id" type="integer" required="true" primaryKey="true" autoincrement="true" /> <unique name="name_uniq"> <unique-column name="name" /> </unique> </table> </database>
外部キー
外部キーを張る時は以下のようにします。
propel:
table1:
table2:
code: varchar(255)
_foreign_keys:
fk_1:
foreign_table: table1
references:
-
foreign: id
local: code
on_delete: cascade
on_update: set nullちょっと長くなりますね。on_delete,on_updateがいらなければ省略できます。
結果は以下のようになります。
<?xml version="1.0" encoding="UTF-8"?> <database name="propel" defaultIdMethod="native" noXsd="true" package="lib.model"> <table name="table1"> <column name="id" type="integer" required="true" primaryKey="true" autoincrement="true" /> </table> <table name="table2"> <column name="code" type="varchar" size="255" /> <column name="id" type="integer" required="true" primaryKey="true" autoincrement="true" /> <foreign-key foreignTable="table1" name="fk_1" onDelete="cascade" onUpdate="set null"> <reference local="code" foreign="id" /> </foreign-key> </table> </database>
SymfonyはsfPropelDatabaseSchemaというクラスでYAMLからXMLへの変換を実現しています。Symfonyはバージョンアップする度にどんどんコード書く量が減っていきますね。

