Cakephp - saving multiple checkboxes to a join table - php

I need help with saving multiple checkboxes to a join table.
There are 3 tables:
Customers (id,name, address)
Products (id,product_name,desc) all products are entered.
Customers_Products (id,product_id,customer_id) <-(join table)
Step 1:
Customer selects the desired products (apples,oranges,cherries in checkbox)
and click <Next> button
Step 2:
Fills out the form about themselves (name, address and etc).
and click <Submit> button
Step 3:
I am saving personal info from Step 2 to Customers table and selected products id(s) from Step 1 to Customers_Products table.
It does save the personal info and product id to designated tables, but when customer selects more than one products, it does not save the products id.
it adds row but the products id field is empty.
Here is my view:
<?php echo $this->Form->checkbox('CustomerProduct.product.', array('value' => '1', 'style' => 'float: left; display: inline')); ?>
<?php echo $this->Form->checkbox('CustomerProduct.product.', array('value' => '2', 'style' => 'float: left; display: inline')); ?>
<?php echo $this->Form->checkbox('CustomerProduct.product.', array('value' => '3', 'style' => 'float: left; display: inline')); ?>
<?php echo $this->Form->input('Customers.name', array('value'=>'Jon Toshmatov')); ?>
Controller:
$this->Prospect->saveAll($this->request->data);
Model:
public $hasAndBelongsToMany = array(
'CustomerProduct' => array(
'className' => 'CustomerProduct',
'joinTable' => 'customers_products',
'foreignKey' => 'customer_id',
'associationForeignKey' => 'product_id',
'unique' => 'false',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
Desired result:
I want save the data in the following order:
Customers table:
id name
1 Jon T
Customers_Products *(join table)*
id product_id customer_id
1 4 1
2 3 1
3 5 1

The problem is that each checkbox will also add a 'hidden' input if created via the CakePHP formhelper. This hidden input is added to make sure that checkboxes always send a value (0 or 1) even if they are not checked.
However, in your example, you're creating 3 checkboxes with the same 'name', therefore each checkbox will overwrite the previous value.
The best way is to create a 'multiple' checkbox with the CakePHP formhelper;
echo $this->Form->input('Product', array('multiple' => 'checkbox'));
For this to work properly, there should be a $products viewVar, containing product-ids and labels;
Inside your controller:
public function some_action()
{
// your code here
$this->set('products', $this->Customer->Product->find('list'));
}
More on saving HABTM data here;
http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-related-model-data-habtm
Note
unless you're using non-standard names for your models, it seems your hasAndBelongsToMany is incorrect;
I suspect your relation is Customer hasAndBelongsTo Product, not CustomerProduct?
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasandbelongstomany-habtm

Related

Adding associated value by not using foreign key in CakePHP 2

Recently I've started using CakePHP by starting from using Bake to get simple CRUD.
I have one Model called "Contract" which is associated with "Product" and "Customer" as following.
public $belongsTo = array(
'Customer' => array(
'className' => 'Customer',
'foreignKey' => 'customer_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Product' => array(
'className' => 'Product',
'foreignKey' => 'product_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
Now I wanted to customize the add view (add.ctp) created by Bake by not using select box as an input form for customer_id and product_id. Instead of using select box which shows all the possible name of product/customer that are associated with foreign key I want to use text field so that people can type in one of the field (for example product_code, customer_code) from Product / Customer table and convert it to foreign key to create a row for Contract table. In case there is a chance that no values be found from Customer / Product field I want to skip adding a row to Contract table.
I would like to know if this is possible.
Thank you,
The basic concept is this: Use a JS lib of your choice, guess it's jquery. Watch the text field for changes, on change make an ajax GET request with the value of the text field to a controller / action of your app that returns json. On click on one of the results set the id of the selected record to a hidden field. Done.
If you search Google or Stackoverflow you'll find plenty of examples.

cakephp control dropdown population from database

I'm trying to populate a dropdown/select tag in cakephp,fortunately I was able to populate it with the values coming from my database,
however it displays ALL. How can I limit the population to a specific ID?
To make things clear here's what I want to achieve:
Apples:
form start
dropdown-contains only values that are associated with apples from the DB
button
form end
Currently here's how it looks like
Apples:
form start
dropdown-contains all fruits values from the DB
button
form end
Here's my current code tnx any help/suggestions is very much appreciated
Controller:
$fruits = $this->Model1->Model2->find('list',
array('fields' =>
array('id',
'fruit_name',
//'conditions' => array(''=>'')
)));
$this->set('fruitsList', $fruits);
View:
echo $this->Form->input('Model1.salad_fruits_id',
array('type' => 'select',
'options' => $fruitsList,
));
If you have association between models between models it would be easier. Just add conditions to second model.
//if you don't have association between models
$this->Model1->bindModel(array(
'belongsTo' => array( //example binding
'Model2' => array(
'className' => 'Model2',
'foreignKey' => 'model2_id',
)
)
));
$fruits = $this->Model1->find('list', array(
'conditions' => array(
'Model2.name' => 'apple'
),
'fields' => array(
'id','fruit_name',
)
));

updating related tables in cake

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.

Saving HABTM data while also creating new record in related table with CakePHP

I'm building a site that works as a social network.
I have a profiles table and a Profile model.
Profile HABTM Interests
Profile HABTM Hobbies
etc...
There are a couple of pre-defined records in the hobbies and interests tables, which users can choose from to display on their profile. But they also have the option to add their own hobbies and interests if theirs isn't pre-defined.
A problem arises when the user chooses to add a hobby or interest which doesn't exist yet. Saving the pre-defined records to the join table is not a problem. But I can't seem to create new entries in the interests and hobbies tables during the same save call.
Below is a snippet of the data array I've tried to save (I've also tried other combinations, but this one seems the most logical):
array(
'Interests' => array(
'Interests' => array(
(int) 0 => '1',
(int) 1 => '2',
(int) 2 => '5'
),
'name' => 'Internet' //this is the user-created entry
),
'Hobbies' => array(
'Hobbies' => array(
(int) 0 => '1',
(int) 1 => '2',
(int) 2 => '5',
(int) 3 => '7',
(int) 4 => '8'
),
'name' => 'Reading' //this is also a user-created entry
)
)
The save function: $this->Profile->saveAll($this->request->data, array('deep' => true))
The problem is that the new entries (in this case "Reading" and "Internet") are being ignored during the save. There is no error and everything else is being saved just fine.
If I call $this->Profile->Hobby->saveAll($this->request->data) then it does work, but only for the Hobby model. The new interest is ignored of course, because the save call doesn't go through its model.
Is the data array not formatted correctly, or is this just not possible to achieve in one save call?
You might want to call saveAll using Profile, not Hobby.
$this->Profile->saveAll($this->request->data)

cakePHP assign selected values from 2 arrays using the html input helper

I create 2 arrays from a model, 1 being already selected values from the user, and the 2nd available values which the user can then also select. This is for an edit page. I want to populate a multi-select input box with the values of both models, but want the already chosen values (1st array) highlighted. It creates the models fine, and using array_merge() I merge both the arrays as the options, but the selected does not highlight the correct fields. Any tips?
// Controller:
$ivrNumbersAvail = $this->Survey->SurveyIvrNumber->find("list",array("conditions" => array("OR" => array("SurveyIvrNumber.survey_id" => array($id)))));
$ivrNumbersSelected = $this->Survey->SurveyIvrNumber->find("list",array("conditions" => array("OR" => array("SurveyIvrNumber.survey_id" => array(0)))));
// In the view:
echo $this->Form->input('SurveyIvrNumbers.id',array(
'empty' => '-- Select IVR Number(s) --',
'options' => array_merge($ivrNumbersAvail,$ivrNumbersSelected),
'selected' => $ivrNumbersSelected,
'class' => 'textbox',
'multiple' => true,
'div' => array(
'class' => 'field'
),
'label' => array(
'class' => 'label-tooltip',
'title' => '', //tool tips
'text' => 'IVR Numbers: (you can select multiple numbers)'
),
'after' => '<p class="field-help"></p>'
));
If you set $this->request->data to the record you are currently editing CakePHP will automatically populate this data for you!
// CONTROLLER
// this line sets the data
$this->request->data = $this->Survey->read(null, $id);
// this passes the SurveyIvrNumbers to the view, (you can put any options on to this)
$this->set('SurveyIvrNumber',$this->Survey->SurveyIvrNumber->find('all'));
// VIEW
// CakePHP does the rest
echo $this->Form->input('SurveyIvrNumbers',array(
'empty' => '-- Select IVR Number(s) --', // plus other options
);

Categories