I'm attending CakeFest 2010!

3.7.6.4 hasMany

Next step: defining a “User hasMany Comment” association. A hasMany association will allow us to fetch a user’s comments when we fetch a User record.

When keying your database tables for a hasMany relationship, follow this convention:

hasMany: the other model contains the foreign key.
Relation Schema
User hasMany Comment Comment.user_id
Cake hasMany Virtue Virtue.cake_id
Product hasMany Option Option.product_id

We can define the hasMany association in our User model at /app/models/user.php using the string syntax as follows:

<?php

class User extends AppModel {
    var $name = 'User';                
    var $hasMany = 'Comment';   
}
?>
  1. <?php
  2. class User extends AppModel {
  3. var $name = 'User';
  4. var $hasMany = 'Comment';
  5. }
  6. ?>

We can also define a more specific relationship using array syntax:

<?php

class User extends AppModel {
    var $name = 'User';                
    var $hasMany = array(
        'Comment' => array(
            'className'     => 'Comment',
            'foreignKey'    => 'user_id',
            'conditions'    => array('Comment.status' => '1'),
            'order'    => 'Comment.created DESC',
            'limit'        => '5',
            'dependent'=> true
        )
    );  
}
?>
  1. <?php
  2. class User extends AppModel {
  3. var $name = 'User';
  4. var $hasMany = array(
  5. 'Comment' => array(
  6. 'className' => 'Comment',
  7. 'foreignKey' => 'user_id',
  8. 'conditions' => array('Comment.status' => '1'),
  9. 'order' => 'Comment.created DESC',
  10. 'limit' => '5',
  11. 'dependent'=> true
  12. )
  13. );
  14. }
  15. ?>

Possible keys for hasMany association arrays include:

  • className: the classname of the model being associated to the current model. If you’re defining a ‘User hasMany Comment’ relationship, the className key should equal ‘Comment.’
  • foreignKey: the name of the foreign key found in the other model. This is especially handy if you need to define multiple hasMany relationships. The default value for this key is the underscored, singular name of the actual model, suffixed with ‘_id’.
  • conditions: An SQL fragment used to filter related model records. It’s good practice to use model names in SQL fragments: “Comment.status = 1” is always better than just “status = 1.”
  • fields: A list of fields to be retrieved when the associated model data is fetched. Returns all fields by default.
  • order: An SQL fragment that defines the sorting order for the returned associated rows.
  • limit: The maximum number of associated rows you want returned.
  • offset: The number of associated rows to skip over (given the current conditions and order) before fetching and associating.
  • dependent: When dependent is set to true, recursive model deletion is possible. In this example, Comment records will be deleted when their associated User record has been deleted.
  • exclusive: When exclusive is set to true, recursive model deletion does the delete with a deleteAll() call, instead of deleting each entity separately. This greatly improves performance, but may not be ideal for all circumstances.
  • finderQuery: A complete SQL query CakePHP can use to fetch associated model records. This should be used in situations that require very custom results.

    If a query you're building requires a reference to the associated model ID, use the special {$__cakeID__$} marker in the query. For example, if your Apple model hasMany Orange, the query should look something like this:

    SELECT Orange.* from oranges as Orange WHERE Orange.apple_id = {$__cakeID__$};
    
    1. SELECT Orange.* from oranges as Orange WHERE Orange.apple_id = {$__cakeID__$};

Once this association has been defined, find operations on the User model will also fetch related Comment records if they exist:

//Sample results from a $this->User->find() call.

Array
(  
    [User] => Array
        (
            [id] => 121
            [name] => Gwoo the Kungwoo
            [created] => 2007-05-01 10:31:01
        )
    [Comment] => Array
        (
            [0] => Array
                (
                    [id] => 123
                    [user_id] => 121
                    [title] => On Gwoo the Kungwoo
                    [body] => The Kungwooness is not so Gwooish
                    [created] => 2006-05-01 10:31:01
                )
            [1] => Array
                (
                    [id] => 124
                    [user_id] => 121
                    [title] => More on Gwoo
                    [body] => But what of the ‘Nut?
                    [created] => 2006-05-01 10:41:01
                )
        )
)

One thing to remember is that you’ll need a complimentary Comment belongsTo User association in order to get the data from both directions. What we’ve outlined in this section empowers you to get Comment data from the User. Adding the Comment belongsTo User association in the Comment model empowers you to get User data from the Comment model - completing the connection and allowing the flow of information from either model’s perspective.