取得したDoctrine_Collectionのインデックスに特定のフィールドの値を使う
通常、Doctrineでレコードを取得すると、Doctrine_Collectionのインデックスには整数インデックスが使われます。
しかし、取得したレコード一覧を単にループで処理するのではなく、連想配列のように処理したい場合もあります。
このような場合、Doctrine_Collectionのインデックスに、取得するレコードの特定のフィールドを使うように設定できます。
この機能を「Key Mapping」と呼びます。
Key Mappingの基本1 INDEXBYキーワードによる指定
DQL内に直接指定できる「INDEXBY」というキーワードがあります。
これを使うのがもっとも簡単です。
<?php $user_list = Doctrine_Query::create()->from('User u INDEXBY u.handle_name') ->execute();
この場合、インデックス化の指定は1つのクエリのみに適用されます。
Key Mappingの基本2 ATTR_COLL_KEY
Doctrine_Tableに設定できる属性で、ATTR_COLL_KEYがあります。
<?php $user_list = Doctrine_Core::getTable('User') ->setAttribute(Doctrine_Core::ATTR_COLL_KEY, 'handle_name') ->execute();
このように、Doctrine_TableのsetAttribute()メソッドを使って、テーブルの属性として「ATTR_COLL_KEY」にインデックスに使用するフィールドの名前を設定します。
なお、ここで設定した属性値はDoctrine内にキャッシュ(テーブルオブジェクトがキャッシュ)されますので、同じテーブルのレコードを続けて取得する場合、インデックス化のフィールドが有効なままになります。
少し複雑な場合
リレーションも含めてJOINしてレコードを取得する場合はどうでしょうか。
この場合も、クエリの主となるテーブルに対してATTR_COLL_KEYを設定すれば、ハイドレーション時に同じようにインデックスとして使われます。
ユーザーと、その電話番号を一度に取得して、結果はハンドル名をキーとする連想配列になるようにしてみます。
<?php Doctrine_Core::getTable('User') ->setAttribute(Doctrine_Core::ATTR_COLL_KEY, 'handle_name'); $dql = new Doctrine_Query::create()->from('User u') ->leftJoin('u.Phonenumber p') ->execute();
まとめ
Key Mappingを使うには、
- 1つのクエリ内のみで有効な「INDEXBY」キーワードを使う
- テーブル属性で「ATTR_COLL_KEY」を設定する
の2つの方法がある。
前者が簡単。全体の挙動を変えたいような場合は後者を使う。