CakePHP Containable with HABTM

2019-07-15 09:02发布

问题:

To explain the issue I'm having, I'll use an example. Let's say that I'm building a system where students can sign up for one or more afterschool courses, but a school official has to approve the sign-up in order for it to be valid. So I have these models:

  • Course (belongs to "Teacher", hasAndBelongsToMany "Student")
  • Student (hasAndBelongsToMany "Course")
  • Teacher (hasMany "Course")

Now let's say I want to see a list of all of the unapproved sign-ups that are for ninth-graders. That's easy:

$this->request->data = $this->Student->CoursesStudent->find('all', array(
    'conditions' => array(
        'CoursesStudent.is_approved' => null,
        'Student.grade' => 9
    )
));

The thing that I'm struggling with is pulling the teacher's data as well (more than just their ID). I've tried this:

$this->request->data = $this->Student->CoursesStudent->find('all', array(
    'conditions' => array(
        'CoursesStudent.is_approved' => null,
        'Student.grade' => 9
    ),
    'contain' => array(
        'CoursesStudent',
        'Course' => array(
            'Teacher' => array(
                'fields' => array(
                    'Teacher.id',
                    'Teacher.name'
                )
            )
        ),
        'Student'
    )
));

But it doesn't have any effect whatsoever on the returned array. To make it easy for you to throw this into an existing CakePHP project to play with, here is the database schema and data and here is what you can paste into a random action of an existing CakePHP project. This is what I'm trying to get (notice that the teacher's data is there):

Array
(
    [0] => Array
        (
            [CoursesStudent] => Array
                (
                    [id] => 1
                    [course_id] => 1
                    [student_id] => 1
                    [is_approved] => 
                    [created] => 2012-12-11 00:00:00
                    [modified] => 2012-12-11 00:00:00
                )

            [Course] => Array
                (
                    [id] => 1
                    [teacher_id] => 1
                    [title] => Introduction to Improvisation
                    [start_date] => 2012-12-17
                    [end_date] => 2012-12-21
                    [created] => 2012-12-11 00:00:00
                    [modified] => 2012-12-11 00:00:00
                    [Teacher] => Array
                        (
                            [id] => 1
                            [first_name] => John
                            [last_name] => Doe
                            [created] => 2012-12-11 00:00:00
                            [modified] => 2012-12-11 00:00:00
                        )

                )

            [Student] => Array
                (
                    [id] => 1
                    [first_name] => Bill
                    [last_name] => Brown
                    [grade] => 9
                    [created] => 2012-12-11 00:00:00
                    [modified] => 2012-12-11 00:00:00
                )

        )

)

Thanks!

回答1:

You must set $recursive to -1 before using contain() will work.

Also, make sure your model is set to use the Containable Behavior. In this case, since 'Course' is also containing something, it needs to use the Containable behavior too.

(You could think about setting the below $actsAs in your AppModel to make Containable available to every model.)

//in your CoursesStudent model (and in your Course model)
public $actsAs = array('Containable');

And here's your find, but with setting recursive first:

$this->Student->CoursesStudent->recursive = -1;
$this->request->data = $this->Student->CoursesStudent->find('all', array(
    'conditions' => array(
        'CoursesStudent.is_approved' => null,
        'Student.grade' => 9
    ),
    'contain' => array(
        'CoursesStudent',
        'Course' => array(
            'Teacher' => array(
                'fields' => array(
                    'Teacher.id',
                    'Teacher.name'
                )
            )
        ),
        'Student'
    )
));