schema.yml
TableA:
actAs:
Timestampable: ~
columns:
columna:
type: string(255)
TableB:
actAs:
Timestampable: ~
columns:
columnb:
type: string(255)
relations:
TableA:
local: a_id
foreign: id
type: one
foreignType: many
テーブルAとBに1対多のリレーションをはっておく。
$data = Doctrine_Query::create()->from('TableA a')->leftJoin('a.TableB b')->limit(5)->execute();
// Expected result : SELECT * FROM TableA a LEFT JOIN TableB b ON a.id = b.a_id LIMIT 5
// Actual result : SELECT * FROM TableA a LEFT JOIN TableB b ON a.id = b.a_id WHERE a.id IN (1,2,3,4,5)
全体に掛けていたはずのLIMIT 5が、『テーブルAの件数が5件』という意味に勝手に書き換えられている。
ふざけてるの?
このファッキンな挙動を止める術は一応あって、
$q = Doctrine_Query::create()->from('TableA a')->leftJoin('a.TableB b')->limit(5);
$q->setDisableLimitSubquery(true);
$data = $q->execute();
で余計な変換をせず想定したとおりのLIMITがかかります。
何故こちらがデフォルトでないのか理解に苦しむ。
あと返り値がbooleanなのでメソッドチェーンできない。
さて、これでめでたしかと思えば実はそんなことはない。
帰ってくるデータは実際はDoctrine_Collectionですが、配列として示すとこんなかんじになっています。
$data = [
0=>[
id=>1,
TableB=>[
0=>[…],
1=>[…],
2=>[…],
]
],
1=>[
id=>2,
TableB=>[…]
],
…
];
テーブルBが、同じa_id毎にまとめられてしまうのだ。
これはこれで便利な機能ではあるのですが、問題はこの挙動をやめさせる手段がないことです。
executeの引数で、返り値の形をある程度変更できます。
// デフォルト、入れ子のDoctrine_Collectionで取得
$data = $q->execute(array(), Doctrine_Core::HYDRATE_RECORD);
// 入れ子の配列で取得
$data = $q->execute(array(), Doctrine_Core::HYDRATE_ARRAY);
// フラットな配列で取得
$data = $q->execute(array(), Doctrine_Core::HYDRATE_ARRAY_SHALLOW);
配列ならフラットな形で取得できるのですが、何故かフラットなDoctrine_Collectionで取得する方法が無い。
素直にforeachループ一回で全TableBを扱わせろ。