You are currently reading the 1.2 documentation. Switch to 2.2  2.1  2.0 

YAML Schema Files

はじめに

スキーマファイルの目的はPHPコードの編集よりもYAMLファイルでモデルの定義を直接管理できるようにすることです。すべてのモデルの定義/クラスを生成するためにYAMLスキーマファイルは解析され使われます。これによってDoctrineモデルの定義がはるかにポータブルなものになります。

スキーマファイルはPHPコードで書く通常のすべての内容をサポートします。接続バインディング用のコンポーネント、リレーション、属性、テンプレート/ビヘイビア、インデックスなどがあります。

省略構文

Doctrineは省略記法でスキーマを指定する機能を提供します。多くのスキーマパラメータはデフォルトの値を持ち、これによって構文をできるのでDoctrineはデフォルトを利用できます。すべての省略記法を利用したスキーマの例は下記の通りです。

detect_relationsオプションによってカラムの名前からリレーションの推測が行われます。下記の例ではDoctrine はUserが1つのContactを持つことを知っておりモデルの間のリレーションを自動的に定義します。

---
detect_relations: true

User:
  columns:
    username: string
    password: string
    contact_id: integer

Contact:
  columns:
    first_name: string
    last_name: string
    phone: string
    email: string
    address: string

冗長な構文

上記のスキーマを100%冗長にしたものは次の通りです:

---
User:
  columns:
    username:
      type: string(255)
    password:
      type: string(255)
    contact_id:
      type: integer
  relations:
    Contact:
      class: Contact
      local: contact_id
      foreign: id
      foreignAlias: User
      foreignType: one
      type: one

Contact:
  columns:
    first_name:
      type: string(255)
    last_name:
      type: string(255)
    phone:
      type: string(255)
    email:
      type: string(255)
    address:
      type: string(255)
  relations:
    User:
      class: User
      local: id
      foreign: contact_id
      foreignAlias: Contact
      foreignType: one
      type: one

上記の例ではdetect_relationsオプションを定義せず、代わりにローカル/外部キー、型、とそれぞれの側のリレーションのエイリアスの設定を通して完全にコントロールできるように手動でリレーションを定義します。

リレーション

リレーションを指定するとき外部キーが存在している方のリレーションを指定することだけが必要です。スキーマファイルが解析されるとき、Doctrineはリレーションを反映し反対側を自動的にビルドします。もう一方のリレーションを指定する場合、自動生成は行われません。

リレーションを検出する

前に見たようにDoctrineはdetect_relationsオプションを指定する機能を提供します。この機能はカラムの名前に基づいてリレーションを自動的に構築します。contact_idを持つUserモデルとContactという名前を持つクラスが存在する場合、2つの間のリレーションが自動的に作成されます。

リレーションをカスタマイズする

Doctrineは外部キーが存在している側のリレーションを指定することのみを要求します。リレーションの反対側は反映されもう一方側に基づいてビルドされます。スキーマ構文はリレーションのエイリアスと反対側の型をカスタマイズする機能を提供します。すべての関連するリレーションを一箇所で維持できるのでこれはよいニュースです。下記の内容はエイリアスと反対側のリレーションの型をカスタマイズする方法です。これはUserが1つのContactを持ちContactは1つのUserUserModelとして持つというリレーションを示しています。通常は自動生成されたUserは1つのContactを持ちContactは複数のUserを持ちます。foreignTypeforeignAliasオプションによって反対側のリレーションをカスタマイズできます。

---
User:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)
  relations:
    Contact:
      foreignType: one
      foreignAlias: UserModel

Contact:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    name:
      type: string(255)

次のようにthe detect_relationsオプションを持つ2つのモデルの間のリレーションを見つけて作成できます。

---
detect_relations: true

User:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    avatar_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)

Avatar:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    name:
      type: string(255)
    image_file:
      type: string(255)

結果のリレーションはUserは1つのAvatarを持ちAvatarは複数のUserを持ちます。

一対一

---
User:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)
  relations:
    Contact:
      foreignType: one

Contact:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    name:
      type: string(255)

一対多

---
User:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)

Phonenumber:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    name:
      type: string(255)
    user_id:
      type: integer(4)
  relations:
    User:
      foreignAlias: Phonenumbers

多対多

---
User:
  columns:
    id:
      type: integer(4)
      autoincrement: true
      primary: true
    username:
      type: string(255)
    password:
      type: string(255)
  attributes:
    export: all
    validate: true

Group:
  tableName: group_table
  columns:
    id:
      type: integer(4)
      autoincrement: true
      primary: true
    name:
      type: string(255)
  relations:
    Users:
      foreignAlias: Groups
      class: User
      refClass: GroupUser

GroupUser:
  columns:
    group_id:
      type: integer(4)
      primary: true
    user_id:
      type: integer(4)
      primary: true
  relations:
    Group:
      foreignAlias: GroupUsers
    User:
      foreignAlias: GroupUsers

この場合Userは複数のGroupsを持ち、Groupは複数のUsersを持ち、GroupUserは1つのUserを持ちGroupUserは1つのGroupを持つモデルのセットが作られます。

