久々に投稿します。株式会社アジャストの渕上です。
PHPにはDoctrineというORMがあります。
弊社では受託案件で特にフレームワークの指定がない場合、
「Symfony」を採用することが多いため、ORMはDoctrineを利用することが多いです。
Doctrineの現行バージョンの2では、
PHPコードのコメントを特定フォーマットで記述する「Annotation」という方法が推奨されているようで、
その他の設定方法のリファレンスが、Annotaionでの設定方法に比べて情報量が少ないです。
弊社はDoctrineの旧バージョン「1」のころからyamlで設定していて、
Doctrine2でもyamlで設定ファイルを書いています。
しかし前述の情報量の少なさから、いろいろとハマることがあります。
今回は、個人的にハマったこと(とその対策)を紹介します。
参考までに、Doctrine2のyaml設定ファイルのリファレンスは下記になります。
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/yaml-mapping.html
ちなみに、Annotationのリファレンスは下記です。
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html
…圧倒的情報量の差を感じ取っていただけたでしょうか。
ManyToMany
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/yaml-mapping.html
前述のリファレンスで紹介されている例ではUserがGroupとManyToManyされているのですが、
この設定の仕方でEntityクラスを自動生成したときに、
リレーションを貼った側にしかsetter/getterが用意されませんでした。
つまり、設定ファイルからEntityを生成したときに
User::getGroups();
は定義されますが、
Group::getUsers();
は定義されません。
両方のEntityにgetter/setterメソッドを自動生成で追加するには、
Annotationのリファレンスで紹介されているように両側から設定する必要があります。
Doctrine 1でもManyToManyを両側から定義していたのですが、
Doctrine2.0のyamlリファレンスには片側から定義する例だけが紹介されていたので少しハマりました。
具体的には下記URLに「manyToMany bidirectional」と紹介されているように設定をします。
https://gist.github.com/mnapoli/3839501
↑のドキュメントは他にも公式のリファレンスで紹介されていない設定例が紹介されているので、
設定ファイルとしてyamlを選択する際には一読をお勧めいたします。
(困っているときにこのドキュメントにたどりついて、実際とても助かりました。)
ManyToMany その2
ある案件で中間テーブルに外部キー以外のカラムを定義する要件があったのですが、
EntityAから中間テーブルにoneToManyし、EntityBから中間テーブルにoneToManyし、
中間テーブルもEntityを定義してなんとか乗り越えました。
…大変力技になります。
イメージとしてはこんな感じになります。
もっとスマートな解決策をご存じの方がいらっしゃいましたらご教示ください。
User:
type:entity
fields:
id: {type: integer, id: true, nullable: false, generator: {strategy: AUTO }}
oneToMany:
UserGroupRelationShip:
targetEntity: UserGroupRelationShip
mappedBy: Users
Group:
type:entity
fields:
id: {type: integer, id: true, nullable: false, generator: {strategy: AUTO }}
oneToMany:
UserGroupRelationShip:
targetEntity: UserGroupRelationShip
mappedBy: Groups
UserGroupRelationShip:
type:entity
fields:
user_id: {type: integer}
group_id: {type: integer}
sort_order: {type: integer } # 追加したいカラムの定義
manyToOne:
Users:
targetEntity: User
inversedBy: UserGroupRelationShip
joinColumns:
joinColumn:
name: user_id
referencedColumnName: id
onDelete: CASCADE
Groups:
targetEntity: Group
inversedBy: UserGroupRelationShip
joinColumns:
joinColumn:
name: user_id
referencedColumnName: id
onDelete: CASCADE
ちなみにこの方法でリレーションを設定すると、
getterとしては中間テーブルに対するメソッドが生成されるため、
User::getGroups()
やGroup::getUsers()
は自前で定義することになります。
…大変力技になります。
自動生成周り
yamlからEntityクラスを自動生成した後で、手動でメソッドを追加することはよくあると思います。
自動生成されたメソッドと手動で追加したメソッドが並ぶようになるのですが、
なんだか気持ち悪いです。
そこで弊社ではBaseというプリフィクスのついたクラス(Baseクラス)を自動生成し、
それを継承したクラスを編集するようにしています。
(UserというEntityを定義する場合BaseUser.phpの名前で自動生成し、それをextendしたUser.phpを作る。)
具体的な設定方法、やサンプルコードは
隣の席の社員がブログ記事にするといっておりました。期待しております。
コメントを残す