This recipe shows how to set up more than one association from one model to the same model, a need that normally arises on most applications.
To go through this recipe we need some sample tables to work with.
addresses
, using the following SQL statement:CREATE TABLE `addresses`( `id` INT UNSIGNED AUTO_INCREMENT NOT NULL, `address` TEXT NOT NULL, `city` VARCHAR(255) default NULL, `state` VARCHAR(255) NOT NULL, `zip` VARCHAR(10) NOT NULL, `country` CHAR(3) NOT NULL, PRIMARY KEY(`id`) );
users
, using the following SQL statement:CREATE TABLE `users`( `id` INT UNSIGNED AUTO_INCREMENT NOT NULL, `billing_address_id` INT UNSIGNED default NULL, `home_address_id` INT UNSIGNED default NULL, `name` VARCHAR(255) NOT NULL, `email` VARCHAR(255) NOT NULL, PRIMARY KEY(`id`), KEY `billing_address_id`(`billing_address_id`), KEY `home_address_id`(`home_address_id`), CONSTRAINT `addresses__billing_address_id` FOREIGN KEY(`billing_address_id`) REFERENCES `addresses`(`id`), CONSTRAINT `addresses__home_address_id` FOREIGN KEY(`home_address_id`) REFERENCES `addresses`(`id`) );
INSERT INTO `addresses`(`id`, `address`, `city`, `state`, `zip`, `country`) VALUES (1, '123 Street', 'Palo Alto', 'CA', '94310', 'USA'), (2, '123 Street', 'London', 'London', 'SE10AA', 'GBR'), INSERT INTO `users`(`billing_address_id`, `home_address_id`, `name`, `email`) VALUES (1, 2, 'John Doe', '[email protected]'),
user.php
and place it in your app/models
folder with the following contents:<?php class User extends AppModel { } ?>
Edit the User
model, and add the binding definitions to include both references to the Address
model:
<?php class User extends AppModel { public $belongsTo = array( 'BillingAddress' => array( 'className' => 'Address' ), 'HomeAddress' => array( 'className' => 'Address' ) ); } ?>
If we issue a find operation to fetch the User
, we would obtain the following data structure:
array( 'User' => array( 'id' => '1', 'billing_address_id' => '1', 'home_address_id' => '2', 'name' => 'John Doe', 'email' => '[email protected]', ), 'BillingAddress' => array( 'id' => '1', 'address' => '123 Street', 'city' => 'Palo Alto', 'state' => 'CA', 'zip' => '94310', 'country' => 'USA' ), 'HomeAddress' => array( 'id' => '2', 'address' => '123 Street', 'city' => 'London', 'state' => 'London', 'zip' => 'SE10AA', 'country' => 'GBR' ) )
In this example, the naming convention we used for the bindings is the standard CakePHP uses for field names, where each uppercase letter is prefixed by an underscore sign, everything is converted to lowercase, and the suffix _id
is added. Thus, the standard field name the binding named BillingAddress
is billing_address_id
.
However there are times where we need to use a field name that does not comply with this standard. In that case, we can use the foreignKey
binding setting to specify the field name. For example, we could change the User
model definition so the name of the HomeAddress
becomes Address
, which would make the User
model look like this:
<?php class User extends AppModel { public $belongsTo = array( 'BillingAddress' => array( 'className' => 'Address' ), 'Address' => array( 'className' => 'Address', 'foreignKey' => 'home_address_id' ) ); } ?>
When we use different aliases to refer to the same model, certain model callback implementations, such as beforeSave
, will need to be changed to avoid using the name of the model directly, and instead use the property alias
, available in all models. More information about this can be obtained from Nick Baker's article available at http://www.webtechnick.com/blogs/view/230/The_Power_of_CakePHP_aliases.
18.191.186.219