Why I can't see the result of HABTM? - cakephp

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.

Related

Editing associated models data in 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.

CakePHP - Retrieving a list of options from another table, to use with form helper/ before Instering

Here is Yet another cakePHP question! I have table called blood_groups which has blood_group_id and group fields.. Then I have another table called donors, which has several fields such as name, surname etc. Another field included inside this table is the foreign key 'blood_group_id' which will need to map to the blood_group table on retrieval. in the donor registration view, i want to be able to retrieve the values from the blood_groups table, and display them using the formHelper (with their respective id's).
I have gone through CAKE doc, and I understand that I would need to create the association between my models, but I am struggling to figure this one out. Should I create $hasOne association inside the Donor Model (considering that the Donor table has the fk of the other table). And how would I go about retrieving the options of blood_groups from the blood_groups Model?
Should It work like this?(and are any other prerequisites involved?) :
In my DonorController -
$this->set('blood_groups', $this->Donor->Blood_Group->find('all'));
in Views/Donor/add.ctp
echo $this->Form->input('blood_group_id');
Accessing data through associations is fine. But for radios or checkboxes you want to do a find('list). Your model and variable name does not match the CakePHP convention, there should be no underscore.
Properly named this should be already enough to populate the input.
// controller
$this->set('bloodGroups', $this->Donor->BloodGroup->find('list'));
// view
echo $this->Form->input('blood_group_id');
If you don't follow the conventions for some reason:
echo $this->Form->input('blood_group_id', array(
'options' => $bloodGroups
));
See:
Linking Models Together
The Form Helper
Create one function in BloodGroup Model
function getDonors(){
$options = array(
// 'conditions' => array('Donor.blood_group_id'=>$id),
'joins' => array(
array(
'alias' => 'Donor',
'table' => 'donors',
'type' => 'LEFT',
'conditions' => array(
'Donor.blood_group_id = BloodGroup.blood_group_id',
),
)
),
'fields' => array('Donor.name','Donor.surname','Donor.blood_group_id',
'BloodGroup.blood_group_id')
);
$returnData = $this->find('all',$options);
return $returnData;
}
Now from controller call this function
App::import('model','BloodGroup');
$BloodGroup = new BloodGroup;
$donorList = $BloodGroup->getDonors();
$this->set('donorList',$donorList);
In view file you will get list of donors in $donorList.

how to use cakedc/search plugin for searching across 3 different tables with 1 search bar?

I am using CakePHP2.4 and the search plugin https://github.com/CakeDC/search
I have the following
Employee hasOne EmployeeProfile
Employee hasMany Qualification
So I have a single search bar.
the search bar will search using LIKE through the following fields
Employee.name
EmployeeProfile.email
Qualification.title
how do I configure the model Employee->filterArgs for this search?
This is a cross-posting of the original issue here
The documentation includes an example.
'username' => array('type' => 'like', 'field' => array('User.username', 'UserInfo.first_name')),
You just have to make sure the models you're calling are available in your find() call. In the example the find will do a like on the users table username and on the user_infos first_name field at the same time.
I'd like to expand on this as I've been trying to setup a search on a hasMany relationship for a few hours and couldn't find anything. Mark mentionned "custom bindModel (as hasOne) for hasMany relationship (Qualification)". Here's how it's done :
$this->Employee->bindModel(array(
'hasOne' => array(
'Qualification' => array(
'foreignKey' => false,
'conditions' => array('Employee.id = Qualification.employee_id')
)
)
), false);
Just bind it before your paginate and add Qualification.title in your field list in your filterArgs

CakePHP SaveMany not saving

I have a issue with the SaveMany call in my CakePHP function.
The code below is my current attempt. This now sort of works, it does not make any errors at all but only the savefield will save any data, the saveMany, although it does not come back with errors does NOT save the data?
Please Help???
$InvoiceArrayData = array(
array('Invoicedata' => array('workdes' => $WorkHolder)),
array('Invoicedata' => array('price' => $PriceHolder)),
);
foreach($InvoiceArrayData as $InvoiceArrayKey => $InvoiceArrayValue) {
debug($InvoiceArrayValue);
$this->Invoicedata->saveMany($InvoiceArrayValue['Invoicedata']);
$this->Invoicedata->saveField('invoicejoblists_id', $MyJobIDInput);
$this->Invoicedata->saveField('invoicejoblists_id', $MyJobIDInput);
$this->Session->setFlash('Invoice Data Saved', 'default', array(), 'good');
//$this->redirect($this->Auth->redirect('/AdminInvoiceSystem/'));
}
When the code runs it does redirect with the saved meessaged but when the database is checked, only the invoicejoblist_id is saved.
Have not not done something right?
Glenn
UPDATE ::
Ok so what I am trying to do is to build an invoice system, I have a number of tables one of which 'invoicedatas' which has 'id, workdes, price, invoicejoblists_id' contained within it. ID is the key and is sent to auto count.
When the user starts to make a new invoice they fill in a form which saves in the other tables. But also in this form they input a work detail and price for that work.
This is then sent over to the function I am working on now, which returns no errors but does not save. Or I should say the saveMany call does not work, the saveField works and saves the ID number which I call from one of my other tables.
A bit of code I forget to add are the vars, which are just basic holders for the $this->data I am trying to save.
$WorkHolder = $this->data['workdes'];
$PriceHolder = $this->data['price'];
Please Help......
Glenn.
OK Here goes, I try and see if I can explain myself in more detail.
I am going to re-do so of my work to make it just plan easier for the UI apart form anything. To explain, I will now have a form which sets the invoice job, e.g jobnumber per user, user id, and other bits. This information will go into a table call invoicejoblist
The second table invoicedata holds just workdes and price along with invociejoblists_id (this links each row with the invoice job details).
But no matter what I do I can not get it to save into workdes and price. This is how my current test setup looks :
MY .cpt file:
$InvoiceMake = $this->Form->create('Invoice', array('url'=>'/InvoiceSet/', 'id' => 'InvoiceSet', 'inputDefaults' => array('div' => false) ) );
$InvoiceMake .= "<div id=\"InvoiceDataInput\">Please Input Description<br />";
$InvoiceMake .= $this->Form->textarea('Invoicedata.0.workdes');
$InvoiceMake .= $this->Form->textarea('Invoicedata.1.workdes');
$InvoiceMake .= $this->Form->textarea('Invoicedata.2.workdes');
$InvoiceMake .= $this->Form->textarea('Invoicedata.3.workdes');
$InvoiceMake .= $this->Form->textarea('Invoicedata.4.workdes');
$InvoiceMake .= "</div>";
$InvoiceMake .= $this->Form->submit('Make Invoice', array('div' => false, 'class' => 'ButtonInvoice'));
$InvoiceMake .= $this->Form->end();
echo $InvoiceMake;
My test function in controller:
function test() {
debug($this->data);
$HoldeME = $this->data;
$this->loadModel('Invoicedata');
$this->Invoicedata->saveAll($HoldeME);
}
These return not errors but the workdes information submitted will not save. The only thing I put in my model was:
public $belongsTo = array(
'Invoicejoblists' => array(
'className' => 'Invoicejoblists',
'foreignKey' => 'invoicejoblists_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
I did have some checks to make sure the inputs where not empty but remove them to see if that was my problem, not sure it that was right or not.
Hope that is better explained, I have gone down to the right basic level to just test save any data set but it still will not let me, is that because I should have something in my model?
Any help most welcome
Glenn.
I really have no clue what you're asking, but I'm giving it a blind-shot.
You should be able to save an item and as many sub/related items as you want in a single saveAll().
Just make sure your form (or the data) is formatted correctly per the copious instructions found in the CakePHP book.
As an example:
echo $this->Form->create('Invoice');
echo $this->Form->input('name');
echo $this->Form->input('Price.0.amount');
echo $this->Form->input('Price.1.amount');
echo $this->Form->end('Submit');
Then, when you do a saveAll() (or saveMany() - whatever), your Invoice will save as well as the two Prices (assuming Invoice is related to Price).
If you're trying to build the data manually, but don't know how it should be formatted, you can always create a form like above, submit it, and debug() the results to see how CakePHP would format it.
Hope that helps clarify for you.

How can i save multiple checkbox value those are checked in cakephp hasMany relation?

Suppose I have 3 tables property_details, property_feature_details, property_feature_relations.
PropertyDetail Model has the hasMany relation with PropertyFeatureRelation.
AT the time saveing my data array looks like that:
$this->data = array('PropertyDetail' => array('name'=>'xyz'),'PropertyFeatureRelation' => array('0' => array('feature_id'=>1),'1' => array('feature_id'=>5),'2' => array('feature_id'=>0),'3' => array('feature_id'=>0)));
Those feature_ids values are coming out from the checkboxes. Those are checked they are contains ids value and non checked are having 0 value. But in the child table saves all the data zero and non zeros.
Actually I want to save those checkboxes values which are only checked. Please do not provide any manual controller logic. Help me.
I am explaining you with my example which is having question ,answer and its survey
you can use multiple checkbox syntax as below:
$answers=array();
$tmp_ans=$question['Answer'];
for($j=0;$j < count($tmp_ans);$j++)
$answers[$tmp_ans[$j]['id']]=$tmp_ans[$j]['answer'];
echo '<li>';
echo $this->Form->input('Answer', array(
'type' => 'select',
'name'=>'Answer['.$question['Question']['id'].']',
'class'=>'test',
'label'=>false,
'multiple' => 'checkbox',
'options' =>$answers ,
));
echo '</li>';
after that you will have only those answers which you have checked others will not come in array of post so to save data you can use below syntax
if(!empty($this->data['Answer'])){
foreach ($this->data['Answer'] as $key=>$val):
if(!empty($val)):
if(is_array($val)):
foreach ($val as $ans):
$post_data['UserAnswer']['id']='';
$post_data['UserAnswer']['survey_id']=$id;
$post_data['UserAnswer']['user_id']=$this->Auth->user('id');
$post_data['UserAnswer']['question_id']=$key;
$post_data['UserAnswer']['answer_id']=$ans;
$this->UserAnswer->save($post_data['UserAnswer']);
endforeach;
else:
$post_data['UserAnswer']['id']='';
$post_data['UserAnswer']['survey_id']=$id;
$post_data['UserAnswer']['user_id']=$this->Auth->user('id');
$post_data['UserAnswer']['question_id']=$key;
$post_data['UserAnswer']['answer_id']=$val;
$this->UserAnswer->save($post_data['UserAnswer']);
endif;
endif;
endforeach;
}

Resources