忍者ブログ
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。



2024/11/24 03:15 |
DoctrineのLEFT JOINはまともに使えない
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を扱わせろ。
PR


2014/08/25 23:53 | Comments(0) | PHP

コメント

コメントを投稿する






Vodafone絵文字 i-mode絵文字 Ezweb絵文字 (絵文字)



<<POH Lite 天才火消しエンジニア霧島 0.01秒の解答 | HOME | 買ったものリスト 2014/08/24>>
忍者ブログ[PR]