2009-11-17 18 views
9

CakePHPのfind()メソッドと「より深い」モデルの関連付けに問題があります。これらの中にはいくつかのものがありますが、私はこれまでこれに対する答えを見つけることができませんでした。Model-> find()(CakePHP)を使用した関連モデルの条件

私のモデルの関連付けはそれぞれUser hasMany Post hasMany Comment hasMany VoteVote belongsTo Comment belongsTo Post belongsTo Userです。 belongsToアソシエーションは内部結合を使用します( 'type' => 'INNER')。

CakePHPのmodel-> find()メソッドを使って、特定のユーザーの投稿に対するコメント投票をすべて見つけるにはどうすればよいですか?

私は4モデルのチェーンを意図的に使用しました。これは、直接関連付けられたモデルの条件で動作するように思われるためです。したがって、隣接するテーブルには外部キー保持列を使用しません( 'User.id == 1'の代わりに 'Post.user_id == 1'という条件)。

SQLでは、これは次のようになります。

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 

が、私はこれらを検索()+収容可能振る舞いを使用して参加し再現することができません。私は単純に彼のすべてのデータを持つユーザーを得ることができますが、結果の配列内からすべての投票を収集する必要があります。

それはこのように動作していません(警告:不明な列 'User.idを'):

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

実際には、これでも代わりに、ユーザーのポストを使用して動作しません(Vote-> COMMENT->私が条件を加えるとすぐに)。製造されたSQLクエリは投票とコメントにのみ参加します。

返される配列には、上記のSQLクエリが返す票しか含まれていない必要があります。他のすべては、プロセスで「結合され」なければなりません。

注: In cakephp how can I do a find with conditions on a related field?

+0

複数のbelongsToを避ける理由はありますか? – cp3

+0

投票テーブルに外部キー列user_idがあり、ユーザーと投票を直接関連付けることを意味しますか?それは少し冗長で、私のスキーマに循環関係を作成するようです。 "それは"それは私が推測することができると述べた。または、私はあなたが複数のbelongsToの意味を誤解していますか?そうであれば、Vote belongsTo Userのアソシエーションを明示的に追加し、コメントと投票を「通過」するように設定することは可能ですか? – Wolfram

+0

別のテーブルを使用して関連付けられているすべてのテーブルに外部キーを追加すると、冗長すぎることになります。 – BWelfel

答えて

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 ...ありがとうございました。私はこれらの結合で非常に苦労していました。このコードの参照は私を助けました... – Fr0zenFyr

1

これは、あなたがquery methodを使用する必要が当時のものであってもよい:私の質問は、始める私を助けたこの1、に非常に近いです。

モデルのquery()メソッドを使用して、他のモデルメソッドでは作成できない、または作成したくないSQL呼び出し(注意が必要 - ほとんどありません)。

$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'); 

これは、findメソッドのような投票エントリの配列を返す必要があります。

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

ありがとう、私はquery()関数とそれが使われていることを認識していますが、find()を使って他の場所に条件を注入する "モデルを歩く"方法を本当に知りたかったのです。 – Wolfram

0

ではなく、カスタムSQLクエリを実行するには、明示的に間接的に関連するテーブルのフィールドでフィルタするために、テーブルを結合することができます。コメントを通じて投票してユーザーを参加させる方法を確認するために、このページを見て: http://book.cakephp.org/view/872/Joining-tables

7

は、関連するモデル上の条件を実行して収容可能振る舞いを使用します。これを掘るのに私は少し時間がかかりましたが、それは魅力のように機能します! LEFT JOINを使用するので、元のモデルのすべての値が引き出されます。

See documentation

このような何かが動作するはずです:

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

そして、あなたはあなたは、単に最初のアレイに1台以上のアイテムを追加することができ投票した人のユーザデータを含めるしたい場合:

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

希望が助けてくれる!

+1

このテクニックを試してみると、私は別の結果を得ています:条件は 'User'にのみ適用されます。条件が満たされない場合、すべてのVotesが返される間、「User」のみがNULLになります。実際には、私のコードでは、Cakeが投票がユーザーに関連付けられていないと不平を言うので、元の配列に「ユーザー」を追加することさえできないようなHABTM関係を持っています。いずれにせよ、私にとっては、条件は葉にのみ適用され、ツリー全体を必要としていないときは全体のツリーに適用されないようです。 –

+0

あなたの答えが私自身の問題で私を助けてくれることを願っています。 10分後、私は自分の文脈で試してみる。覚えておいて、 'public $ actsAs = array( 'Containable');を' AppModel'クラスの中に入れてください。 –

関連する問題