2011-11-22 58 views
6

我已經花了一段時間嘗試在CakePHP中使用可容忍行爲,但我無法讓它按預期工作。CakePHP:使用多級可容忍行爲

我的應用程序是不同的,但爲了簡化我會把這個例子。假設我有一個包含線程和活動的論壇,並且可以對活動進行評分。一般的關係是:

論壇:的hasMany [主題]
主題:屬於關聯[論壇]的hasMany [活動]
活動:屬於關聯[主題]的hasMany [評分]
評級:屬於關聯[活動]

我想要實現的是,使用find方法,獲取在某個論壇上執行的所有評級。我想應該做的是以下幾點:

$this->Rating->find('count', array(
    'contain' => array(
     'Activity' => array(
      'Thread' 
     ) 
    ), 
    'conditions' => array(
     'Thread.forum_id' => 1 
    ) 
)); 

但結果查詢:

SELECT COUNT(*) AS `count` FROM `ratings` AS `Rating` LEFT JOIN `activities` AS `Activity` ON (`Rating`.`activity_id` = `Activity`.`id`) WHERE `Thread`.`forum_id` = 1; 

我已經完成了這個使用「連接」選項,但它更復雜,我必須在許多情況下使用這種行爲。

所有用例相關的文件可以在這裏找到:http://dl.dropbox.com/u/3285746/StackOverflow-ContainableBehavior.rar

感謝

更新23/11/2011

調查的框架,並感謝萬盎司莫里斯的答案後,和api55我找到了問題的根源。

基本問題是,因爲我理解CakePHP,我認爲它每次都使用連接查詢。但它沒有做到這一點的東西,真正的操作,將進行以獲得我一直在尋找的結果會是這樣的:

SELECT * FROM Rating JOIN Activity... 
SELECT * FROM Activity JOIN Thread... 
SELECT * FROM Activity JOIN Thread... 
... 

含義,它會做一個查詢來獲取所有活動然後,對於每個活動,執行一個查詢以獲取線程......我的方法失敗的原因不在於可容錯行爲被錯誤使用,而是因爲「條件」選項適用於所有查詢,並且在第一個查詢中,它由於沒有Thread表而崩潰。發現這一點後,有兩種可能的解決方案:

  • 正如api55說,使用「包含」陣列內的條件下,將僅適用於他們使用線程表查詢。但是這樣做問題依然存在,因爲我們有太多的疑問。如Moz Morris所說,將線程模型綁定到評分也是可行的,並且它會執行單個查詢,這正是我們想要的。問題是,我將它看作是跳過模型之間關係的補丁,並且不遵循CakePHP的哲學。

我標記了api55解決方案作爲正確的,因爲它解決了我的具體問題,但都解決了問題。

回答

5

首先,你有沒有把appAmodel中的actAs包含變量?沒有它這beahaviour將無法工作(我看它是不正常工作,因爲它沒有加入螺紋表)

我會從頂部,我的意思是從論壇,所以你選擇你的論壇(即時通訊不知道你想要的論壇或線程),並獲得其所有評級,如果沒有評級你最終將評級鍵空。

像這樣

appModel

public $actsAs = array('Containable'); 

評級控制器

$this->Rating->Activity->Thread->Forum->find('count', array(
    'contain' => array(
     'Thread' => array(
      'Activity' => array(
       'Rating' => array (
         'fields' => array ('Rating.*') 
       ) 
      ) 
     ) 
    ), 
    'conditions' => array(
     'Forum.id' => 1 
    ) 
)); 

然後,如果你只需要在評級表中的值只用設置:提取得到這個數值數組。

當你做了它應該反正工作,但我sugest不forum_id有使用,但在條件裏面包含這樣

'contain' => array(
    'Activity' => array(
     'Thread' => array(
       'conditions' => array('Thread.forum_id' => 1) 
     ) 
    ) 
), 

此外,使用中可容納behaviuor永遠不會忘記在模型中actsAs變量(或在應用模式)

+0

移動Thread數組內的'conditions'將不起作用,因爲結果仍然會返回其他數據,'Thread'數組爲空。 –

+0

@MozMorris這是真的,因爲是左連接...但如果他從頂部(從論壇/線程)運行它會得到所有的評級或空,雖然它會有很多煩人的樹(我通常使用可鏈接行爲) – api55

+0

感謝您的回覆。我嘗試了我在鏈接上提供的代碼,查詢是'SELECT COUNT(*)AS count FROM forums AS Forum WHERE Forum.id = 1'。我已經在AppModel和所有內容上設置了可容忍行爲。我不知道我是否有一些配置問題或某些問題,但它似乎沒有正常工作。 –

2

惠斯特我喜歡api55的解決方案,我認爲結果有點雜亂 - 取決於你打算如何處理我想要的數據。

我認爲,當你說使用「連接」的方法,你都在談論使用這種方法:

$this->Rating->bindModel(array(
    'belongsTo' => array(
    'Thread' => array(
     'foreignKey' => false, 
     'conditions' => 'Thread.id = Activity.thread_id', 
    ), 
    'Forum' => array(
     'foreignKey' => false, 
     'conditions' => 'Forum.id = Thread.forum_id' 
    ) 
) 
)); 

$ratings = $this->Rating->find('all', array(
    'conditions' => array(
    'Forum.id' => 1 // insert forum id here 
) 
)); 

這似乎只是乾淨了一點給我,你不必擔心使用AppModel中的可包含行爲。值得考慮。

+0

如果你需要計數,那麼只需用'count'代替'all',顯然。 :) –

+0

我從來沒有想過這個XD,但它的真實更清潔,另一種方式給許多遞歸... – api55

+0

謝謝你的答案,這將在這個例子工作。問題是,在真正的應用程序中,我必須多次執行此操作,並且希望更加模塊化(使用「已啓用」模型的陣列)。做你所說的話,我應該每次都設置所有的條件。另外,它讓我感到它不起作用,這就是可容忍行爲應該是什麼,我不知道我是否錯過了一些東西。無論如何,謝謝你。 –