In a model, is it possible to do multiple iterations of belongsTo?
Assuming 3 tables, alerts, schedules, tasks and the model is for alerts. I want to get at a field from tasks but I have to join through schedules.
alerts.schedule_id -> schedules.tasks_id -> tasks.name
I tried this syntax:
var $belongsTo = array(
'Schedule' => array(
'className' => 'Schedule',
'foreignKey' => 'schedule_id'
),
'Task' => array(
'className' => 'Task',
'foreignKey' => 'task_id'
));
But that just joins both Schedules and Tasks directly to Alerts (here's the sql that was generated:
LEFT JOIN `schedules` AS `Schedule` ON (`Alert`.`schedule_id` = `Schedule`.`id`) LEFT JOIN `tasks` AS `Task` ON (`Alert`.`task_id` = `Task`.`id`)
)
I ended up setting this property:
$this->Alert->recursive = 2;
In the index() function of the alerts controller.
Then I didn't have to do a separate find and was able to reference the name field in the Tasks table in index.ctp like this:
<td><?php echo $alert['Schedule']['Task']['name']; ?> </td>
Try this.
in alert.php
CLass Alert extends AppModel{
var $name = 'Alert';
var $belongsTo = array(
'Schedule' => array(
'className' => 'Schedule',
'foreignKey' => 'schedule_id'
)
);
}
in schedule.php
CLass Schedule extends AppModel{
var $name = 'Schedule';
var $belongsTo = array(
'Task' => array(
'className' => 'Task',
'foreignKey' => 'task_id'
)
);
}
then find with recursive=>2
Related
hello I have three tables in my database. Country, State,and City. In state table there is a country_id as foreign key and in city table there is state_id as foreign key. The problem is I want to get the country name when I am querying in the city table. I'll share the code so you can fully understand
Country.php
class Country extends AppModel{
public $useTable = 'countries';
}
State.php
class City extends AppModel{
public $useTable = 'cities';
public $belongsTo = array(
'State' => array(
'className' => 'State',
'foreignKey' => 'state_id',
'fields' => array('state.id','state.name')
)
);
}
City
class State extends AppModel{
public $useTable = 'states';
public $belongsTo = array(
'Country' => array(
'className' => 'Country',
'foreignKey' => 'country_id',
'fields' => array('Country.id','Country.name','Country.short_name')
)
);
okay here is the code. If I use this query
$this->State->find('all', array(
'conditions' => array(
'state.country_id' => $country_id
),
I can get the country name from country table. same is the case If I do this in city table like this
$this->City->find('all', array(
'conditions' => array(
'city.state_id' => $state_id
),
I can get all the state names city names here. So Now in this same table in one query how I can get the country name as well ?
Try using the recursive property.
Setting $this->City->recursive = 2 gets associated data for the table and associated data on the associated tables.
$this->City->recursive = 2;
$this->City->find('all', array(
'conditions' => array(
'city.state_id' => $state_id
),
//other stuff you use in this find
));
You can also using the "joins" flag.
$this->City->find('all', array(
'conditions' => array(
'City.state_id' => $state_id
),
'joins' => array(
array(
'table' => 'states',
'alias' => 'State',
'type' => 'left',
'conditions' => 'State.id = City.state_id'
),
array(
'table' => 'countries',
'alias' => 'Country',
'type' => 'left',
'conditions' => 'Country.id = State.country_id'
)
),
'fields' => array('City.id', 'State.name', 'Country.name',
//include all the fields you need
)
));
See: http://book.cakephp.org/2.0/en/models/model-attributes.html#recursive
In addition to the first answer, make sure to contain the foreign key for the Country.
class City extends AppModel{
public $belongsTo = array(
'State' => array(
'className' => 'State',
'foreignKey' => 'state_id',
'fields' => array('State.id','State.name', 'State.country_id'), // Make sure to contain the foreign key for the `Country`.
)
);
}
For your information, you can also use ContainableBehavior instead of recursive.
http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
I have multiple tables associated with each other:
Messages
Message details
Message details has the fields id, Message_id, created_date and message.
I want to sort messages on the message details created_date.
How can I do that?
$messages = $this->Message->find('all', array(
'conditions' => array('Message.status'=> 'progress')
));
// What do I do now to sort it on message_details created time?
class MessageDetail extends AppModel {
//public $hasMany=array('MessageDetail');
//$belongsTo = array('Message');
public $belongsTo = array(
'Message' => array(
'className' => 'Message',
'foreignKey' => 'message_id'
)
);
}
class Message extends AppModel {
public $hasMany=array('MessageDetail');
}
Can You pls try this code,You need Descending order put DESC instead of ASC
$messages = $this->Message->find('all', array(
'conditions' => array('Message.status'=> 'progress'),
'order' => array('MessageDetails.created_date ASC')
));
You can simple pass order, and mention which field to sort, see below:
$messages = $this->Message->find('all', array(
'conditions' => array('Message.status'=> 'progress'),
'ORDER' => 'MessageDetail.created_date ASC'
));
UPDATE
You Message.php Model will look like:
class Message extends AppModel {
public $hasMany = array(
'MessageDetail' => array(
'className' => 'MessageDetail',
'foreignKey' => 'message_id',
'order' => 'MessageDetail.created_date DESC'
),
);
}
and MessageDetail.php Model will be:
class MessageDetail extends AppModel {
public $belongsTo = array(
'Message' => array(
'className' => 'Message',
'foreignKey' => 'message_id'
)
);
}
I have two tables:
users contains (id, name, email) id is the primary key.
users_details contains (user_id, address, city, postcode) user_id is the foreign key to user table.
The users.id=users_details.user_id.
I wrote user model like this in User.php
class User extends AppModel {
public $name = 'User';
public $displayField = 'name';
public $primaryKey = 'id';
var $belongsTo = 'UsersDetail';
public $hasone = array(
'UsersDetail' => array(
'className' => 'UsersDetail',
'conditions' => '',
'fields' => '',
'foreignKey' => 'id',
'order' => '',
'dependent' => true
)
);
}
I wrote the usersdetail model in UsersDetail.php
class UsersDetail extends AppModel {
public $name = 'UsersDetail';
public $displayField = 'name';
public $belongsTo = array( 'User' =>
array( 'className' => 'User','foreignKey' => 'user_id') );
public $hasone = array(
'User' => array(
'className' => 'User',
'conditions' => '',
'fields' => '',
'foreignKey' => 'id',
'order' => '',
'dependent' => true
));
}
I want to get the data from table using the join with condition. The users.id=users_details.user_id.
You have declared two relationships for each model association, when you should only have one going each way.
Like so:
In the userDetail Model:
public $hasMany = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
And consequently, in the User Model:
public $belongsTo = array(
'UserDetail' => array(
'className' => 'UserDetail',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
Check out the documentation for more details.
user has (id, name, email) id is the primary key.
users_details has(user_id, address, city, postcode) user_id is the foreign key to user table. Means.
Point to remember:
one to one relation - hasOne - A user table has one users_detail.
belongto - A userdetails table belongs to User table.
So, the relation between the two tables is hasone and belongsto.
find the right code below.
User model:
public $hasOne = array('UsersDetail' => array(
'className' => 'UsersDetail',
'foreignKey' => 'user_id')
);
UsersDetail model
public $belongsTo = array('User' => array(
'className' => 'Users',
'foreignKey' => 'id',
'conditions' => '',
'fields' => '',
'order' => '')
);
which provide the join precisely. You can add the conditions, order in collections.
The output query
SELECT `User`.`id`, `User`.`first_name`, `User`.`last_name`, `User`.`email`, `User`.`mobile`, `User`.`pswd`, `UsersDetail`.`user_id`, `UsersDetail`.`address`, `UsersDetail`.`city`, `UsersDetail`.`state`, `UsersDetail`.`postcode`, `UsersDetail`.`dob`, `UsersDetail`.`photo` FROM `cakedemo`.`users` AS `User` LEFT JOIN `cakedemo`.`users_details` AS `UsersDetail` ON (`UsersDetail`.`user_id` = `User`.`id`) WHERE 1 = 1
Thank you,
I am trying to display a field from a 3rd table in a relationship, and after checking posts here and the docs, I am still stuck.I have 3 models all related in some way. I have found similar posts here but I am still not getting it to work. I am learning so sorry if I have missed this somewhere in the docs but I have read a fair bit and have tried a lot. I am guessing too much now on this so I need help.
1)Tutorsession - belongsto teachers,
2) Teacher -has 1 user,hasmany tutorsessions
3) User- has 1 teacher, //////I want to display a field from this table given I display tutorsessions
In controller
$this->set('tutor',
$this->Tutorsession->find('first',
array(
'conditions' => array('Teacher.user_id' => $id),
'contain' => 'User.username'
)
)
); //////////no error but no results
from view echo '<td>'. $item['User']['username'].'</td>'; ///////error user undefined
The tutorsession automatically gets rows from teacher table but not user table witht he model setup on a findall.
I want to display a username from the user table. I display the tutorsession table , I then can display the teacher table with the model association but I cant go from the teacher table to the user table to get a user name from the user id as the common field. I have checked the docs below and I am not sure why my code isnt ble to display a username from users table.
http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
http://book.cakephp.org/2.0/en/models/retrieving-your-data.html
update: here are the models
class User extends AppModel {
public $hasOne = array(
'Teacher' => array(
'className' => 'Teacher',
'dependent' => true
)
class Tutorsession extends AppModel
{
public $name='Tutorsession';
public $belongsTo = array(
'Teacher' => array(
'className' => 'Teacher',
'foreignKey' => 'teacher_id'
)
class Teacher extends AppModel
{
public $name='Teacher';
public $hasMany = array('Tutorsession');
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
Add containable behavior in your Model
public $actsAs = array('Containable');
Execute following query In controller
$contain = array('Teacher' => array('User'));
$this->set('tutor', $this->Tutorsession->find('first',array(
'conditions' => array('Teacher.user_id' => $id),
'contain' => $contain
)));
Try this:
$this->Tutorsession->recursive = 2;
$this->Tutorsession->Teacher->contain('User');
$this->set('tutor',
$this->Tutorsession->find('first',
array(
'conditions' => array('Teacher.user_id' => $id)
)
)
);
$tutor=$this->Teacher->find('first',
array(
'conditions' => array('Teacher.user_id' => $id)
)
);
debug($tutor); exit();
Your result similar:
'Teacher' => array(
'id' => '1',
'name' => 'abc',
'created' => '1397040385',
'updated' => '1397725860'
),
'User' => array(
'id' => '4',
'name' => 'administrators',
'created' => '1397032953',
'modified' => '1397032953'
),
'Tutorsession' => array(
0=>array(
'id' => '3',
'name'=>'abc',
'created' => '1400729137'
),
1=>array(
'id' => '4',
'name'=>'abc',
'created' => '1400729137'
)
)
Ensure your models are correct
I've run through the Cakephp documentation on linking models together (creating associations), and I can get a single select dropdown in the scaffolded add and edit views by defining a $hasOne member one model and a corresponding $belongsTo in the other. Now, for a $hasMany relationship, I'm trying to get some kind of form input (either a multi-select dropdown, or checkboxes ... preferably checkboxes) in my scaffolded add and edit views that lets the user choose the associated advertisements for a given rental. But with the below code I get no mention of Advertisements in the Rental add and edit views :'( Am I missing something? Is this even possible? I've seen this done in RoR and Grails but can't get it working with CakePHP. Thanks for any help!
Rental model (app/Model/Rental.php)
<?php
class Rental extends AppModel {
var $name = 'Rental';
var $belongsTo = array(
'Agent' => array(
'className' => 'User',
'foreignKey' => 'agent_id'
),
'Bedroom',
'Landlord' => array(
'className' => 'Landlord',
'foreignKey' => 'landlord_id'
)
);
var $hasMany = array(
'Advertisement' => array(
'className' => 'Advertisement',
'foreignKey' => 'rental_id',
//'conditions' => array('Comment.status' => '1'),
'order' => 'Advertisement.created DESC',
'limit' => '5',
'dependent'=> false
)
);
public $validate = array(
'title' => array(
'rule' => 'notEmpty'
),
'description' => array(
'rule' => 'notEmpty'
)
);
public function isOwnedBy($rental, $user) {
return $this->field('id', array('id' => $rental, 'user_id' => $user)) === $rental;
}
}
Rentals Controller (app/Controller/RentalsController.php)
<?php
class RentalsController extends AppController {
public $scaffold;
}
Advertisement model (app/Model/Advertisement.php)
<?php
class Advertisement extends AppModel {
var $name = 'Advertisement';
var $belongsTo = array(
'Rental' => array(
'className' => 'Rental',
'foreignKey' => 'rental_id'
),
'Author' => array(
'className' => 'User',
'foreignKey' => 'author_id'
)
);
}
Advertisements Controller (app/Controller/AdvertiesementsController.php)
<?php
class AdvertisementsController extends AppController {
public $scaffold;
}
Cake's scaffold views don't show anything from the hasMany side of the relationship. They assume you want to pick it from the model that has the belongsTo.
Frankly, doing it as a multi-select is a little odd for this relationship, IMHO. Multi-selects are normally used for hasAndBelongsToMany relationships. If you want to do it, you'll need to do the work yourself, and not use Cake's scaffolding.