繁体   English   中英

CakePHP:使用多级可包含行为

[英]CakePHP: Using multilevel Containable Behaviour

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

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

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

我想要实现的是,使用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;

我使用'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...
...

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

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

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

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

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

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

这样的事情

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

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

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

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

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

惠斯特我喜欢api55的解决方案,我认为结果有点乱 - 取决于你打算用数据做什么我猜。

我假设当你说使用'join'方法时你正在讨论使用这种方法:

$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中使用可包含的行为。 值得考虑。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM