schema.ymlがどこまで楽させてくれるか

私のようにデータベース設計をテキストエディタでやる人にとって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はバージョンアップする度にどんどんコード書く量が減っていきますね。

Leave a Reply

Name (required)
Mail (will not be published) (required)

Your Comments:

Spam Protection by WP-SpamFree