機能と例

接続バインディング

モデルを管理するためにスキーマファイルを使わないのであれば、通常は次のコードのようにコンポーネントを接続名にバインドするために使います:

下記のように接続を作成します:

Doctrine_Manager::connection('mysql://jwage:pass@localhost/connection1', 'connection1');

Doctrineのブートストラップスクリプトでモデルをその接続にバインドします:

Doctrine_Manager::connection()->bindComponent('User', 'conn1');

スキーマファイルは接続パラメータを指定することでこれを特定の接続にバインドする機能を提供します。接続を指定しなければモデルはDoctrine_Managerインスタンスにセットあれた現在の接続を使います。

---
User:
  connection: connection1
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)

属性

Doctrine_Record子クラスを手作業で書いたのと同じようにDoctrineはスキーマファイルで生成モデル用の属性を直接設定する手段を提供します。

---
User:
  connection: connection1
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)
  attributes:
    export: none
    validate: false

列挙型

スキーマファイルでenumカラムを使うために型をenumとして指定し可能なenumの値として値の配列を指定しなければなりません。

---
TvListing:
 tableName: tv_listing
 actAs: [Timestampable]
 columns:
   notes:
     type: string
   taping:
     type: enum
     length: 4
     values: ['live', 'tape']
   region:
     type: enum
     length: 4
     values: ['US', 'CA']

ActAsビヘイビア

actAsオプションでモデルにビヘイビアを取り付けることができます:

---
User:
  connection: connection1
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)
  actAs:
    Timestampable:
    Sluggable:
      fields: [username]
      name: slug    # defaults to 'slug'
      type: string  # defaults to 'clob'
      length: 255   # defaults to null. clob doesn't require a length

何も指定しない場合デフォルトの値が使われるのでSluggableビヘイビアで指定されたオプションはオプションです。これらはデフォルトなので毎回入力する必要はありません。

---
User:
  connection: connection1
  columns:
# ...
  actAs: [Timestampable, Sluggable]

リスナー

モデルに取り付けたいリスナーがある場合、同じようにYAMLファイルで直接これらを指定できます。

---
User:
  listeners: [ MyCustomListener ]
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)

上記の構文で次のような基底クラスが生成されます:

class BaseUser extends Doctrine_Record
{
   // ...

   public setUp()
   {
       // ...
       $this->addListener(new MyCustomListener());
   }
}

オプション

テーブル用のオプションを指定するとDoctrineがモデルからテーブルを作成するときにオプションはcreate tableステートメントに設定されます。

---
User:
  connection: connection1
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)
  options:
    type: INNODB
    collate: utf8_unicode_ci
    charset: utf8

インデックス

インデックスとオプションの詳細情報はchapterの[doc defining-models:indexes :name]セクションを参照してくださるようお願いします。

---
UserProfile:
  columns:
    user_id:
      type: integer
      length: 4
      primary: true
      autoincrement: true
    first_name:
      type: string
      length: 20
    last_name:
      type: string
      length: 20
  indexes:
    name_index:
      fields:
        first_name:
          sorting: ASC
          length: 10
          primary: true
        last_name: []
      type: unique

インデックスの定義用のモデルクラスのsetTableDefinition()で自動生成されたPHPコードは次の通りです:

$this->index('name_index', array(
        'fields' => array(
            'first_name' => array(
                'sorting'  => 'ASC',
                'length'   => '10',
                'primary'  => true
            ),
            'last_name' => array()),
        'type' => 'unique'
    )
);

継承

下記のコードはYAMLスキーマファイルを使用して異なるタイプの継承をセットアップする方法を示しています。

単一継承

---
Entity:
  columns:
    name: string(255)
    username: string(255)
    password: string(255)

User:
  inheritance:
    extends: Entity
    type: simple

Group:
  inheritance:
    extends: Entity
    type: simple

単一継承するモデルで定義されたカラムもしくはリレーションはPHPクラスが生成されたときに親に移動します。

[doc inheritance:simple :fullname]の章でこのトピックの詳細を読むことができます。

具象継承

---
TextItem:
  columns:
    topic: string(255)

Comment:
  inheritance:
    extends: TextItem
    type: concrete
  columns:
    content: string(300)

[doc inheritance:concrete :fullname]の章でこのトピックの詳細を読むことができます。

カラム集約継承

単一継承のように、PHPクラスが生成されたとき子に追加されるカラムもしくはリレーションは自動的に削除され親に移動します。

他のモデルが継承するEntityという名前のモデルを定義しましょう:

---
Entity:
  columns:
    name: string(255)
    type: string(255)

typeカラムはオプションです。このカラムは子クラスで指定された場合自動的に追加されます。

Entityモデルを継承するUserモデルを作りましょう:

---
User:
  inheritance:
    extends: Entity
    type: column_aggregation
    keyField: type
    keyValue: User
  columns:
    username: string(255)
    password: string(255)

