【问题标题】:CakePHP: Using multilevel Containable BehaviourCakePHP:使用多级可包含行为
【发布时间】:2011-11-22 12:10:20
【问题描述】:

我尝试在 CakePHP 中使用 Containable Behavior 已经有一段时间了,但我无法让它按预期工作。

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

论坛:hasMany [主题]
主题:belongsTo [论坛]、hasMany [活动]
活动:belongsTo [Thread]、hasMany [Rating]
评分:属于 [Activity]

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

我已经使用 'joins' 选项完成了这项工作,但它更复杂,而且我必须在许多情况下使用这种操作。

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

谢谢

2011 年 11 月 23 日更新

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

基本问题是,根据我对 CakePHP 的理解,我认为它每次都使用连接进行查询。它不这样做的事情,它为获得我正在寻找的结果而执行的实际操作将是这样的:

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

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

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

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

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

【问题讨论】:

    标签: php cakephp behavior


    【解决方案1】:

    首先,你有没有把actAs 可包含变量放在appModel 中??没有它,这种行为根本不起作用(我发现它不能正常工作,因为它没有加入 Thread 表)

    我会从顶部开始,我的意思是从论坛,所以你选择你的论坛(我不确定你想要论坛或主题)并获得它的所有评级,如果没有评级,你最终会得到评级键为空.

    类似的东西

    应用模型

    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 获取该值的数组。

    正如你所做的那样,它应该可以工作,但我建议不要在那里使用 forum_id,但在里面包含这样的条件

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

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

    【讨论】:

    • 在 Thread 数组中移动“条件”将不起作用,因为其他所有内容仍会返回结果,而“Thread”数组为空。
    • @MozMorris 是的,因为是左加入...但是如果他从顶部(来自论坛/线程)运行它,它将获得所有评级或为空,尽管它会有很多烦人树(我通常使用可链接行为)
    • 感谢您的回复。我在链接上提供的代码上进行了尝试,查询是SELECT COUNT(*) AS count FROM forums AS Forum WHERE Forum.id = 1。我已经在 AppModel 和所有东西上设置了 Containable Behavior。不知道是不是配置有问题还是什么,但好像不能正常工作。
    • @NoelDeMartin 100% 确保您正在正确加载行为您可以在控制器中编写以下代码$this->Rating->Behaviors->attach('Containable'); 这是出于测试目的...如果您正在调用 find来自论坛做$this->Rating->Activity->Thread->Forum->Behaviors->attach('Containable')
    • @api55 我已经用最终解决方案更新了问题,感谢您的回答,它帮助我找到了问题。
    【解决方案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 中使用可包含行为。值得考虑。

    【讨论】:

    • 如果您需要计数,那么显然只需将“全部”替换为“计数”即可。 :)
    • 我从没想过那个 XD,但它确实更干净,其他方式提供了许多递归......
    • 感谢您的回答,这将适用于此示例。问题在于,在实际应用程序中,我必须多次执行此操作,并且我希望它更加模块化(拥有一个包含“启用”模型的数组以供使用)。照你说的做我也应该每次都设置好所有的条件。此外,它让我觉得它不起作用,这就是 Containable Behavior 的用途,我不知道我是否遗漏了什么。还是谢谢你。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-03
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    • 2011-11-06
    • 2012-10-23
    • 1970-01-01
    相关资源
    最近更新 更多