I've been searching for all types of solutions and it's not working. I have two models, Bredbook and Genre, in bredbook.php and genre.php, associated with HABTM. No way to save the association.
Here is the code of one model:
public $hasAndBelongsToMany = array('Bredbook' => array('className' => 'Bredbook',
'joinTable' => 'bredbooks_genres',
'foreignKey' => 'genre_id',
'associationForeignKey' => 'bredbook_id'));
Here is the form:
echo $this->Form->create('Bredbook', array('action' => 'firstConnection'));
echo $this->Form->input('Genre', array('options' => $genres, 'empty' => false));
echo $this->Form->end('Validate');
And in BredbooksController.php:
if ($this->request->data)
{
if($this->Bredbook->saveAssociated($this->request->data))
return $this->redirect('/bredbooks/index');
}
The creation of the bredbook is ok, but no association is created in the table bredbooks_genres. I've tried everything... any help will be welcome.
You need to send Bredbook.id in your data array:
<?php
echo $this->Form->create('Bredbook');
//It can be any other attribute, but need some Breedbook data
echo $this->Form->input('Bredbook.id', array('value' => $id));
echo $this->Form->input(
'Genre',
array(
'options' =>$genres,
'empty' => false
)
);
echo $this->Form->end('Validate');
Or make sure your $this->request->data looks similar to this before saving:
Array
(
[Bredbook] => Array
(
//It can be any other attribute, but need some Breedbook data
[id] => 1
)
[Genre] => Array
(
[Genre] => Array
(
[0] => 1
)
)
)
This Solution will work also work when you are creating a new Bredbook as long as you send some data of that Model, it doesn't need to be the id, you can also send name or other attributes from your Bredbook Model. If you send Bredbook.id it will not create a new record and only make the associations, but if you don't send the id and send other attributes (like name for example) it will create a new record and will associate it with the Genre data your are sending.
I finally did it: I don't know if it's a necessary thing, but I just used cake bake to generate everything: http://book.cakephp.org/2.0/en/console-and-shells/code-generation-with-bake.html
Now I need some work to rearrange all the views, but my saving is working, with the exact same code I posted first, and I think I saved some time too with all that generated behaviour I needed !
Related
I am trying to work with HABTM association between Profiles and Qualifications tables.
Model: Profile.php
App::uses('AppModel', 'Model');
class Profile extends AppModel {
public $hasAndBelongsToMany = array(
'Qualification' => array(
'className' => 'Qualification',
'joinTable' => 'profile_qualifications',
'foreignKey' => 'profile_id',
'associationForeignKey' => 'qualification_id',
'unique' => 'keepExisting'
)
);
}
Model: Qualification.php
App::uses('AppModel', 'Model');
class Qualification extends AppModel {
public $hasAndBelongsToMany = array(
'Profile' => array(
'className' => 'Profile',
'joinTable' => 'profile_qualifications',
'foreignKey' => 'qualification_id',
'associationForeignKey' => 'profile_id',
'unique' => 'keepExisting',
)
);
}
Controller: ProfilesController.php
App::uses('AppController', 'Controller');
class ProfilesController extends AppController {
public function edit() {
$this->Profile->id = $this->Auth->user('profile_id');
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->Profile->save($this->request->data)) {
$this->Session->setFlash(__('The profile has been saved'));
$this->redirect(array('action' => 'view'));
} else {
$this->Session->setFlash(__('The profile could not be saved. Please, try again.'));
}
} else {
$this->request->data = $this->Profile->read(null, $this->Auth->user('profile_id'));
}
$salutations = $this->Profile->Salutation->find('list', array('fields' => array('Salutation.id', 'Salutation.abbr_name')));
$qualifications = $this->Profile->Qualification->find('list', array('fields' => array('Qualification.id', 'Qualification.abbr_name')));
$this->set(compact('salutations', 'qualifications'));
}
}
Vew: edit.ctp
<div class="profiles form">
<?php echo $this->Form->create('Profile'); ?>
<fieldset>
<legend><?php echo __('My Profile'); ?></legend>
<?php
echo $this->Form->input('salutation_id');
echo $this->Form->input('first_name');
echo $this->Form->input('middle_name');
echo $this->Form->input('last_name');
echo $this->Form->input('qualification'); /* gives drop down not multi select */
echo $this->Form->input('bio');
echo $this->Form->input('email');
echo $this->Form->input('mobile');
echo $this->Form->input('phone');
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
</div>
The edit view thus generated contains drop down to select a single value at a time for Qualifications attribute.
I want to know how can I generate a view with multi value selection box for qualifications ?
Moreover, what is the mistake in my code right now ?
First time poster, long time user.
I stumbled across this question today, and ended up using the subsequent solution which indeed does work quite nicely. However, I left myself wondering "why wouldn't CakePHP pickup on the HABTM relationship properly?" Especially considering (at least in my case) that the majority of the files had been baked in the cake console.
If we dive a little deeper into the issue, we discover that the problem is actually quite simple. A closer look at this snippet in the PostsController.php reveals how Cake builds in the HABTM relationship to the function, and uses $this->set() in order to pass it to the view (IMPORTANT: using lower-case plural versions "salutations"):
$salutations = $this->Profile->Salutation->find('list', array('fields' => array('Salutation.id', 'Salutation.abbr_name')));
$qualifications = $this->Profile->Qualification->find('list', array('fields' => array('Qualification.id', 'Qualification.abbr_name')));
$this->set(compact('salutations', 'qualifications'));
According to the Cake Cook Book, in order to take advantage of this HABTM in the front end when using the form helper is to specify the variable in singular form & title case (ie: "Salutation")
Snippet from the cook book:
Assuming that User hasAndBelongsToMany Group. In your controller, set a camelCase plural variable (group -> groups in this case, or ExtraFunkyModel -> extraFunkyModels) with the select options. In the controller action you would put the following:
$this->set('groups', $this->User->Group->find('list'));
And in the view a multiple select can be created with this simple code:
echo $this->Form->input('Group');
Should solve your issue without any necessary field tweaking.
Cheers!
Bake on.
Perhaps you need further configuration of your input:
echo $this->Form->input('Qualification',array(
'label' => 'Qualifications',
'type' => 'select',
'multiple' => true, // or 'checkbox' if you want a set of checkboxes
'options' => $qualifications,
'selected' => $html->value('Qualification.Qualification'),
));
I've used this blog post whenever I've come up against HABTM associations. It seems to me that a set of checkboxes maybe desired by default over a select input - maybe someone with greater CakePHP insight can chime in here?
Change
echo $this->Form->input('qualification');
to
echo $this->Form->input('qualification', array(
'multiple' => true
));
The CakePHP manual has more information on the form helper input options.
I've table called Uploads.
I've to make entries in this tables twice with 'type'
i.e. for youtube video link and image in table uploads
So I've written code like this
//for video link
echo $form->input('Project.Upload.Name', array('type'=>'file','label' => false));
and
//for image
echo $form->input('Project.Upload.Name', array('type'=>'file','label' => false));
How can I differentiate these two fields?
Is there any way so of naming convention so that I can separate out fields for links and images.
If you want two Upload-fields, you have to name them like this:
echo $form->input('Project.Upload.0.Name', array('type'=>'file','label' => false));
echo $form->input('Project.Upload.1.Name', array('type'=>'file','label' => false));
This will create an array in $this->data ready for use. Have a look on how to save related model data in the Cookbook for more and deeper information.
Edit
If you need to keep track of what type your upload is you have to add it like this:
echo $form->input('Project.Upload.0.Name', array('type'=>'file','label' => false));
echo $form->input('Project.Upload.0.Type', array('type'=>'hidden','value' => 'image'));
echo $form->input('Project.Upload.1.Name', array('type'=>'file','label' => false));
echo $form->input('Project.Upload.1.Type', array('type'=>'hidden','label' => 'video'));
What you do here is that you associate your first upload with the first type-field which has the hidden value 'image'. So the first entry would be stored in your database something like this (as Cake-Array):
The processing of the image and the video must of course be done before saving it so the database.
array(
[Upload] => array(
[0] => array(
[id] => 1,
[name] => 'test.jpg',
[type] => 'image'
),
[1] => array(
[id] => 1,
[name] => 'test.avi',
[type] => 'video'
)
)
)
I've done a lot of searching but havent been able to solve this yet. I have a user registration form where the user can select a number of store branches as favourites upon registration. I have this relationship set up as a HABTM.
I am able to display the store branches as multiple checkboxes, but I need to display the store name (the store branches belongs to store names) along with the branch name in the label for each checkbox. Something like:
Levi's - Canal Walk
where Canal Walk is the branch name, and Levi's is the store name (coming from a different table)
Can anyone please share some insight on how to do this?
I haven't tested this, but it might work (or help you along the right path):
$branches = $this->Branch->find('list', array(
'fields' => array('Branch.id', 'CONCAT(Store.name, " - ", Branch.name)'),
'joins' => array(
array(
'table' => 'stores',
'alias' => 'Store',
'type' => 'inner',
'foreignKey' => false,
'conditions' => array('Branch.store_id' => 'Store.id')
)
)
));
Set this in your controller, or keep things DRY by placing it in your model in a function such as findFullList()
Hope that helps!
I would do all of this in the view. If your HABTM relationship is setup correctly, a query of the Store model should work something like this:
$stores = $this->Store->findAll();
//Returns
Array([0] => Array(
'Store' => array(),
'Branch' => array(
[0] => array(),
[1] => array()...));
Then pass the $stores variable into the view, and iterate through it with a double nested loop.
foreach($stores as $store){
foreach($store['Branch'] as $branch){
//Code to output checkbox by using $branch['name']
}
}
I got a controller named Posts, a model called Content which is properly linked with other models such as Category and Location.
In my view for add 'Content' i successfully populate the multi select lists with categories and locations to pick to relate to the post. Saving it all works perfectly.
Now in edit/update mode, I can once again fill the multi selects with categories and locations, but it will not select the ones related to the current post. When looking in the database, there are categories and locations successfully realted to the current post.
This is what I got in my controller:
$this->data = $this->Content->read();
$this->set('locations',$this->Content->Location->find('list',array('fields' => array('id','location'))));
$this->set('categories',$this->Content->Category->find('list',array('fields' => array('id','category'))));
And this is what I got in my view:
echo $this->Form->input('Location', array('type' => 'select','multiple' => 'true','options' => $locations));
echo $this->Form->input('Category', array('type' => 'select','multiple' => 'true','options' => $categories));
What am i missing here? How do i get the already related locations and categories, select in the multi select lists?
(filling of non relationship data, will repopulate textfields etc just perfectly)
Grateful for any help!
Jason
instead of
$this->data = $this->Content->read()
try
$params['conditions'] = array(
'Content.id' => $id
);
$params['contain'] = array(
'Category',
'Location'
);
$this->data = $this->Content->find('first', $params);
You will need the Containable Behaviour for that
Use this:
echo $this->Form->input('Location', array(
'label' => 'Location',
'type' => 'select',
'options' => $LocationArray,
'selected'=> 12(Selected Value)
);
I'm trying to save data with following structure:
As you can see, there is HABTM association between users and experiences table. And another HABTM between experiences_users and tags. I created following form:
<?php echo $form->create('Experience', array('action' => 'addClassic'));?>
<?php
echo $form->input('Experience.date', array('dateFormat' => 'DMY'));
echo $form->input('Experience.time', array('timeFormat' => '24', 'empty' => array(-1 => '---'), 'default' => '-1'));
echo $form->input('Experience.name');
echo $form->input('ExperiencesUser.1.note');
echo $form->input('ExperiencesUser.1.rating');
//echo $form->input('Tags.Tags', array('multiple' => 'multiple', 'options' => $tags));
//echo $form->input('ExperiencesUser.1.Tags', array('multiple' => 'multiple', 'options' => $tags));
//echo $form->input('ExperiencesUser.1.Tags.Tags', array('multiple' => 'multiple', 'options' => $tags));
echo $form->input('ExperiencesUser.1.confirmed', array('type' => 'hidden', 'value' => '1'));
echo $form->input('ExperiencesUser.1.user_id', array('type' => 'hidden'));
echo $form->input('ExperiencesUser.2.user_id', array('type' => 'hidden'));
?>
<?php echo $form->end(__('Add', true));?>
And everything works well. saveAll method creates new Experience, assings this new experience to two users (via experiences_users) and sets the stuff around.
What bothers me is that I want to assign some Tags to newly created experiences_users record (to the first one). I thought, that should be done via some of the commented stuff. Every line of this commented code creates form and sends data to $this->data, but it never gets saved.
So my question is: What is the right syntax of $this->data or $form->input in my example to save data into experiences_users_tags?
I figured it out. Cake saveAll function works only for directly associated models. Luckily Cake is able to take care of this:
view
echo $form->input('Tags.Tags', array('multiple' => 'multiple', 'options' => $tags));
controller
$this->Experience->saveAll($data, $parameters);
$this->Experience->ExperiencesUser->save($data);
Cake after calling saveAll() fills $this->data with last inserted id. So second call save() will save data to the right table and set properly foreign keys.