DoctrineのLEFT JOINはまともに使えない

  • 5
    Like
  • 0
    Comment
More than 1 year has passed since last update.

DISTINCT / 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を扱わせろ。