Editing associated models data in cakephp - cakephp

I'm using CakePHP 2.3.6. I have some Models in my project, which are associated and I defined the association explicitly. Now, I have an Edit form, where I retrieve all the models data, and trying to edit those data in the corresponding models. But, edition is not happening, instead, new rows are created in the associated tables.
Here is my associations among the models :
in the model User.php :
public $hasMany=array('Education'=>array(
'className'=>'Education
'foreignKey'=>'user_id'
),
'Experience'=>array(
'className'=>'Experience',
'foreignKey'=>'user_id'
),
'Employment'=>array(
'className'=>'Employment',
'foreignKey'=>'user_id'
),
'ProfessionalQualification'=>array(
'className'=>'ProfessionalQualification',
'foreignKey'=>'user_id'
)
)
in the model Education.php :
public $belongsTo=array('User'=>array(
'className'=>'User',
'foreignKey'=>'user_id'
)
)
in the model Experience.php
public $belongsTo=array('User'=>array(
'className'=>'User',
'foreignKey'=>'user_id'
)
)
in the model Employment.php :
public $belongsTo=array('User'=>array(
'className'=>'User',
'foreignKey'=>'user_id'
)
)
in the model ProfessionalQualification.php :
public $belongsTo=array('User'=>array(
'className'=>'User',
'foreignKey'=>'user_id'
)
)
Now, in the Edit form (View/Users/edit.ctp) :
echo $this->Form->create('User');
echo $this->Form->input('User.name');
echo $this->Form->input('User.username');
echo $this->Form->input('User.password');
echo $this->Form->input('User.address');
echo $this->Form->input('User.phone');
echo $this->Form->input('Education.0.degree');
echo $this->Form->input('Education.0.passing_year');
echo $this->Form->input('Experience.0.title');
echo $this->Form->input('Experience.0.description');
echo $this->Form->input('Employment.0.company');
echo $this->Form->input('Employment.0.description');
echo $this->Form->input('ProfessionalQualification.0.certificate');
echo $this->Form->input('ProfessionalQualification.0.description');
echo $this->Form->submit('Save');
echo $this->Form->end();
in the UsersController.php controller :
public function edit(){
$this->set('title_for_layout','Edit CV');
if(!AuthComponent::user('id'))
throw new NotFoundException(__('Invalid User'));
$user=$this->User->findById(AuthComponent::user('id'));
if(!$user)
throw new NotFoundException(__('Invalid User'));
if($this->request->is('post') || $this->request->is('put')){
if(!$this->User->saveAll($this->request->data)){
$this->Session->setFlash('Sorry, your info could not be saved. Please, try again.');
$this->redirect(array('action'=>'edit'));
}
}
if(!$this->request->data)
$this->request->data=$user;
}
Here, I am trying saveAll() function on User model. I Also tried using save() & saveAssociated() functions, but same result. It doesn't change the corresponding rows in the tables, instead, it creates a new row in all tables, accept the users table, this table successfully gets the new values and updates the values.
What should I do ? Please help me.
Thanks

Here is a way to make it works (in theory) but I'm not sure it's the best and, it's not "secure": Adding the id for related field in your form, with hidden field, like so:
echo $this->Form->create('User');
echo $this->Form->hidden('User.id');
echo $this->Form->input('User.name');
/* ... */
echo $this->Form->hidden('Education.0.id');
echo $this->Form->input('Education.0.degree');
/* ... */
echo $this->Form->hidden('Employment.0.id');
echo $this->Form->input('Employment.0.company');
/* ... */
echo $this->Form->submit('Save');
echo $this->Form->end();
You should check in your controller that the id of your associated models match the id of your main model, if not people will be able to edit associated model not linked with their user model.
Edit: This is an edit for further explanation about the discussion in comment.
When you have hasMany relationship, like so:
public $hasMany = array('Experience') ; // In User class
You have to specify ID when saving the relation, if not the Cake engine cannot infer that you want to update a model instead of saving one.
$data = array(
'User' => array(
'id' => 33,
'name' => 'Holt'
),
'Experience' => array(
array(
/* 'id' => 45, */
'name' => 'PHP'
)
)
) ;
$this->User->saveAssociated($data) ;
Here, you know that the User you're refering to is Holt with the id 33, and so you know that the experiences in the following array refers to this user. But, if you don't specify the id field in the Experience array, how the engine would know which experience you're refering to?
If the relation was a belongsTo, it's easy to infer that's the Experience related to user Holt (there is only one Experience per user according to relation belongsTo or hasOne), and by the way you wouldn't have a nested array.
There are different ways to tell the engine you want to update a model, the 2 I use are:
Setting the id value in the data array (like above)
Setting the $this->Model->id value in your controller: This value is implicitely set when you do a $this->Model->read or a $this->Model->find (like you do)
What I'm sure, is that the first option works for associated model (like in the above data array if you uncomment the id), I'm not sure that the second works for associated model, like doing $this->User->Experience->id = ..., you can try it, I cannot check it right now.

