2009-04-30 9 views
14

kann mir jemand sagen, wie man verbundenes Ergebnis aus mehreren Tabellen in CakePHP (mit CakePHP MVC-Architektur) abrufen. Zum Beispiel habe ich drei Tabellen zu verbinden (tbl_topics, tbl_items, tbl_votes. Ihre Beziehung ist wie folgt definiert: ein Thema kann viele Elemente und ein Element kann viele Stimmen haben. Jetzt möchte ich eine Liste von Themen mit der Anzahl von abrufen . alle Stimmen auf allen Einzelteilen für jedes Thema für diese SQL-Abfrage wird unten geschrieben:Wie schreibe ich eine Join-Abfrage über mehrere Tabellen in CakePHP?

SELECT Topic.*, count(Vote.id) voteCount 
FROM 
tbl_topics AS Topic 
LEFT OUTER JOIN tbl_items AS Item 
ON (Topic.id = Item.topic_id) 
LEFT OUTER JOIN tbl_votes AS Vote 
ON (Item.id = Vote.item_id); 

Mein Problem ist, ich es mit tun kann leicht $this-><Model Name>->query Funktion, aber das SQL-Code erfordert in der Steuerung geschrieben werden die I Ich versuche, eine andere Möglichkeit zu finden (find()).

Antwort

2

Ich werde hier ehrlich sein und sagen, dass Sie wahrscheinlich viel glücklicher sein werden, wenn Sie nur eine Funktion erstellen im Ihr Modell, etwas wie getTopicVotes() und Aufruf von query() dort. Jede andere Lösung, die mir einfällt, wird es nur komplizierter und damit hässlicher machen.

Edit:

auf die Größe Ihrer Daten Je und vorausgesetzt, Sie haben richtig Ihr Modell Beziehungen einrichten (Thema hasMany Artikel hasMany Stimmen), könnten Sie ein einfaches Finde tun (‚alle‘) enthält alle die Einzelteile und Stimmen, und dann etwas tun, wie folgt aus:

foreach ($this->data as &$topic) 
{ 
    $votes = Set::extract('/Topic/Item/Vote', $topic); 
    $topic['Topic']['vote_count'] = count($votes); 
} 

Zwei Dinge sind wichtig:

  1. Wenn Sie eine Menge von Daten haben, y Man sollte diesen Ansatz wahrscheinlich vergessen, es wird langsam sein.
  2. Ich habe das von meinem Speicher geschrieben und es könnte so nicht im wirklichen Leben aussehen und/oder es kann
-2

Sie sollten überhaupt nicht :-) arbeiten studieren HABTM (Hat und gehört Many)

+0

Ich verstehe es nicht, wie funktioniert HABTM hier gelten? –

+0

Versuchen Klasse Artikel mit erstreckt AppModel { var $ belongsTo = array ('Topic') } – drikoda

+0

Ist das nicht für zwei Tabellen HABTM, wo die Frage nach fragt drei Beitritt? – SeanDowney

1

Was Sie brauchen, ist rekursive Assoziationen Unterstützung, die derzeit mit dem Lager CakePHP nicht möglich ist.
Obwohl es unter Verwendung einiger bindModel trickery
oder einer experimentellen RecursiveAssociationBehavior erreicht werden konnte.

Bei beiden Lösungen müssen Sie entweder zusätzlichen Code verwenden oder sich auf ein Verhalten in Ihrer Anwendung verlassen. Wenn Sie jedoch der Versuchung widerstehen, reinen SQL-Code zu schreiben, werden Sie mit Cake-Seitenzahlen belohnt , automatische Bedingungen, Modellmagie usw.

2

Sie können die Eigenschaft "recursive" für eine Abfrage find() einfach festlegen.

$result = $this->Topic->find('all', array('recursive' => 2)); 

Alternativ können Sie das Containable-Verhalten in Ihrem Modell verwenden.Dann können Sie verwenden:

$this->Topic->contain(array(
    'Item', 
    'Item.Vote', 
)); 

$result = $this->Topic->find('all'); 

oder

$result = $this->Topic->find('all', array(
    'contain' => array(
     'Item', 
     'Item.Vote', 
    ), 
)); 
+0

Ich habe versucht, 'contain' zu verwenden, wie Sie beschrieben haben, und es funktioniert nicht. Außerdem würde ich davon abraten, 'rekursiv = 2' zu verwenden, denn wenn Sie viele Assoziationen haben, verstopfen Sie Ihre App. –

+0

@Alex: Es gab einen Fehler in meinem Beispiel. Ich habe es repariert. Stellen Sie sicher, dass dem Modell das Containable-Verhalten hinzugefügt wird! –

38
$markers = $this->Marker->find('all', array('joins' => array(
    array(
     'table' => 'markers_tags', 
     'alias' => 'MarkersTag', 
     'type' => 'inner', 
     'foreignKey' => false, 
     'conditions'=> array('MarkersTag.marker_id = Marker.id') 
    ), 
    array(
     'table' => 'tags', 
     'alias' => 'Tag', 
     'type' => 'inner', 
     'foreignKey' => false, 
     'conditions'=> array(
      'Tag.id = MarkersTag.tag_id', 
      'Tag.tag' => explode(' ', $this->params['url']['q']) 
     ) 
    ) 
))); 

im Sinne von Artikel des nate abele: link text

+0

aus Gründen der Übersichtlichkeit zeigt das Beispiel nur, wie man Joins manuell zu einem Model :: find-Parameter hinzufügt. – jmcneese

+0

Ich werde das heute Abend für meine Tabellen testen ... – Drewdin

+3

Ihre obige Suchfunktion ruft nur Felder in der Markierungstabelle ab, nicht die anderen zwei Tabellen. –

Verwandte Themen