CakePHP 中的多级模型关联

Posted

技术标签:

【中文标题】CakePHP 中的多级模型关联【英文标题】:Multi-level Model associations in CakePHP 【发布时间】:2012-03-27 20:24:12 【问题描述】:

我正在使用 Cakephp 构建一个电子学习网站,其中包含以下模型:课程、测试、问题、答案等。

这是我的联想:

课程有很多测试 测试属于课程 问题属于测试 问题有很多答案 答案属于问题

这种模型关联在大多数情况下都能正常工作。例如,Course 的烘焙 CRUD 动作知道有属于它的测试,问题知道它们有关联的答案,等等......

但我正在尝试编写一个在 TestsController 中运行的测试管理工具,并且关联级别以 Question 结束。没有答案。换句话说,我正在处理的视图默认情况下来自烘焙的 TestsController:

Array
(
[Test] => Array
    (
        [id] => 1
        [name] => Test 1
        [course_id] => 1
        [time_limit] => 30
        [max_questions] => 20
        [randomize_order] => 1
        [num_questions] => 2
    )

[Course] => Array
    (
        [id] => 1
        [course_identifier] => TLE1001
        [title] => Child Development I
        [description] => 
    )

[Question] => Array
    (
        [0] => Array
            (
                [id] => 1
                [text] => What is your name?
                [test_id] => 1
                [order] => 0
            )

        [1] => Array
            (
                [id] => 2
                [text] => What is my name?
                [test_id] => 1
                [order] => 0
            )

    )

)

如您所见,我视图中的 $test 数组在 Question 处停止,并且不会为 Question(s) 提取相关的 Answer(s)。

我通过更改 TestsController 中“视图”操作的底部来解决此问题:

$test = $this->Test->read(null, $id);
$test['Question'] = $this->Test->Question->find('all'); //I added this line...
$this->set('test', $test);

我添加了中间行,因此它在设置 $test 数组以供视图使用之前手动替换了 $test['Question'] 的所有内容。

结果如下:

Array
(
[Test] => Array
    (
        [id] => 1
        [name] => Test 1
        [course_id] => 1
        [time_limit] => 30
        [max_questions] => 20
        [randomize_order] => 1
        [num_questions] => 2
    )

[Course] => Array
    (
        [id] => 1
        [course_identifier] => TLE1001
        [title] => Child Development I
        [description] => The first years of life offer a window of opportunity for a child’s development. A solid understanding of how children grow and develop is essential to providing a quality care environment.
    )

[Question] => Array
    (
        [0] => Array
            (
                [Question] => Array
                    (
                        [id] => 1
                        [text] => What is your name?
                        [test_id] => 1
                        [order] => 0
                    )

                [Test] => Array
                    (
                        [id] => 1
                        [name] => Test 1
                        [course_id] => 1
                        [time_limit] => 30
                        [max_questions] => 20
                        [randomize_order] => 1
                        [num_questions] => 2
                    )

                [Answer] => Array
                    (
                        [0] => Array
                            (
                                [id] => 1
                                [question_id] => 1
                                [text] => My name is what I say it is.
                                [correct] => 1
                            )

                        [1] => Array
                            (
                                [id] => 2
                                [question_id] => 1
                                [text] => My name is Earl.
                                [correct] => 
                            )

                    )

            )

        [1] => Array
            (
                [Question] => Array
                    (
                        [id] => 2
                        [text] => What is my name?
                        [test_id] => 1
                        [order] => 0
                    )

                [Test] => Array
                    (
                        [id] => 1
                        [name] => Test 1
                        [course_id] => 1
                        [time_limit] => 30
                        [max_questions] => 20
                        [randomize_order] => 1
                        [num_questions] => 2
                    )

                [Answer] => Array
                    (
                        [0] => Array
                            (
                                [id] => 3
                                [question_id] => 2
                                [text] => None of your business
                                [correct] => 1
                            )

                        [1] => Array
                            (
                                [id] => 4
                                [question_id] => 2
                                [text] => Jim
                                [correct] => 
                            )

                    )

            )

    )

)

这适用于我必须完成的工作,但对我来说似乎很难看。如您所见,答案已加载,但我现在也有重复的信息,因为当它加载问题模型时,它会拉入相关的测试。而且我很确定这不符合 CakePHP 约定...

有没有更好的方法来做到这一点? CakePHP 是否只为模型关联建立关联数据数组到一定级别然后停止?

附:我尝试添加:

var $uses = array('Test', 'Question', 'Answer');

...到我的 TestsController 的顶部,但它没有解决问题并且似乎没有任何效果。

必须有更好的方法让 CakePHP 加载所有相关的数据模型以及它们的关联......

【问题讨论】:

【参考方案1】:

使用 CakePHP 的可包含行为: http://book.cakephp.org/1.3/view/1323/Containable

我认为对于您的具体情况,查询看起来像:

$this->Test->find('all', array(
    'contain'=>array('Question')
    )
);

您还可以使用条件、排序等。

【讨论】:

该查询对我来说也没有任何改变。结果 $test 仍然只有问题,没有答案。我查看了您发送的链接并尝试了这个:$test = $this->Test->find('all', array('contain' => array('Question' => array('Answer')))); 这也不起作用。我也试过只输入'contain'=>array('Answer'),但这不起作用 错误是什么?此外,这取决于您的 CakePHP 版本 - 在某些早期版本中,您可能必须显式添加 Containable 行为。【参考方案2】:

我使用了似乎可以做到的递归属性。

$test = $this->Test->find('all', array('recursive' => 2));

告诉 CakePHP 加载另一个级别的关联,因此结果不仅包括问题,还包括相关的答案。

【讨论】:

是的,也可以。对于大型查询和大量记录,它的效率会有点低,因为它可以有效地获取所有内容,但对于小型查询应该没问题。

以上是关于CakePHP 中的多级模型关联的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 cakephp 3 在不同数据库中的模型之间进行关联?

Cakephp 3 保存关联属于ToMany

CakePHP 模型关联深层模型包含

CakePHP 3:保存关联模型失败

CakePHP 多模型关联

CakePHP 2.1 - 模型关联 - 保存和查找