Czy ktoś mi powie, czemu kolejność JOINów w Doctrine jest taka ważna?
Przykład:
Mam 3 tabele:
user (przechowuje uzytkowników);
map (przechowuje zapisane mapy użytkownika);
map_position (przechowuje pozycje GPS każdej z map);

Tabela map ma kolumnę user_id, która jest kluczem obcym tabeli user;
Tabela map_position ma kolumnę map_id, która jest kluczem obcym tabeli map;
Tabela user ma klucz podstawowy user_id, który występuje jako klucz obcy w tabeli map.

Baza danych MySQL 5.0 - klucze obce oczywiście w bazie istnieją. Moje pliki modelu (funkcja setUp(); wygląda tak dla poszczególnych tabel):

map:
  1. <?php
  2. $this->hasMany('MapPosition', array('local' => 'map_id', 'foreign' => 'map_id'));
  3. $this->hasOne('User', array('local' => 'user_id', 'foreign' => 'user_id'));
  4. ?>


map_position:
  1. <?php
  2. $this->hasOne('Map', array('local' => 'map_id', 'foreign' => 'map_id'));
  3. ?>


user:
  1. <?php
  2. $this->hasMany('GoogleMap', array('local' => 'user_id', 'foreign' => 'user_id'));
  3. ?>


Chciałem wyciągnąć z bazy danych pozycje map (z tabeli map_position), gdzie user_id jest jakieś, user_hash (przechowany w tabeli `user`) jest jakiś, map_id oraz map_hash (przechowany w tabeli map) posortowany po map_postion_order (w tabeli map_position).
Efektem tego jest konieczność złączenia wszystkich 3 tabel.

W SQL napisał bym tak:
  1. SELECT * FROM map m INNER JOIN user u ON u.user_id = m.user_id INNER JOIN map_position pos ON pos.map_id = m.map_id WHERE u.user_id = X AND u.user_hash = 'X' AND m.map_id = X AND m.map_hash = 'X' ORDER BY pos.position_order;


W Doctrine próbowałem stworzyć to w ten sposób:
  1. <?php
  2. $pQuery = Doctrine_Query::create();
  3.  
  4. $pResult = $pQuery->from('Map m')->innerJoin('m.User u')->innerJoin('gm.MapPosition pos')->where("m.map_id = '" . $aMapID . "'")->addWhere("m.map_hash = '" . $aMapHash . "'")->addWhere('u.user_id = ?')->addWhere('u.user_hash = ?')->orderBy('pos.position_order')->execute(array($aUserID, $aUserHash), Doctrine::FETCH_ARRAY);
  5. ?>


W efekcie tego Doctrine wygenerowało mi do bazy jakieś zupełnie bzdurne 2 zapytania:
  1. SELECT DISTINCT u2.user_id FROM user u2 INNER JOIN map g3 ON u2.user_id = g3.user_id INNER JOIN map_position g4 ON g3.map_id = g4.map_id WHERE g3.map_id = '5' AND g3.map_hash = '4600edb6b7122d7e97f5fab6ef0afb50' AND u2.user_id = ? AND u2.user_hash = ? - (1, kj5675k7jn467jkj54y6nklj54ynk54 )
  2.  
  3. SELECT u.user_id AS u__user_id, u.first_name AS u__first_name, u.last_name AS u__last_name, u.user_email AS u__user_email, u.user_password AS u__user_password, u.user_isactive AS u__user_isactive, u.user_hash AS u__user_hash, u.date_added AS u__date_added, g.map_id AS g__map_id, g.user_id AS g__user_id, g.map_hash AS g__map_hash, g.map_seesion_id AS g__map_seesion_id, g.file_name AS g__file_name, g.is_active AS g__is_active, g.date_added AS g__date_added, g2.gps_id AS g2__gps_id, g2.map_id AS g2__map_id, g2.gps_latitude AS g2__gps_latitude, g2.gps_longitude AS g2__gps_longitude, g2.gps_order AS g2__gps_order FROM user u INNER JOIN map g ON u.user_id = g.user_id INNER JOIN map_position g2 ON g.map_id = g2.map_id WHERE u.user_id IN ('1') AND g.map_id = '5' AND g.map_hash = '4600edb6b7122d7e97f5fab6ef0afb50' AND u.user_id = ? AND u.user_hash = ? - (1, kj5675k7jn467jkj54y6nklj54ynk54 )


Powyższe zapytania skopiowane są z paska Symfony. To jakiś kosmos... przynajmniej jak dla mnie.

Podobny kosmos otrzymałem przy połączeniu innerJoin w innej kolejności:
from(user)->innerJoin(map)->innerJoin(MapPosition);

Dopiero przy takim połączeniu uzyskałem oczekiwany rezultat:
  1. <?php
  2. $pResult = $pQuery->from('MapPosition pos')->innerJoin('pos.Map gm')->innerJoin('gm.User u')->where("gm.map_id = '" . $aMapID . "'")->addWhere("gm.map_hash = '" . $aMapHash . "'")->addWhere('u.user_id = ?')->addWhere('u.user_hash = ?')->execute(array($aUserID, $aUserHash), Doctrine::FETCH_ARRAY);
  3. ?>


Czy ktoś mi powie, czy powinienem się kierować jakimiś innymi regułami w Doctrine niż w SQL (przy charakterystyce budowy zapytań), czy to kolejny bug w doctrine?

Dzięki
Rafał