官术网_书友最值得收藏!

Modifying binding parameters for a find

This recipe shows how to use Containable to change some of the parameters that affect model bindings.

Getting ready

To go through this recipe, we need some sample tables to work with.

  1. Create a table named users, using the following SQL statement:
    CREATE TABLE `users`(
    `id` INT UNSIGNED AUTO_INCREMENT NOT NULL,
    `name` VARCHAR(255) NOT NULL,
    `email` VARCHAR(255) NOT NULL,
    PRIMARY KEY(`id`)
    );
    
  2. Create a table named profiles, using the following SQL statement:
    CREATE TABLE `profiles`(
    `id` INT UNSIGNED AUTO_INCREMENT NOT NULL,
    `user_id` INT UNSIGNED NOT NULL,
    `website` VARCHAR(255) default NULL,
    `birthdate` DATE default NULL,
    PRIMARY KEY(`id`),
    KEY `user_id`(`user_id`),
    CONSTRAINT `profiles__users` FOREIGN KEY(`user_id`) REFERENCES `users`(`id`)
    );
    
  3. Create a table named articles, using the following SQL statement:
    CREATE TABLE `articles`(
    `id` INT UNSIGNED AUTO_INCREMENT NOT NULL,
    `user_id` INT UNSIGNED NOT NULL,
    `title` VARCHAR(255) NOT NULL,
    `body` TEXT NOT NULL,
    `published` TINYINT NOT NULL default 1,
    `created` DATETIME NOT NULL,
    `modified` DATETIME NOT NULL,
    PRIMARY KEY(`id`),
    KEY `user_id`(`user_id`),
    CONSTRAINT `articles__users` FOREIGN KEY(`user_id`) REFERENCES `users`(`id`)
    );
    
  4. Add some sample data, using the following SQL statements:
    INSERT INTO `users`(`id`, `name`, `email`) VALUES
    (1, 'John Doe', 'john.doe@example.com'),
    (2, 'Jane Doe', 'jane.doe@example.com');
    INSERT INTO `profiles`(`user_id`, `website`, `birthdate`) VALUES
    (1, 'http://john.example.com', '1978-07-13'),
    (2, NULL, '1981-09-18');
    INSERT INTO `articles`(`user_id`, `title`, `body`, `published`, `created`, `modified`) VALUES
    (1, 'John\'s Post 1', 'Body for John\'s Post 1', 1, NOW(), NOW()),
    (1, 'John\'s Post 2', 'Body for John\'s Post 2', 1, NOW(), NOW()),
    (1, 'John\'s Post 3', 'Body for John\'s Post 3', 0, NOW(), NOW()),
    (1, 'John\'s Post 4', 'Body for John\'s Post 4', 1, NOW(), NOW()),
    (2, 'Jane\'s Post 1', 'Body for Jane\'s Post 1', 1, NOW(), NOW());
    
  5. Add the Containable behavior to all your models by following the recipe Adding Containable to all models.
  6. Now we need to create the main model. Create a file named user.php and place it in your app/models folder with the following contents:
    <?php
    class User extends AppModel {
    public $hasOne = array('Profile');
    public $hasMany = array('Article');
    }
    ?>
    

How to do it...

If we want to obtain the first User record together with the Article records that the User owns, but ordered by latest articles first, we use the order binding setting (we also use the fields setting to limit the fields returned for each Article):

$user = $this->User->find('first', array(
'contain' => array(
'Article' => array(
'fields' => array('Article.title'),
'order' => array( 'Article.created' => 'desc', 'Article.id' => 'desc' )
)
)
));

Using our sample data, the above query will result in the following array structure:

array(
'User' => array(
'id' => '1',
'name' => 'John Doe',
'email' => 'john.doe@example.com',
),
'Article' => array(
array(
'title' => 'John\'s Post 4',
'user_id' => '1'
),
array(
'title' => 'John\'s Post 3',
'user_id' => '1'
),
array(
'title' => 'John\'s Post 2',
'user_id' => '1'
),
array(
'title' => 'John\'s Post 1',
'user_id' => '1'
)
)
)

If we want to get the same data, but make sure we only obtain the latest Article a User has written, we use the limit binding setting:

$user = $this->User->find('first', array(
'contain' => array(
'Article' => array(
'fields' => array('Article.title'),
'order' => array(
'Article.created' => 'desc',
'Article.id' => 'desc'
),
'limit' => 1
)
)
));

Using our sample data, the above query will result in the following array structure:

array(
'User' => array(
'id' => '1',
'name' => 'John Doe',
'email' => 'john.doe@example.com',
),
'Article' => array(
array(
'title' => 'John\'s Post 4',
'user_id' => '1'
)
)
)

Another option that is useful on some scenarios is offset, applicable to the hasMany and hasAndBelongsToMany bindings. Using the example above, we now want to obtain the two most recent articles a User created, after the latest Article.

$user = $this->User->find('first', array(
'contain' => array(
'Article' => array(
'fields' => array('Article.title'),
'order' => array(
'Article.created' => 'desc',
'Article.id' => 'desc'
),
'limit' => 2, 'offset' => 1
)
)
));

The returned data structure now looks like this:

array(
'User' => array(
'id' => '1',
'name' => 'John Doe',
'email' => 'john.doe@example.com',
),
'Article' => array(
array(
'title' => 'John\'s Post 3',
'user_id' => '1'
),
array(
'title' => 'John\'s Post 2',
'user_id' => '1'
)
)
)

How it works...

The Containable behavior uses the built-in bindModel() method defined in CakePHP's Model class to alter the binding settings defined in the contain find setting.

It goes through the defined bindings and checks to see whether there are defined binding settings. If there are, it passes them to the bindModel() method for each of the specified bindings.

Some binding settings make sense only on some relationship types. For example, the limit setting used previously would not be useful on belongsTo or hasOne relationships.

The following list includes which settings can be specified for each relationship type:

  • belongsTo: className, conditions, foreignKey, order.
  • hasOne: className, conditions, foreignKey, order.
  • hasMany: className, conditions, finderQuery, foreignKey, limit, offset, order.
  • hasAndBelongsToMany: associationForeignKey, className, conditions, deleteQuery, finderQuery, foreignKey, insertQuery, joinTable, limit, offset, order, unique, with.

See also

  • Modifying binding conditions for a find
主站蜘蛛池模板: 湖州市| 铅山县| 上饶市| 二连浩特市| 嘉荫县| 祁门县| 聂荣县| 泰州市| 壶关县| 囊谦县| 扶沟县| 固镇县| 泰州市| 云安县| 扎囊县| 庆元县| 沽源县| 辽阳市| 江津市| 绥芬河市| 郯城县| 江达县| 无棣县| 贺兰县| 丹阳市| 沙坪坝区| 富阳市| 桂阳县| 老河口市| 新晃| 泗洪县| 泽州县| 虞城县| 芦山县| 景德镇市| 内江市| 岢岚县| 锡林郭勒盟| 莱西市| 乐安县| 石柱|