3
votes

I apologize in advance if this question has been answered elsewhere; I searched high and low for an existing answer but came up empty. Perhaps I am looking with the wrong keywords.

I have three models, two (Student and Tutor)of which have a $hasMany relationship with a common model(Appointment) which has a $belongsTo relationship with both of the other models. Exact models are below...

A Student hasMany Appointments...

class Student extends AppModel {
    var $hasMany = array (
        'Appointment' => array (
            'foreignKey' => 'student_id'
        )
    );

A Tutor hasMany Appointments...

class Tutor extends AppModel {
    var $hasMany = array (
        'Appointment' => array (
            "foreignKey" => 'tutor_id'
        )
    );

An Appointment belongsTo a Student and a Tutor...

class Appointment extends AppModel {
    var $belongsTo = array (
        'Student' => array (
            'foreignKey' => 'student_id'
        ),
        'Tutor' => array (
            'foreignKey' => 'tutor_id'
        )   
    );

When looking at a student's record (e.g. 'app/student/view/4') I need to be able to list the dates of their upcoming appointments and the name of the tutor for that appointment. So I need to access data from the Tutor model (name) while looking at the Student model. Right now I have only been able to accomplish this using $this->Student->query() to pull the related tutor records, but this results in the student's information repeating in the resulting array.

All of the $hasMany and $belongsTo relationships work just fine. Does CakePHP have a built-in function that I am missing to get the related information, or does this need to be done longhand somewhere?

1
Try setting recursive => 2 on your find. This should give you one extra level of associated models.bfavaretto
Thanks. This is working, but is this a scalable solution? The student record is iterated for each appointment in the returned array. With 15 fields in that table and 10+ appointments per student, that's 150 extra fields in each query.jonny_bk
I know, been there... The alternatives are (1) Containable, (2) forcing joins, or (3) writing the query manually.bfavaretto

1 Answers

3
votes

You should consider using Containable. In case you're not familiar with it, it's a Behavior which you can attach to models and use it to define precisely which associated models are to be included in a find, as many models and as deep as you like.

I always use it for all models, by setting it in AppModel:

var $actsAs = array('Containable');

Then in the controller:

$this->Student->find('first', array(
    'conditions' => ...,
    'contain' => array('Appointment' => 'Tutor'),
    ...
));