inheritance定義の下のtypeオプションはkeyFieldもしくはkeyValueを指定する場合暗示されるのでオプションです。keyFieldが指定されない場合デフォルトではtypeという名前のカラムが追加されます。何も指定しない場合デフォルトでkeyValueがモデルの名前になります。

再度Entityを継承するGroupという名前の別のモデルを作りましょう:

---
Group:
  inheritance:
    extends: Entity
    type: column_aggregation
    keyField: type
    keyValue: Group
  columns:
    description: string(255)

UserusernamepasswordGroupdescriptionカラムは自動的に親のEntityに移動します。

[doc inheritance:column-aggregation :fullname]で詳細トピックを読むことができます。

カスタムのエイリアス

データベースのカラム名以外のカラム名のエイリアスを作成したい場合、Doctrineでこれを実現するのは簡単です。カラムの名前で"column_name as field_name"の構文を使います:

---
User:
  columns:
    login:
      name: login as username
      type: string(255)
    password:
      type: string(255)

上記の例ではusernameエイリアスからカラム名のloginにアクセスできます。

パッケージ

Doctrineはサブフォルダでモデルを生成する"package"パラメータを提供します。大きなスキーマファイルによってフォルダの内外でスキーマをよりよく編成できます。

---
User:
  package: User
  columns:
    username: string(255)

このスキーマファイルからのモデルファイルはUserという名前のフォルダに設置されます。"package: User.Models"とさらにサブフォルダを指定すればモデルはUser/Modelsになります。

カスタムパスのパッケージ

パッケージファイルを生成する完全なカスタムパスを指定することで適切なパスでパッケージを自動生成することもできます:

---
User:
  package: User
  package_custom_path: /path/to/generate/package
  columns:
    username: string(255)

グローバルスキーマの情報

Doctrineスキーマによってスキーマファイルで定義されたすべてのモデルに適用する特定のパラメータを指定できます。スキーマファイル用に設定できるグローバルパラメータの例が見つかります。

グローバルパラメータのリストは次の通りです:

名前 説明
connection モデルをバインドする接続名。
attributes モデル用の属性の配列
actAs モデル用のビヘイビアの配列
options モデル用のテーブルオプションの配列
package モデルを設置するパッケージ
inheritance モデル用の継承情報の配列
detect_relations 外部キーのリレーションを検出するかどうか

上記のグローバルパラメータをいつか使ったスキーマの例は次の通りです:

---
connection: conn_name1
actAs: [Timestampable]
options:
  type: INNODB
package: User
detect_relations: true

User:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)

Contact:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    name:
      type: string(255)

トップレベルのすべての設定はYAMLで定義されたすべてのモデルに適用されます。

スキーマファイルを使う

一旦スキーマファイルを定義したらYAMLの定義からモデルをビルドするコードが必要です。

$options = array(
  'packagesPrefix'  =>  'Plugin',
  'baseClassName'   =>  'MyDoctrineRecord',
  'suffix'          =>  '.php'
);

Doctrine_Core::generateModelsFromYaml('/path/to/yaml', '/path/to/model', $options);

上記のコードは/path/to/generate/modelsschema.yml用のモデルを生成します。

モデルのビルド方法をカスタマイズするために利用できる異なるオプションの表は次の通りです。packagesPrefixbaseClassNamesuffixオプションを使用していることに注目してください。

名前 デフォルト 説明
packagesPrefix Package ミドルパッケージモデルのプレフィックス
packagesPath #models_path#/packages パッケージファイルを書き込むパス
packagesFolderName packages パッケージパス内部で、パッケージを置くフォルダーの名前
generateBaseClasses true 定義と空の基底モデルを継承するトップレベルのクラスを含めて抽象基底モデルを生成するかどうか
generateTableClasses true モデルごとにテーブルを生成するか
baseClassPrefix Base 生成既定モデルに使うプレフィックス
baseClassesDirectory generated 基底クラスの定義を生成するフォルダーの名前
baseTableClassName Doctrine_Table ほかの生成テーブルクラス名が継承する基底テーブルクラス
baseClassName Doctrine_Record Doctrine_Record既定クラスの名前
classPrefix すべての生成クラスで使うプレフィックス
classPrefixFiles true 生成ファイルの名前にもクラスのプレフィックスを使うかどうか
pearStyle false PEARスタイルのクラス名とファイルを生成するか。このオプションがtrueにセットされている場合。生成クラスファイルにおいてunderscores(_)DIRECTORY_SEPARATORに置き換えられます。
suffix .php 生成モデルに使う拡張子
phpDocSubpackage docブロックで生成するphpDocのサブパッケージ名
phpDocName docブロックで生成するphpDocの著者名
phpDocEmail docブロックで生成するphpDocのメール

まとめ

YAMLスキーマファイルのすべてを学んだのでData Validationに関する大きなトピックに移ります。これは重要なトピックです。ユーザーが入力したデータをあなた自身でバリデートしたくない場合データベースに永続的に保存する前にDoctrineにデータをバリデートさせます。


Questions and Feedback

If you find a problem with the documentation or have a suggestion, please register and open a ticket.

If you need support or have a technical question, you can post to the user mailing-list.