I have 3 tables in the following format.
users
id
FirstName
LastName
userjobs
id
jobinfo
starredjobs
id
user_id
userjob_id
comments
enddate
The 'starredjobs' table holds all the jobs which an user starred/added to favorites.
I have defined the following relationships in their respective model files.
user.php
protected $_has_many = array( 'starredjobs' => array('model' => 'starredjobs' , 'foreign_key'=>'user_id'),
starredjob.php
protected $_belongs_to = array('user' => array('model' => 'user','foreign_key' => 'user_id'));
protected $_has_many = array('jobs' => array('model'=> 'userjob', 'foreign_key'=> 'job_id'));
userjobs.php
none
The idea is to retrieve all the starred jobs and details regarding jobs from the user object. A user can 'n' number of jobs and A job can be starred by 'n' number of users.
Am i defining relationships correctly?
Short answer: No. What you have here is a typical n:m relationship which can easily be used in Kohana using has_many "through" (as is used in the default roles users-relationship). But this doesn't allow for extra attributes in the "middle" table, so you need to use 2 has_many with corresponding belongs_to.
This can be described in plain English like so:
One user has many starredjobs.
One job has many starredjobs.
One starredjob belongs to one user and one job
Also consider the difference between far_key and foreign_key (official doc sadly doesn't cover it), but one easy rule to remember: The key in the other table is far away -> it is the far_key.
This would give you the following
user.php
$_has_many = array(
'starredjobs' => array(
'model' => 'Starredjob',
'far_key' => 'user_id'
)
);
userjob.php
$_has_many = array(
'starredbyuser' => array(
'model' => 'Starredjob',
'far_key' => 'userjob_id'
)
);
starredjob.php
$_belongs_to = array(
'user' => array(
'model' => 'User',
'foreign_key' => 'user_id'
),
'job' => array(
'model' => 'Userjob',
'foreign_key' => 'userjob_id'
)
);
Now you can do various things such as:
//get all jobs starred by given $user
foreach ($user->starredjobs->find_all() as $starredjob) {
//info on userjob via $starredjob->job->jobinfo, etc.
//info from pivot table via $starredjob->comments, etc.
}
//get all users that starred a given $userjob
foreach ($userjob->starredbyuser->find_all() as $starredjob) {
//info on user via $starredjob->user->FirstName, etc.
//info from pivot table via $starredjob->comments, etc.
}
Related
I have a function where a user can request a project. The request has 2 fields for other employees to be added.
It's got a field for a person who is responsible for the project (person_responsible) and the employee who is supposed to attend the opening meeting (person_attending).
What I want to know is, since both these fields (person_responsible and person_attending) will be pulling it's data from hr_employees table, how would I set this up in my Project-Model.
At the moment I have the one field set up like this:
public $belongsTo = array(
'HrEmployee' => array(
'className' => 'HrEmployee',
'foreignKey' => 'responsible_person',
'fields' => 'HrEmployee.employeename',
)
);
How would I set up the other field?
What I do in this cases is to make two associations. Since cake allow to customize relations, you can have two relations to the same model with different names.
public $belongsTo = array(
'ResponsibleEmployee' => array(
'className' => 'HrEmployee',
'foreignKey' => 'responsible_person',
'fields' => 'HrEmployee.employeename',
),
'AttendingEmployee' => array(
'className' => 'HrEmployee',
'foreignKey' => 'person_attending',
'fields' => 'HrEmployee.employeename',
)
);
Change the names to adjust your needs. Now, if your model is set as containable and you retrieve the Project model with those models in it, you'll get something like
array('Project' => array(/*data project*/),
'ResponsibleEmployee' => array(/*name*/),
'AttendingEmployee' => array(/*name*/)
)
(or another variation of that array depending on how the query was made).
I have HABTM for Users and Groups. I want to show in a Group view - all the Groups that belong to a User. Or to put it differently - all the Groups that have the User.
I am getting tangled in the MVC and am not able to figure it out. Here are my two models:
class Course extends AppModel
public $name = 'Course';
public $hasAndBelongsToMany = array('User' =>
array(
'unique' => false
)
);
And...
public $name = 'User';
public $hasAndBelongsToMany = array('Course' =>
array(
'unique' => true
)
);
The table name in the database is courses_users - this table houses group ids and user ids.
Should be simple enough but I'm new to CakePHP so I'd love some help. Thank you!
CakePHP has recursive set to 1 by default, which means that assuming you have not changed the recursive setting, it will automatically fetch all associated courses when you call find on a user, assuming you set up the HABTM relationship when doing the find. Therefore, all you have to do is:
$this->User->find('first', array('conditions' => array('User.id' => $this->Auth->user('id'))));
In your User model, I don't think it's strictly necessary, but I like to specify the join table and such on HABTM relationships:
public $hasAndBelongsToMany = array('Course' =>
array(
'unique' => true,
'dependent' => false,
'joinTable' => 'courses_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'course_id',
)
);
Keep in mind that in HABTM relationships, you don't ever really touch the joinTable beyond specifying which table to use as the joinTable when setting up the relationship. CakePHP will automatically do the rest of the work.
Assume we have 3 models, User, House and Profile with the following associations between them:
User hasMany House (House belongsTo User)
User hasOne Profile (Profile belongsTo User)
I would like to query for houses (inside the HousesController class), whose associated Profiles satisfy the given Profile conditions. Consider the following example:
Assuming that gender is a property of Profile model, I would like to retrieve all the houses, whose owner is male.
I have found this question, which is close enough to what I seek for. In my case, the relationship between models is more complex (House belongsTo User hasOne Profile) and I can't get it to work. I have tried something like this, without any luck:
$this->House->find('all', array(
'contain' => array(
'User' => array(
'Profile' => array(
'conditions' => array(
'Profile.gender' => 'male'
))))));
The above call returns all the houses and in case the gender is male, it includes the respective User's Profile in the result. Otherwise, the User's Profile remains empty. What exactly I need is to return only the houses whose owner is male.
I have actually implemented it using the 'joins' option of Model::find() function, but I would like to know whether is this possible without using 'joins' and if yes, how?
I would recommend explicitly declaring the relationships using the bindModel method.
You could do this from your Houses controller like so:
/**
* Bind the models together using explicit conditions
*/
$this->House->bindModel(array(
'belongsTo' => array(
'User' => array(
'foreignKey' => false,
'conditions' => array('House.user_id = User.id')
),
'Profile' => array(
'foreignKey' => false,
'conditions' => array('Profile.user_id = User.id')
)
)
));
/**
* Standard find, specifying 'Profile.gender' => 'male'
*/
$houses = $this->House->find('all', array(
'conditions' => array(
'Profile.gender' => 'male'
)
));
When I was working on my current project, I ran into a rather complex issue. I'll point out my problem much more detailed right now:
There are three Models: User, UsersExtendedField and UsersExtended.
UsersExtendedField contains custom fields that can be managed manually. All custom fields can be shown in the Users view as well, and be filled out of course. The values are then stored in UsersExtended, which has got two foreignKeys: user_id and field_id.
The relations look like this: User hasMany UsersExtendedField, UsersExtendedField hasMany UsersExtended, UsersExtended belongsTo User, UsersExtendedField.
The problem: When accessing the Users view, a form with user information input is shown. Any UsersExtendedFields are available as well, and since these hasMany UsersExtended, they've got plenty of UsersExtended values. But I want to reduce those to only the value(s) that belong to the User, whose view is shown at the moment. Here are my (desired) relations:
Croogo::hookBehavior('User', 'Crooboard.ExtendedUser', array(
'relationship' => array(
'hasMany' => array(
'UsersExtendedField' => array(
'className' => 'Crooboard.UsersExtendedField',
'foreignKey' => '',
'conditions' => array('status' => 1)
),
),
),
));
class UsersExtendedField extends AppModel {
var $name = 'UsersExtendedField';
var $displayField = 'fieldname';
var $hasMany = array(
'UsersExtended' => array(
'className' => 'Crooboard.UsersExtended',
'foreignKey' => 'field_id',
'conditions' => array(
'UsersExtended.user_id = User.id'
)
),
);
}
This is not the full code, these are the important parts. The problem starts right where I wrote 'UsersExtended.user_id = User.id'. Obviously, this won't work. But I do not have any idea how to access the User.id here. I also could not imagine a HABTM structure to solve this task. Do you have any idea how to get the semantics of this 'UsersExtended.user_id = User.id' to work?
Thank your very much for taking the time to read through this and helping me!
It sounds like you need to set up your HABTM relationship properly.
You already have the join table, UsersExtended, which contains your foreign keys.
Remove all previous relationships and set up HABTM in each of your User and UserExtendedField models.
The relationship code in your User model would look like this:
var $hasAndBelongsToMany = array(
'UsersExtended' => array(
'className' => 'UsersExtended',
'joinTable' => 'UsersExtended', //assuming this is the
//name of that model's table
'foreignKey' => 'user_id',
'associationForeignKey' => 'field_id'
)
);
For more information check out the page in the cakephp book
In addition, this blog post helped me grasp the relationship concepts when I was learning cakephp.
I have table messages with two foreign key: user_id_from and user_id_to.
I need to retrieve both rows from table users with "has one" relation.
How can I do that?
I just noticed this is actually a belongs to relationship. So the code should be as follows...
protected $_belongs_to = array(
'user_from' => array('model' => 'user', 'foreign_key' => 'user_id_from'),
'user_to' => array('model' => 'user', 'foreign_key' => 'user_id_to')
);
The user_from and user_to can be changed to however you want to access them.
i.e.
$message->user_from
and
$message->user_to