CakePHP 2.x深度关联的可包含行为条件

时间:2013-01-25 18:52:54

标签: cakephp

我有这样的模特关系:

Project hasMany SubProject hasMany Item

我想设置一个containable数组,以便找到属于特定Item的所有Project,并对结果进行分页。所以,在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,但我觉得这不应该是必要的。

看起来这应该是显而易见的,但唉,解决方案让我感到厌烦。

2 个答案:

答案 0 :(得分:9)

我最终解决了这个问题,所以我想我会解释我做了什么,希望它可以帮助别人。

在阅读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。在视图代码中进行了一些小的调整,以适应稍微不同的结果数组结构,并且我已经完成了设置。

答案 1 :(得分:1)

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

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