【问题标题】:CakePHP 2.x containable behavior conditions on deep associationsCakePHP 2.x 深度关联上的可包含行为条件
【发布时间】:2013-01-31 17:33:32
【问题描述】:

我有这样的模型关系:

ProjecthasMany SubProjecthasMany Item

我想设置一个containable 数组,这样我就可以找到属于特定Project 的所有Items,并对结果进行分页。所以,在我的ItemsController 我有:

public $paginate = array(
  'Item' => array(
    'limit' => 10,
    'order' => array('
      'Item.create_time' => 'desc'
    ),
    'contain' => array(
      'SubProject' => array(
        'Project'
      )
    )
  )
);

显然,我需要在某处放置"SubProject.project_id = $pid" 之类的条件,但我尝试过的任何方法都不会产生正确的结果。我能做到的最好结果是如下所示:

Array
(
[0] => Array
    (
        [Item] => Array
            (
                [id] => 13
                [file_name] => foo.tar.gz
                .... other keys ...
                [create_time] => 2013-01-23 14:59:49
                [subProject_id] => 4
            )

        [SubProject] => Array
            (
                [id] => 4
                [name] => foo
                [project_id] => 2
                ..... other keys ....
                [Project] => Array
                    (
                    )

            )

    )
 [1] => Array
 .....

编辑:省略不匹配的项目记录是完全正确的;我想跳过没有匹配项目记录的任何项目记录。

我想到了manually specify my joins,但我觉得没有必要。

这似乎应该是显而易见的,但是,解决方案让我无法理解。

【问题讨论】:

  • 除了我在问题中提到的hasMany 关系(以及相关的belongsTo 关系)之外,模型真的没有任何东西。
  • 为什么不使用 $pid 查找子项目,然后提取 $subpids(可能使用 Set::extract),然后使用 $subpids 对项目进行分页?
  • 我想这是可能的,但这不是 Containable 设计的那种搜索吗?

标签: cakephp


【解决方案1】:

我最终确实解决了这个问题,所以我想我会解释一下我做了什么,希望它可以帮助其他人。

在阅读this blog post by Mark Story(从 1.2 时代开始但仍然相关)之后,我决定要做的事情是在我的 Item 模型中创建一个自定义查找类型,直接绑定 Project 模型。这给出了 Containable 可以正确过滤的第一级关联。

因此,在 Items 模型中,我有类似以下的内容(请参阅 the documentation 自定义查找类型)。

public $findMethods = array('byProject' => true);

public function _findByProject($state, $query, $results=array()) {
    if ($state == 'before') {
        $this->bindModel(array(
            'hasOne' => array(
                'Project' => array(
                    'foreignKey' => false,
                    'conditions' => array('Project.id = SubProject.project_id')
                )
            )
        ));
        return $query;
    }
    return $results;
}

请注意,必须将foreignKey 设置为 false 以防止 CakePHP 尝试自动使用不存在的数据库密钥。在 ItemsController 中,分页选项现在如下所示:

public $paginate = array(
    'Item' => array(
        'findType' => 'byProject',
        'limit' => 10,
        'order' => array(
            'Item.create_time' => 'desc'
        ),
        'contain' => array(
            'SubProject',
            'Project'
        ),
        'conditions' => array('Project.id' = $pid)
    ),
);

...$pid 是要显示的项目的 ID。视图代码中的一些小调整以适应略有不同的结果数组结构,我已经准备好了。

【讨论】:

  • foreignKey false 是必需的,因为您使用了 hasOne。如果使用belongsTo,则无需指定键或条件,因为project_id 是默认键
  • 好点。另外,我应该提到的是,从 find 只生成单个 SQL 查询的意义上说,这具有更高效的额外好处。
  • 一次查询就可以获取数据并不意味着它是最有效的。
【解决方案2】:

编辑 ================

public $paginate = array(
    'limit' => 10,
    'order' => 'Item.create_time DESC',      //'order' => array(''Item.create_time' => 'desc'),
    'contain' => array(
        'SubProject' => array(
            'Project' => array(
                'conditions' => array(
                    'id' => $project_id    // Passed parameter
                )
            )
        )
     )
);

================================================ ==

您是否尝试过如下使用conditions?另外,我没有按照您的方式编写代码的“订单”部分。

public $paginate = array(
    'Item' => array(
        'limit' => 10,
        'order' => 'Item.create_time DESC',      //'order' => array(''Item.create_time' => 'desc'),
        'contain' => array(
            'SubProject' => array(
                'Project' => array(
                    'conditions' => array(
                        'id' => $project_id    // Passed parameter
                    )
                )
            )
        )
     )
);

【讨论】:

  • 是的,这是我尝试过的众多方法之一(我刚刚再次检查过)。结果仍然包括所有 Item 条目,正如我在问题中解释的那样(为了清楚起见,我将编辑该部分)。
  • 好的...也许您不应该在其中包含Item,因为您是从ItemsController 函数调用它...我会用我的意思更新我的答案
  • 没有任何区别——正如 in the docs 所说,将模型名称作为顶级键是有效的,因此您可以为多个模型设置分页选项。
  • +1 帮助我思考这个问题,我真的很感激。最终的解决方案有些不同。我已将其发布为另一个答案。
  • 感谢您发布解决方案。其他值得学习的东西!
猜你喜欢
  • 1970-01-01
  • 2015-04-03
  • 2012-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多