Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CakePHP 3-level-deep model associations

I am relatively new to CakePHP, I am doing fine with the documentation, but I've been trying to find a way out to this problem for weeks and I don't seem to find the solution, I am sure it is easy and maybe even automagically doable, but I just don't know how to find it (maybe I don't know the jargon for these kind of things)

My model structure is like this:

<?php
    class Trip extends AppModel {
          var $belongsTo = array(
            'User' => array(
                'className' => 'User',
                'foreignKey' => 'user_id'
            ),
            'Start' => array(
                'className' => 'Place',
                'foreignKey' => 'start_id'
            ),
            'End' => array(
                'className' => 'Place',
                'foreignKey' => 'end_id'
            ),
            'Transport' => array(
                'className' => 'Transport',
                'foreignKey' => 'transport_id'
            )
        );

     }
?>

<?php
class Place extends AppModel {

    var $belongsTo = array(
        'User' => array(
            'className' => 'User',
            'foreignKey' => 'user_id'
        ),
        'Country' => array(
            'className' => 'Country',
            'foreignKey' => 'country_id'
        ),
        'State' => array(
            'className' => 'State',
            'foreignKey' => 'state_id'
        ),
        'City' => array(
            'className' => 'City',
            'foreignKey' => 'city_id'
        )
    );
    var $hasMany = array(
        'PlaceStart' => array(
            'className' => 'trip',
            'foreignKey' => 'start_id',
            'dependent' => false
        ),
        'PlaceEnd' => array(
            'className' => 'trip',
            'foreignKey' => 'end_id',
            'dependent' => false
        )
    );

}
?>

<?php
class State extends AppModel {

    var $belongsTo = array(
        'Country' => array(
            'className' => 'Country',
            'foreignKey' => 'country_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        )
    );

    var $hasMany = array(
        'City' => array(
            'className' => 'City',
            'foreignKey' => 'city_id',
            'dependent' => false
        )
    );

}
?>

... and so forth with User, City, Country, and Transport Models.

What I am trying to achieve is to get all the information of the whole tree when I search for a Trip.

<?php
class TripController extends AppController {
    function index() {
        debug($this->Trip->find('first'));
    }
}

Outputs

Array
(
    [Trip] => Array
        (
            [id] => 6
            [created] => 2010-05-04 00:23:59
            [user_id] => 4
            [start_id] => 2
            [end_id] => 1
            [title] => My trip
            [transport_id] => 1
        )

    [User] => Array
        (
            [id] => 4
            [name] => John Doe
            [email] => [email protected]
        )

    [Start] => Array
        (
            [id] => 2
            [user_id] => 4
            [country_id] => 1
            [state_id] => 1
            [city_id] => 1
            [direccion] => Lincoln Street
        )

    [End] => Array
        (
            [id] => 1
            [user_id] => 4
            [country_id] => 1
            [state_id] => 1
            [city_id] => 4
            [address] => Fifth Avenue
        )

    [Transport] => Array
        (
            [id] => 1
            [name] => car
        )
)

Here is the question: How do I get in one query all the information down the tree?

I would like to have something like

Array
(
    [Trip] => Array
        (
            [id] => 6
            [created] => 2010-05-04 00:23:59
            [User] => Array
                (
                    [id] => 4
                    [name] => John Doe
                    [email] => [email protected]
                )
            [Start] => Array
                (
                    [id] => 2
                    [user_id] => 4
                    [Country] => Array
                        (
                            [id] => 1
                            [name] = Spain
                        )
                    [State] => Array
                        (
                            [id] => 1
                            [name] = Barcelona
                        )
                    [City] => Array
                        (
                            [id] => 1
                            [name] = La Floresta
                        )
                    [address] => Lincoln Street
                )
            [End] => (same as Start)
            [title] => My trip
            [Transport] => Array
                (
                    [id] => 1
                    [name] => car
                )
        )
)

Can CakePHP create this kind of data? Not only for $this->Model->find() but also for $this->paginate() as for example:

    // filter by start
    if(isset($this->passedArgs['start'])) {
        //debug('isset '.$this->passedArgs['start']);
        $start = $this->passedArgs['start'];
        $this->paginate['conditions'][] = array(
            'OR' => array(
                'Start.address LIKE' => "%$start%",
                'Start.State.name LIKE' => "%$start%",
                'Start.City.name LIKE' => "%$start%",
                'Start.Country.name LIKE' => "%$start%"
            )
        );
        $this->data['Search']['start'] = $start;
    }

It seems like a rough question but I am sure this is extensively done and documented, I'd really appreciate any help.

like image 485
Naoise Golden Avatar asked Nov 25 '25 21:11

Naoise Golden


2 Answers

You seem to have everything setup OK. All you should have to do is set the recursive to 2 and that should give you an extra level to your data (assuming that you have set up all the relations correctly)

var $recursive =2;
like image 190
paullb Avatar answered Nov 28 '25 11:11

paullb


An alternative, more surgical, solution that's particularly useful if you need to go deeper than 2 levels or if you have a lot of 2nd level associations that you don't need for this particular problem is the Containable Behavior. This is the 1.2.x documentation. If you're using v1.3.x, you'll find it here.

like image 29
Rob Wilkerson Avatar answered Nov 28 '25 09:11

Rob Wilkerson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!