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.
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 this:
$this->request->data['Person']['person_id'] = $this->Session->read('insertedPersonID');
$savedPerson = $this->Person->saveAll($this->request->data, array('validate'=>'first'));
which updates the selected person row fine however its related tables like PersonColor and PersonParts are not updating, instead inserting new rows.
I thought cake automatically updates the related tables as well as long as the id of the main table which is the foreign key for the other two tables are provided since doing this:
$savedPerson = $this->Person->saveAll($this->request->data, array('validate'=>'first'));
inserts to the Person table and the other two related two tables fine.
How do I make it update the other two tables as well?
Edit:
For the model relations:
Person Model:
public $hasMany = array(
'PersonParts' => array(
'className' => 'Part',
'foreignKey' => 'part_person_id'
),
'PersonColors' => array(
'className' => 'Color',
'foreignKey' => 'color_person_id'
)
);
Part Model:
public $belongsTo = array(
'PartPerson' => array(
'className' => 'Person',
'foreignKey' => 'part_person_id'
)
);
Color Model:
public $belongsTo = array(
'ColorPerson' => array(
'className' => 'Person',
'foreignKey' => 'color_person_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
edit 2
var_dump of $this->request->data
array(3){
["Person"]=>array(4){
["person_user_id"]=>string(1)"3"
["person_name"]=>string(9)"Britney"
["person_category_id"]=>string(2)"16"
["visibility"]=>string(1)"1"
["person_id"]=>string(1)"71"
}
["PersonParts"]=>array(1){
[0]=>array(3){
["part_name"]=>string(4)"hands"
["quantity"]=>string(1)"2"
["part_part_type_id"]=>string(1)"1"
}
}
["PersonColors"]=>array(2){
[0]=>array(4){
["color_name"]=>string(3)"blue"
["test_field1"]=>string(1)"8"
["test_field2"]=>string(1)"9"
["position"]=>int(1)
}
[1]=>array(2){
["color_name"]=>string(5)"red"
["position"]=>int(2)
}
}
}
Note: This var_dump is only showing ["person_id"]=>string(1)"71" under Person array as the added field to make cake do an update, not insert... person_id is not showing under the PersonParts and PersonColors here since it's not working that way. What should I pass or How should I do an update on the other 2 related tables?
To make Cake do an update on the related tables, you do need to pass in the id of the related record, otherwise Cake won't know which record to update.
You can make this a hidden field in your form, which is how I do things.
The var dump for PersonParts should look like this (note the extra 'part_id' field):
["PersonParts"]=>array(1){
[0]=>array(3){
["part_id"]=>string(1)"7"
["part_name"]=>string(4)"hands"
["quantity"]=>string(1)"2"
["part_part_type_id"]=>string(1)"1"
}
}
If you don't pass the id, then (from memory) Cake will delete the existing related records, and add new ones.
Okay, so I have a form in CakePHP that submits to a database. In this form it submits a field called client_id and it is stored in the database as such as well.
Then I have a view to allow me to view all of the invoices that have ever been created. To view the client responsible for the invoice, I can currently only see the id entered in the form by placing: <?php echo $invoice['Invoice']['client_id']; ?> in the view.
The invoices go to one database called: invoices
The clients name is not stored in the invoices table, just the id
The clients information is stored in one database called: clients
I want to be able to actually display out the clients real name in the invoices view rather than the client id.
I tried adding the following query to my index controller, But i'm not sure what to do after this or if this is even right.
$this->set('clients', $this->Invoice->query("SELECT * FROM clients WHERE id='89545'"));
In order to keep this question short in the first place, Please request specific code by commenting. i.e. Controller code, view code, etc... Thank you in advance.
Additional Thoughts
If I wasn't using CakePHP I could use something like the following, So I guess I just don't know how to put this into cakephp "language".
<?php
query($con, "SELECT name FROM clients WHERE id='$client_id'");
echo $row['name'];
?>
roughly!
Update
Here are my models
First one being the Client.php
<?php
class Client extends AppModel {
public $hasMany = array(
'Invoice' => array(
'className' => 'Invoice',
'foreignKey' => 'client_id'
)
);
}
?>
Second one being the Invoice.php
<?php
class Invoice extends AppModel {
public $belongsTo = array(
'Client' => array(
'className' => 'Client',
'foreignKey' => 'client_id'
)
);
}
?>
And finally, to get my invoices from the database, I am using the following inside: InvoicesController.php
public function index() {
$this->set('invoices', $this->Invoice->find('all'));
}
Have you properly set up your model associations? If so you should be able to do something like $invoice['Client']['client_name'] assuming you didn't use recursive = -1.
/edit: Ok I don't mind throwing some code out, but this is a fundamental concept you'll have to try to wrap your head around. Every model that is connected to another model has to have the association set up or things will be painful.
I am assuming a Client hasMany Invoice. So each invoice is specific to a client, and they can have multiple invoices (ex. October 2013 vs November 2013 invoice). From the CakePHP page we see:
class User extends AppModel {
public $hasMany = array(
'Comment' => array(
'className' => 'Comment',
'foreignKey' => 'user_id',
'conditions' => array('Comment.status' => '1'),
'order' => 'Comment.created DESC',
'limit' => '5',
'dependent' => true
)
);
}
So using that as our template, we end up with:
public $hasMany = array(
'Invoice' => array(
'className' => 'Invoice',
'foreignKey' => 'client_id'
)
);
And that goes in Client.php. As the inverse of hasMany is belongsTo, we have an Invoice belongsTo Client. Again, using the CakePHP page as the template, we end up with:
public $belongsTo = array(
'Client' => array(
'className' => 'Client',
'foreignKey' => 'client_id'
)
);
And that goes in Invoice.php. Once you set up those associations, whenever you do something like $this->Invoice->find('all'); or $this->paginate('Invoice');, with proper $recursive settings, Cake will grab the corresponding Client record. This allows you to do what I said before, something like $invoice['Client']['client_name'].
You can also use the $actsAs = array('Containable'); in the model in order to use the 'contain' directive in your controller's find method (instead of using recursive which most likely will get unwanted data on models with many relations)
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.
I'm trying to figured out what's the best way to make a "Has One Belong to One" relation in CakePHP. Unfortunatly I didn't found anything for helping me on the internet.
I've tried to proceed like that:
Company model :
var $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
User model :
var $hasOne = array(
'Company' => array(
'className' => 'Company',
//'foreignKey' => 'user_id',
'dependent' => true
)
);
But still cakePHP allow me to create two companies for one user.
And here my database schema :
Company : id, name, ..., user_id
User : id, name, ...
Many thanks
CakePHP can handle the following relationships only:
one to one
one to many
many to one
many to many
Read more here
If you want to do "Has One Belong to One" then use the hasOne feature in both objects.
If each user has only one company and each company belongs to one and only one user, shouldn't they be on the same table?
like:
USER
Id
Name
...
Company
Sorry if I shouldn't ask questions back here but seemed pertinent.
In your database, company table, user_id should be set unique.