2015-04-18 14 views
7

Ho le seguenti tabelle DB: articoli, utenti, gruppi, itemImages. Ci sono molte e molte relazioni tra (elementi, gruppi) e (utenti, gruppi) e uno a molti tra (elementi, itemImages). Tutte le chiavi esterne appropriate sono state impostate in CakePHP come associazioni.CakePHP 3 contiene campi selezionati

Come posso costruire una query con contain() che seleziona tutti gli elementi e la loro immagine principale, che si trovano in un gruppo che è stato assegnato come gruppo principale ad un utente con un particolare id?

per renderlo più chiaro, qui è quello che una query SQL pianura sarà simile:

SELECT items.id AS itemId, items.name, itemImages.url AS itemUrl 
FROM items 
INNER JOIN groups_items ON groups_items.item_id = items.id 
INNER JOIN groups ON groups_images.group_id = groups.id 
INNER JOIN groups_users ON groups_users.group_id = groups.id 
INNER JOIN users ON groups_users.user_id = users.id 
INNER JOIN itemImages ON itemImages.item_id = items.id 
WHERE groups_users.isMainGroup = 1 
    AND users.id = :userId 
    AND itemImages.isMainImage = 1 

codice CakePHP ho per ora:

$items = $this->Items->find() 
      ->hydrate(false) 
      ->contain([ 
       'Groups.Users' => function($q) use ($userId){ 
        return $q->where(['isMainGroup' => 1, 'Users.id' => $userId]); 
       }, 
       'ItemImages' => function($q){ 
        return $q->where(['isMainImage' => 1]); 
       }, 
      ]); 
      //->select(['itemId' => 'Items.id', 'Items.name', 'itemUrl' => 'itemImages.url']); 

risposta

9

corrispondenza() metodo può aiutare con questo

$items = $this->Items->find() 
     ->hydrate(false) 
     ->select(['Items.id', 'Items.name', 'itemImages.url']) 
     ->distinct(['Items.id']) 
     ->matching('Groups.Users', function ($q) use ($userId) { 
      return $q->where(['Groups.isMainGroup' => 1, 'Users.id' => $userId]); 
     }) 
     ->matching('ItemImages', function ($q) { 
      return $q->where(['ItemImages.isMainImage' => 1]); 
     }) 
     ->contain([ 
      'ItemImages' => function ($q) { 
       return $q->autoFields(false) 
         ->select(['id','url']) 
         ->where(['ItemImages.isMainImage' => 1]); 
      } 
     ]); 

Penso, in questo caso, l'ultimo cono la dichiarazione può essere omessa, poiché il risultato desiderato è già nella proprietà _matchingData.

Nota sulla distict() stament:

Poiché questa funzione creerà un INNER JOIN, si potrebbe prendere in considerazione chiamando distinta sulla query ritrovamento come si potrebbe ottenere le righe duplicate se vostre condizioni non filtrare loro già

http://book.cakephp.org/3.0/en/orm/retrieving-data-and-resultsets.html#filtering-by-associated-data

+0

Sì, l'ultimo contengono non era necessaria - tutti i dati sono stati ALRE ady in _matchingData dalle funzioni matching(). La mia più grande domanda era come "appiattire" il risultato correttamente. Quando seleziono() in questo modo, mi dà l'url come suboject sotto la chiave "_matchingData", e vorrei che fosse allo stesso livello degli altri valori. Quello che ho fatto come soluzione alternativa era json_encode -> rimuovere tutti "_matchingData". occorrenze di stringhe -> json_decode. – user1507558

+0

Il commento sull'istruzione 'distinct' è molto utile. –