2009-11-17 18 views
9

Ich habe einige Probleme mit CakePHP find() -Methode und Bedingungen in 'tiefer' Modell Assoziationen. Es gibt einige davon, aber ich konnte bisher keine Antwort finden.Bedingungen in verknüpften Modellen mit Model-> find() (CakePHP)

Meine Modellassoziationen sind User hasMany Post hasMany Comment hasMany Vote bzw. Vote belongsTo Comment belongsTo Post belongsTo User. Die belongsTo Assoziationen verwenden innere Joins ('type =>' INNER ').

Wie finde ich alle Kommentarstimmen für Beiträge eines bestimmten Benutzers mit CakePHPs modell-> find() -Methode?

Ich habe bewusst eine Kette von vier Modellen verwendet, weil dies für Bedingungen in direkt verbundenen Modellen zu funktionieren scheint. Daher wird die Fremdschlüsselhaltungsspalte in der benachbarten Tabelle nicht verwendet (Bedingung 'Post.user_id == 1' anstelle von 'User.id == 1').

In SQL dies wäre:

SELECT v.* 
FROM votes v 
    JOIN comments c ON (v.comment_id = c.id) 
    JOIN posts p ON (c.post_id = p.id) 
    JOIN users u ON (p.user_id = u.id) 
WHERE u.id = 1 

vermag ich nicht zu reproduzieren diese schließt sich FIND() + das Contain Verhalten. Obwohl ich einfach einen Benutzer mit all seinen Daten bekommen könnte, müsste ich dann alle Stimmen aus dem resultierenden Array sammeln.

Es ist nicht wie diese Arbeit (Achtung: unbekannt Spalte 'User.id'):

$this->Vote->recursive = 2; // or higher 
$this->Vote->find('all',array('conditions' => array('User.id' => 1))); 

In der Tat ist dies auch nicht statt Benutzer mit Post arbeiten (Vote-> Kommentar-> Post) sobald ich die Bedingung hinzufüge. Die hergestellte SQL-Abfrage verknüpft nur Stimmen und Kommentare.

Das zurückgebende Array sollte nur die Stimmen enthalten, die die obige SQL-Abfrage zurückgeben würde, alles andere sollte dabei "zusammengeführt" werden.

Hinweis: Meine Frage ist ganz in der Nähe dieser, die mir geholfen, die ersten Schritte: In cakephp how can I do a find with conditions on a related field?

+0

Gibt es einen Grund, warum Sie mehrere AngleTo vermeiden? – cp3

+0

Sie meinen, Sie haben eine Fremdschlüsselspalte user_id in der Vote-Tabelle und können Benutzer und Vote direkt zuordnen? Das scheint ein wenig überflüssig zu sein und schafft zirkuläre Beziehungen in meinem Schema. "Nachdem ich das gesagt habe, würde es funktionieren, denke ich. Oder missverstehe ich, was du unter multiple selectsTo bedeutest? Wenn ja, ist es möglich/notwendig, explizit eine Assoziation für Vote belongTo User hinzuzufügen und sie so zu konfigurieren, dass sie Kommentare und Abstimmungen "durchläuft"? – Wolfram

+0

Das Hinzufügen eines Fremdschlüssels zu jeder Tabelle, der er durch eine andere Tabelle zugeordnet ist, wäre viel zu redundant. – BWelfel

Antwort

16
$joins = array(
      array('table'=>'comments', 
       'alias' => 'Comment', 
       'type'=>'inner', 
       'conditions'=> array(
       'Comment.id = Vote.comment_id' 
      )), 
      array('table'=>'posts', 
       'alias' => 'Post', 
       'type'=>'inner', 
       'conditions'=> array(
       'Post.id = Comment.post_id' 
      )), 
      array('table'=>'users', 
       'alias' => 'User', 
       'type'=>'inner', 
       'conditions'=> array(
       'User.id = Post.user_id','User.id'=>$user_id 
      )) 
     ); 

$votes = $this->Vote->find('all',array('joins'=>$joins,'recursive'=>-1)); 
+0

Super upvote ... Danke mate .. Ich war so schwer mit diesen Joins, Referenz dieses Codes hat mir geholfen ... – Fr0zenFyr

1

Dieses eine jener Zeiten sein können Sie die query method verwenden müssen.

SQL-Aufrufe, die Sie nicht über andere Modellmethoden vornehmen können oder wollen (vorsichtig - es gibt nur wenige Umstände, die zutreffen), können Sie mit der Methode query() des Modells durchführen.

$votes = $this->Vote->query('SELECT Vote.* FROM votes Vote 
    JOIN comments Comment ON (Vote.comment_id = Comment.id) 
    JOIN posts Post ON (Comment.post_id = Post.id) 
    JOIN users User ON (Post.user_id = User.id) 
    WHERE User.id = 1'); 

würde Dies sollte eine Reihe von Vote Einträge wie die Methode find zurückzukehren.

foreach ($votes as $vote): 
    echo $vote['Vote']['id']; 
endforeach; 
+0

Danke, ich bin mir der Funktion query() bewusst, für die es verwendet wird, aber ich wollte wirklich wissen, wie man mit find() das Modell "laufen lässt", um eine Bedingung woanders zu injizieren. – Wolfram

0

Anstatt eine benutzerdefinierte SQL-Abfrage auszuführen, können Sie die Tabellen explizit verknüpfen, um nach einem Feld einer indirekt zugeordneten Tabelle zu filtern. Werfen Sie einen Blick auf diese Seite, um zu sehen, wie die Stimmen und Nutzer durch Kommentare zu verbinden: http://book.cakephp.org/view/872/Joining-tables

7

das Contain Verhalten Verwenden Bedingungen auf zugehörigen Modelle auszuführen. Es hat mich etwas gekostet, das auszugraben, aber es funktioniert wie ein Zauber! Und es verwendet LEFT JOINs, so dass es immer noch alle Werte für das ursprüngliche Modell eingibt.

See documentation.

So etwas sollte funktionieren:

$this->Vote->Behaviors->attach('Containable'); 
$this->Vote->find('all',array(
          'contain'=>array(
           'Comment'=>array(
            'Post'=>array(
             'User'=>array(
              'conditions'=>array(
               'User.id'=>1, 
              ), 
             ), 
            ), 
           ), 
          ), 
         )); 

Und wenn Sie die Benutzerdaten der Person schließen wollen, die man einfach gestimmt könnte man mehr Artikel in den Anfang Array hinzufügen:

$this->Vote->Behaviors->attach('Containable'); 
$this->Vote->find('all',array(
          'contain'=>array(
           'Comment'=>array(
            'Post'=>array(
             'User'=>array(
              'conditions'=>array(
               'User.id'=>1, 
              ), 
             ), 
            ), 
           ), 
           'User', 
          ), 
         )); 

Ich hoffe, das hilft!

+1

Ich bekomme ein anderes Ergebnis, wenn Sie diese Technik versuchen: die Bedingung gilt nur für 'Benutzer'. Wenn die Bedingung nicht erfüllt ist, wird nur "Benutzer" beendet, während alle Stimmen zurückgegeben werden. In Wirklichkeit habe ich in meinem Code HABTM-Beziehungen, so dass ich nicht einmal 'Benutzer' zum ursprünglichen Array hinzufügen kann, weil Cake beschwert, dass Vote nicht mit dem Benutzer verknüpft ist. Auf jeden Fall scheint die Bedingung nur für das Blatt zu gelten, nicht für den ganzen Baum, wenn ich den ganzen Baum haben wollte. –

+0

Ich hoffe, Ihre Antwort wird mich in meinem eigenen Problem hepen. Nach 10 Minuten versuche ich in meinem Zusammenhang, es klappt, super! Denken Sie daran, setzen Sie 'public $ actsAs = array ('Containable');' in 'AppModel' Klasse. –

Verwandte Themen