CakePHP:使用多级可包含行为

Noe*_*tin 6 php cakephp behavior

我已经花了一些时间尝试在CakePHP中使用Containable Behavior,但我无法让它像我预期的那样工作.

我的应用程序是不同的,但为了简化,我将把这个例子.假设我有一个包含线程和活动的论坛,可以对活动进行评级.一般关系是:

论坛:hasMany [Thread]
主题:belongsTo [论坛],hasMany [活动]
活动:belongsTo [主题],hasMany [评分]
评分:belongsTo [活动]

我想要实现的是,使用find方法,获得在某个论坛上执行的所有评级.我认为应该做的是以下内容:

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

但结果查询是:

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

我使用'join'选项完成了这个,但它更复杂,我必须在很多情况下使用这种动作.

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

谢谢

更新23/11/2011

在调查框架后,感谢Moz Morris和api55的答案,我找到了问题的根源.

基本的问题是,正如我所理解的CakePHP,我以为它每次都在使用连接进行查询.它不会这样做的事情,它将获得我正在寻找的结果的实际操作将是这样的:

SELECT * FROM Rating JOIN Activity...
SELECT * FROM Activity JOIN Thread...
SELECT * FROM Activity JOIN Thread...
...
Run Code Online (Sandbox Code Playgroud)

这意味着它将进行查询以获取所有活动,然后,对于每个活动,执行查询以获取线程...我的方法失败不是因为使用了可包含行为错误,而是因为'条件'选项已应用于所有查询,并且在第一个查询中,由于缺少Thread表而崩溃.找到这个后,有两种可能的解决方案:

  • 正如api55所说,使用'contains'数组中的条件,它只会将它们应用于使用Thread表的查询.但是这样做仍然存在问题,因为我们有太多的查询.

  • 正如Moz Morris所说,将Thread模型绑定到Rating也会起作用,它会执行单个查询,这就是我们想要的.问题在于,我认为这是一个跳过模型之间的关系而不遵循CakePHP哲学的补丁.

我将api55解决方案标记为正确,因为它解决了我遇到的具体问题,但两者都解决了问题.

api*_*i55 5

首先,您是否将actAs包含在appModel中?没有它这个beahaviour根本不会工作(我发现它没有正常工作,因为它没有与Thread表连接)

我会从顶部做到这一点,我的意思是从论坛,所以你选择你的论坛(我不确定你想要论坛或线程)并得到它的所有评级,如果没有评级你将最终评级键为空.

这样的事情

appModel

public $actsAs = array('Containable');
Run Code Online (Sandbox Code Playgroud)

评级控制器

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

然后,如果您只需要一个评级表中的值,只需使用Set:extract来获取此值的数组.

正如你所做的那样,IT应该继续工作,但我不会在那里使用forum_id,但在内部条件包含这样的

'contain' => array(
    'Activity' => array(
        'Thread' => array(
              'conditions' => array('Thread.forum_id' => 1)
         )
    )
),
Run Code Online (Sandbox Code Playgroud)

此外,永远不要忘记使用可包容的行为(或在应用程序模型中)中的actsAs变量