Related

Saving User and Detail rows with Cake 2.4.5

I am very new to cake and I was wondering how i would be able to create a new user and also be able to create the contact details
database is like so
Users
user_id
contact_detail_id
password
role_id
username
Contact_Details
contact_detail_id
address1
address2
and many other fields
In the User model I have assigned public $hasOne = array('ContactDetail');
Since the user will have one contactdetail
Now what I need to know is how would this would be saved in the add method as many said to use the saveassociated although this doesn't seem to be working.
The add view is like so and from my understanding this is correct
<?php echo $this->Form->create('User', array('action' => 'add')); ?>
<fieldset>
<legend><?php echo __('Add User'); ?></legend>
<?php
echo $this->Form->input('User.username');
echo $this->Form->input('User.password');
echo $this->Form->input('roles');
echo $this->Form->input('ContactDetail.name');
echo $this->Form->input('ContactDetail.surname');
echo $this->Form->input('ContactDetail.address1');
echo $this->Form->input('ContactDetail.address2');
echo $this->Form->input('ContactDetail.country');
echo $this->Form->input('ContactDetail.email');
echo $this->Form->input('ContactDetail.fax');
?>
<label>Are you interested in buying property in Malta?</label>
<?php
$interest_buy = array('0'=>'no','1' => 'yes');
echo $this->Form->input('ContactDetail.interest_buy_property',array('type'=>'radio','options'=>$interest_buy,'value'=>'0','legend'=>FALSE));
?>
<label>Are you interested in renting property in Malta?</label>
<?php
$interest_rent = array('0'=>'no','1' => 'yes');
echo $this->Form->input('ContactDetail.interest_rent_property',array('type'=>'radio','options'=>$interest_rent,'value'=>'0','legend'=>FALSE));
echo $this->Form->input('ContactDetail.mobile');
echo $this->Form->input('ContactDetail.phone');
echo $this->Form->input('ContactDetail.postcode');
echo $this->Form->input('ContactDetail.town');
echo $this->Form->input('ContactDetail.newsletter',array('type'=>'checkbox','label'=>'Would you like to register for the newsletter?' ,'checked'=>'1','legend'=>FALSE,));
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
Please see Arun explanation about what to put in your model first and then, you can use $this->User->saveAll(); or $this->User->saveAssociated(); to save both tables at the same time.
If you want to save ContactDetail first and then save User, You can do this second option, but it is not recomended.
$this->User->ContactDetail->create();
$this->User->ContactDetail->save($this->request->data);`
this->request->data['User']['contact_detail_id'] = $this->User->ContactDetail->id`;
$this->User->Create();
$this->User->save($this->request->data);`
But I prefer the first option, to try the first option again,
Note: Make sure ContactDetail and User relationship are there in the model like this in User Model
public $hasOne= array(
'ContactDetail' => array(
'className' => 'ContactDetail',
'foreignKey' => 'contact_detail_id'
)
);
Hope it helps.
In the first look into your database, you should use the following database structure, this will help you in a more directions:
User Model
id
username
password
role_id
ContactDetail Model
id
user_id
address1
address2
Define hasMany model relationship in the User Model with ContactDetail like:
$hasMany => array('ContactDetail');
Now populate an array of Contact details with (id => address1) pair using:
$this->ContactDetail->find('list', array('conditions' => array('user_id' => $user_id)),
'fields' => array('ContactDetail.id', 'ContactDetail.address1')));
Now to save an associated details, use SaveAssociated Method.

CakePHP Not Saving BelongsTo Key

I'm trying to save a record that belongs to another model. Yet, I get an error that the foreign key is missing. The CakePHP docs show examples of this working but I can't get it to work.
Here is the Form:
echo $this->Form->create('Message', array('action'=>'add'));
echo $this->Form->hidden('Ticket.id');
echo $this->Form->input('Message.message');
echo $this->Form->submit('Save Message');
echo $this->Form->end();
Here is what is returned to the controller upon submit:
Array(
[Ticket] => Array
(
[id] => 2
)
[Message] => Array
(
[message] => Message text
)
)
Here is my Message model:
class Message extends AppModel {
public $belongsTo = array('Ticket');
}
Here is my Ticket model:
class Ticket extends AppModel {
public $hasMany = 'Message';
}
Here is my controller logic:
$this->Message->save($this->request->data);
Here is the error message I receive:
Error: SQLSTATE[HY000]: General error: 1364 Field 'ticket_id' doesn't have a default value
The CakePHP documents are pretty clear that Cake will grab the id from the Ticket array. The only way I can get this to work is if I manually assign the ticket id to the message array.
$this->request->data['Message']['ticket_id'] = $this->request->data['Ticket']['id']
I shouldn't have to do that. Where's the magic? I've read at least 20 similar posts but none exactly like this (probably because this is so basic that nobody has this problem because it works for them).
I'm using version 2.4.2
Thanks for any help.
Don't use Model::save() in this case, the reason is that you also want to save associated data, in order for you save data for the main model along with its associated models you need to use Model::saveAssociated().
Your controller should be looking like this
$this->Message->saveAssociated($this->request->data);

How to insert multiple entrys

iam new to cake and want to set up a order process where the user could send some recommendations (friends mail adr) to get a discount. each recommendation reduces the price. so i want to have up to 5 recommendation inserts in one step.
recommendation table is like (id, order_id, email)
i extend the order model with recommendations
class Order extends AppModel {
public $hasMany = array(
'Recommendation' => array(
'className' => 'Recommendation',
)
);
in the order controller i have to use the saveall method.
now, how should the order add view look like. if i use
echo $this->Form->input('Recommendation.mail');
it will only save one recommendation, or ? But i would like to have up to 5 of them on one page...
Thank you very much,
Julius
Change your form to this
echo $this->Form->input('Recommendation.0.mail');
echo $this->Form->input('Recommendation.1.mail');
echo $this->Form->input('Recommendation.2.mail');
echo $this->Form->input('Recommendation.3.mail');
echo $this->Form->input('Recommendation.4.mail');
Then in your controller,use the saveAll method
$this->Recommendation->saveAll($this->request->data);

2 fileds in a table associated to the same table

how can I display values from an over a JOIN table associated table in cakePHP?
I tried the following:
echo $post['Post']['user_id'] // displays e.g. '4'
but then I only get the id not the defined $displayfield of the user model.
It works when I use the association in an input field like:
echo $this->Form->input('user_id', array( 'label' => 'User'); // displays 'Mr. Oizo'
The virtualField is defined in the user model as follows:
public $virtualFields = array(
'VirtualName' => 'CONCAT(User.Name, " ", User.Vorname)'
);
public $displayField = 'VirtualName';
Can anyone help me ?
Best regards
dan
If you have the relationships defined between models correctly, you would display the User virtual field like this in your view:
echo $post['User']['VirtualName']

Why I can't see the result of HABTM?

I am using cakephp since few months, and I have a problem today that I don't know why it is not working as always.
I've got three table:
posts
comments
posts_comments
In the models, I set :
Comment Model:
var $hasAndBelongsToMany = array('Post');
Post Model
var $hasAndBelongsToMany = array('Comment');
Then in my controller, for example the PostController:
$this->set('comments', $this->Post->Comment->find('list', array('order' => 'Comment.id')));
And then in my Post View I have :
<?php
echo $this->Form->create('Post');
echo $this->Form->input('name', array('label' => 'Name', 'maxlength' => '100'));
echo $this->Form->input('Comment.Comment', array('label' => 'New Comment', 'type' => 'select', 'multiple' => true));
echo $this->Form->submit('Add', array('class' => 'button'));
?>
In my others projects it always worked !
I always had my "Comment" displayed on the list, but here, I don't know why it is not working, nothing is displayed, did I forgot something ?
Regards,
4m0ni4c.
I don't know if you solved it yet, but according to Cake convention, the HABTM tables should be named alphabeticaly for them to work magically.
This new join table’s name needs to include the names of both models involved, in alphabetical order, and separated with an underscore ( _ ). The contents of the table should be two fields, each foreign keys (which should be integers) pointing to both of the primary keys of the involved models
So your posts_comments table should be comments_posts, unless you change the association directly on Post and Comment model.

Resources