Working with HABTM Form Data in CakePHP

I would like to document several speedy ways I have of working with HABTM data.

The Tables

CREATE TABLE `posts` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  `body` text NOT NULL,
  PRIMARY KEY  (`id`)
);
CREATE TABLE `tags` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`)
);
CREATE TABLE `posts_to_tags` (
  `post_id` int(11) NOT NULL,
  `tag_id` int(11) NOT NULL,
  PRIMARY KEY  (`post_id`,`tag_id`)
);

The Models

Before we get started, lets setup the models. models/post.php
<?php
class Post extends AppModel {
	var $name = 'Post';
	
	var $hasAndBelongsToMany = array(
		'Tag' => array(
			'className' => 'Tag',
			'joinTable' => 'posts_to_tags',
			'foreignKey' => 'post_id',
			'associationForeignKey' => 'tag_id',
			'with' => 'PostToTag',
		),
	);	
	
}
models/tag.php
<?php
class Tag extends AppModel {
	var $name = 'Tag';
}

HABTM Select

This is the default CakePHP way of handling HABTM forms.

It will allow you to add or remove HABTM data using a multiple select box (by holding CTRL).

[inline:habtm-select.jpg] views/posts/form.ctp
<?php echo $form->create('Post',array('url'=>array('action'=>'form')));?>
	<fieldset>
		<legend><?php __('Post Details');?></legend>
		<?php
		echo $form->input('id');
		echo $form->input('name');
		echo $form->input('body');
		echo $form->input('Tag.Tag');
		?>
	</fieldset>
<?php echo $form->end('Submit');?>
controllers/posts_controller.php
<?php 
class PostsController extends AppController {
	var $name = 'Posts';
	
	function form($id = null) {
		if (!empty($this->data)) {
			// form sends data as:
			// $this->data['Post']['Tag']['Tag'][1] = 1;
			// $this->data['Post']['Tag']['Tag'][3] = 3;
			
			// save the data (auto-handles habtm save)
			$this->Post->create();
			if ($this->Post->save($this->data)) {
				$this->Session->setFlash(__('The Post has been saved.',true));
				$this->redirect(array('action'=>'form',$this->Post->id));
			}
			else {
				$this->Session->setFlash(__('The Post could not be saved. Please, try again.'),true);
			}
		}
		if (empty($this->data)) {
			$this->data = $this->Post->read(null, $id);
		}
		$tags = $this->Post->Tag->find('list',array('fields'=>array('id','name')));
		$this->set(compact('tags'));
	}
}

HABTM Checkbox

If you have too many options to list in a select box, or if the labels in the select options do not suit your needs then you may want to try HABTM Checkbox.

It will allow you to add or remove HABTM data using a checkbox for each HABTM item.

[inline:habtm-checkbox.jpg] views/posts/form.ctp
<?php echo $form->create('Post',array('url'=>array('action'=>'form')));?>
	<fieldset>
		<legend><?php __('Post Details');?></legend>
		<?php
		echo $form->input('id');
		echo $form->input('name');
		echo $form->input('body');
		?>
	</fieldset>
	<fieldset>
		<legend><?php __('Tags');?></legend>
		<?php

		// output all the checkboxes at once
		echo $form->input('Tag',array(
			'label' => __('Tags',true),
			'type' => 'select',
			'multiple' => 'checkbox',
			'options' => $tags,
			'selected' => $html->value('Tag.Tag'),
		)); 

		/*
		// output all the checkboxes individually
		$checked = $form->value('Tag.Tag');
		echo $form->label(__('Tags',true));
		foreach ($tags as $id=>$label) {
			echo $form->input("Tag.checkbox.$id", array(
				'label'=>$label,
				'type'=>'checkbox',
				'checked'=>(isset($checked[$id])?'checked':false),
			));
		}
		*/
		?>
	</fieldset>
<?php echo $form->end('Submit');?>
controllers/posts_controller.php
<?php
class PostsController extends AppController {
	var $name = 'Posts';

	function form($id = null) {
		if (!empty($this->data)) {

			/*
			// get the tags from the single checkbox data
			$this->data['Tag']['Tag'] = array();
			foreach($this->data['Tag']['checkbox'] as $k=>$v) {
				if ($v) $this->data['Tag']['Tag'][] = $k;
			}
			*/
			
			// save the data
			$this->Post->create();
			if ($this->Post->save($this->data)) {
				$this->Session->setFlash(__('The Post has been saved.', true));
				$this->redirect(array('action'=>'form',$this->Post->id));
			}
			else {
				$this->Session->setFlash(__('The Post could not be saved. Please, try again.', true));
			}
		}
		if (empty($this->data)) {
			$this->data = $this->Post->read(null, $id);
		}
		$tags = $this->Post->Tag->find('list',array('fields'=>array('id','name')));
		$this->set(compact('tags'));
	}
}

HABTM Text Add

If you want to allow users to enter tags that are added to the current tags.

It will allow you to add but not remove HABTM data using a text input with comma seperated values.

[inline:habtm-textadd.jpg] views/posts/form.ctp
<?php echo $form->create('Post',array('url'=>array('action'=>'form')));?>
	<fieldset>
 		<legend><?php __('Post Details');?></legend>
	<?php
		echo $form->input('id');
		echo $form->input('name');
		echo $form->input('body');
	?>
	</fieldset>
	<fieldset>
 		<legend><?php __('Tags');?></legend>
	<?php
		// display current tags
		$links = array();
		if ($post['Tag']) {
			foreach($post['Tag'] as $k=>$row) {
				$links[] = $row['name'];
			}
		}
		echo '<div>';
		echo __('Current tags',true).':<br/>';
		echo implode(', ',$links);
		echo '</div>';
	    echo $form->input('Tag.tags',array(
			'type' => 'text',
			'label' => __('Add Tags',true),
			'after' => __('Seperate each tag with a comma.  Eg: family, sports, icecream',true)
		));
	?>
	</fieldset>
<?php echo $form->end('Submit');?>
controllers/posts_controller.php
<?php
class PostsController extends AppController {
	var $name = 'Posts';

	function form($id = null) {
		if (!empty($this->data)) {

			// get the tags from the text data
			if ($this->data['Tag']['tags']) {
				$this->data['Post']['id'] = $id;
				$tags = explode(',',$this->data['Tag']['tags']);
				foreach($tags as $_tag) {
					$_tag = strtolower(trim($_tag));
					if ($_tag) {
						// check if the tag exists
						$this->Post->Tag->recursive = -1;
						$tag = $this->Post->Tag->findByName($_tag);
						if (!$tag) {
							// create new tag
							$this->Post->Tag->create();
							$tag = $this->Post->Tag->save(array('name'=>$_tag));
							$tag['Tag']['id'] = $this->Post->Tag->id;
							if (!$tag) {
								$this->Session->setFlash(__(sprintf('The Tag %s could not be saved.',$_tag), true));
							}
						}
						if ($tag) {
							// use current tag
							$this->data['Tag']['Tag'][$tag['Tag']['id']] = $tag['Tag']['id'];
						}
					}
				}
			}

			// prevent the current tags from being deleted
			$this->Post->hasAndBelongsToMany['Tag']['unique'] = false;
			
			// save the data
			$this->Post->create();
			if ($this->Post->save($this->data)) {
				$this->Session->setFlash(__('The Post has been saved.', true));
				$this->redirect(array('action'=>'form',$this->Post->id));
			}
			else {
				$this->Session->setFlash(__('The Post could not be saved. Please, try again.', true));
			}
		}
		if (empty($this->data)) {
			$this->data = $this->Post->read(null, $id);
		}
		
		// get the posts current tags
		$post = $id ? $this->Post->find(array('Post.id'=>$id)) : false;
		
		$this->set(compact('post'));
	}
}

HABTM TextArea Edit

Finally, your admin may ask you if they can just edit all of the data as a comma seperated list.

It will allow you to add and remove HABTM data using a textarea input with comma seperated values.

[inline:habtm-textareaedit.jpg] views/posts/form.ctp
<?php echo $form->create('Post',array('url'=>array('action'=>'form')));?>
	<fieldset>
 		<legend><?php __('Post Details');?></legend>
		<?php
		echo $form->input('id');
		echo $form->input('name');
		echo $form->input('body');
		?>
	</fieldset>
	<fieldset>
 		<legend><?php __('Tags');?></legend>
	<?php
	    echo $form->input('Post.tags',array(
			'type' => 'textarea',
			'label' => __('Tags',true),
			'after' => __('Seperate each tag with a comma.  Eg: family, sports, icecream',true)
		));
	?>
	</fieldset>
<?php echo $form->end('Submit');?>
controllers/posts_controller.php
<?php
class PostsController extends AppController {
	var $name = 'Posts';

	function form($id = null) {
		if (!empty($this->data)) {

			// get the tags from the textarea data
			$tags = explode(',',$this->data['Post']['tags']);
			foreach($tags as $_tag) {
				$_tag = strtolower(trim($_tag));
				if ($_tag) {
					$this->Post->Tag->recursive = -1;
					$tag = $this->Post->Tag->findByName($_tag);
					if (!$tag) {
						$this->Post->Tag->create();
						$tag = $this->Post->Tag->save(array('name'=>$_tag));
						$tag['Tag']['id'] = $this->Post->Tag->id;
						if (!$tag) {
							$this->_flash(__(sprintf('The Tag %s could not be saved.',$_tag), true),'success');
						}
					}
					if ($tag) {
						$this->data['Tag']['Tag'][$tag['Tag']['id']] = $tag['Tag']['id'];
					}
				}
			}

			// save the data
			$this->Post->create();
			if ($this->Post->save($this->data)) {
				$this->Session->setFlash(__('The Post has been saved.', true));
				$this->redirect(array('action'=>'form',$this->Post->id));
			}
			else {
				$this->Session->setFlash(__('The Post could not be saved. Please, try again.', true));
			}
		}
		if (empty($this->data)) {
			$this->data = $this->Post->read(null, $id);
			// load the habtm data for the textarea
			$tags = array();
			if (isset($this->data['Tag']) && !empty($this->data['Tag'])) {
				foreach($this->data['Tag'] as $tag) {
					$tags[] = $tag['name'];
				}
				$this->data['Post']['tags'] = implode(', ',$tags);
			}
		}
		
		// get the posts current tags
		$post = $id ? $this->Post->find(array('Post.id'=>$id)) : false;
		
		$this->set(compact('post'));
	}
}

Conclusion

There are many great ways to work with HABTM data, these are just a few examples of what can be done. Enjoy your CakePHP.

Comments

Add new comment

Acutually I came to know that I does not fire querry to save post
Can you tell me why so?

Guest's picture

I Used this code but it is saving claim successfully but its not saving post :(

Guest's picture

The select example worked perfectly for adding new records. But, after adding, I'd like to re-display the form to allow changes. Geven that I'm working with members rathr than tags, the following loads all the other fields in the form with default values, but won't add "selected" to the multi-select where appropriate. How to view what I've just saved?

$member = $this->Member->findById($id);
$this->request->data = $member;

Guest's picture

I know this is years old but it's still helpful! After spending hours upon hours trying to get blog posts to be tagged this was the solution, turns out my array format for save() was wrong.

Thank you for this article!

Guest's picture

Hi Chris, so put your solution please. It would be very much appreciated ;) I use newer version of cake too

Guest's picture

I can not save on HABTM Checkbox , why data is not save ? please help.

Guest's picture

Thanks a lot. It works excellent, but not on edit. When I edit the post I can not loop current tags. Please help. Thanks!

Guest's picture

Very helpfull. Thanx!

Guest's picture
Guest's picture

Your tutorial is very helpfull for me. With some modification for relation table name, I was success to create similiar method between messages and multiple recipients. Thank you bro!

Guest's picture

Hi
i am not delete all tags from a post.

please help me

Guest's picture

In models/post.php the 11th line should be 'with' => 'PostsToTag', . Isn't it?

Guest's picture

Hi, i have a question, i think it is relate to HABTM and ajax i need your help.

I have a form to servey what cities in country people like

People must fill his name, address, and email and select a country, and cities in that country he like. user can selected more than one cities

My form have a select field (drop down list) display a lish of country, contries save in Country table

when user change the country so my form must reload cities of selected country.

so i think i must implement dynamic multiple checkboxs for the cities

a country have multiple cities, but user just select some cities he like

how to implement my form and model? could you help me?

Guest's picture

When I edit the post, I can't remove some tags I added before, can only add new tag. Could you tell me how to show the tags in the form tags for removing some tags?

Guest's picture

Hi, I tried your code, it's work great in the form add, but when I edit post, the form tag didn't show any tags I added before, and I don't know how to fix it, any idea for me?

Guest's picture

Thanks a lot! Your explanation has helped tremendously!

Guest's picture

Thanks, Nice job

Guest's picture

Oh wow! Now I see that this post is over 2 years old....
and still helping people!

Kudos to you!

(feel free to merge this comment with the previous one)

Guest's picture

Extremely helpful! You have no idea :)

I love Cake for its simplicity and I hate Cake for making you do it a certain way (otherwise, it fails completely).

But still... it's great when it works!

Guest's picture

woww, it's nice for me..
i am a newbie :)
but, how about view, edit, and delete tags???

Guest's picture

Thanks a lot for this tutorial, havent seen anything like it and it was perfect help for my multichoice form option.

Guest's picture

Thank you so much, your work is great.

It took me a while cause I was playing with keywords and documents instead of tags and posts.

this is the key...
echo $this->Form->input( 'Document.keywords', array( ...

keep to convention and cake will do the rest.

Guest's picture

omg, this really is an awesome how-to-do.

missing doc for cakephp beginners!

thanks thousand time!

Guest's picture

exactly what I needed!!!

good stuff thanks^^

Guest's picture

Hi, first of all this is great, thanks.

One question, at the front end of the website, (in my case a blog), how would you display the tags given to the post, and make the tags into links which when clicked shows all the posts with that tag?

eg. Tags: Sports Cars

When you click on Sports Cars it shows all the posts associated with that tag_id.

I have already implemented the search facility as per another article on Mr Php, I can successfully search by tag_id, so I think I am half way there!?

Sorry I am new to PHP.

Thanks

Guest's picture

I'm searching for this, too! I have my problems with the filter. (Even with the example at the other articles.. So it would be a great way to find my errors)

Guest's picture

This was a lifesaver!!! I was trying to associate categories with jobs but was having no luck writing to the categories_jobs table!!!

Now a new question... Can you give me a clue as to how I would add the category association in a table?

For example, each job has multiple categories, and I would like to print the name of those categories in a column. How do I go about doing that?

Guest's picture

First:Thank you! This is great! BUT :)
I try to do things link fabio (August 28th, 2009 fabio)

I think the problem is that the $this->data is like

[Tag] => Array
(
[Tag] => Array
(
[0] => 2
[2] => 8
)
)

If I "expand" the checkbox with another field I need an array lile

[Tag] => Array
[Tag] => Array
(
[0] => Array
(
[tag_id] => 2
[another] => "this is great"
)

[2] => Array
(
[tag_id] => 8
[another] => "this is great"
)

)
)

but that does work! But why?

Can someone give me a hint?

Thanks!

THAAAAAAANKS.
It really helps me.

Guest's picture

This is the detail of doco that is missing from the CakePHP manual that is really what I needed. Thanks a bunch. You should see if you can get this in the official docs.

Thank you for this great article and the perfect summary of the HABTM-Possibilities!

I just wanted to say that I've used this tutorial twice on my latest project, once as a checkbox list, and once as a textarea - and both times it worked fantastically well. Thank you :)

Guest's picture

Great article. A couple of questions:

1. Wondering why you have Tag.Tag in the input field. Not sure I understand why that was necessary.
2. CakePHP HABTM conventions say that the join table should be called posts_tags -- is there a reason why you chose to go with posts_to_tags?

Guest's picture

thanks for the comment.

1. it needs to be Tag.Tag in order to come into the controller in the right array key to save. have a play with debug($data) in the controller to see the difference. i think that using save() without Tag.Tag will mean nothing gets saved into the tags HABTM table.

2. i prefer putting a _to_ in the middle because otherwise longer table names are harder to understand, long_table_other_long_table looks much nicer as long_table_to_other_long_table. you can call it anything, just personal taste more than anything.

brett's picture

I did the approach with textarea (last one).

My problem is that the relation table posts_to_tags has one more field taking values 1,2,3 according to some conditions, which I want to add a value along with the save. Is this possible somehow?

Guest's picture

Your user would have to enter it in some delimited format... eg: "sports:3" and then you would have to break it apart in the controller after the data is submitted.

brett's picture

Hi, very good explanation in this article !

I wondering if someone could give some tips about extending the join table with extra field and then being able to handling it with nested checkboxes+textfields. Let me explain a bit better:

Think about extending the model like this:

CREATE TABLE `posts_to_tags` (
`id` int(11) unsigned NOT NULL auto_increment,
`post_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL,
`extravaue` varchar(100) NOT NULL default 'yes',
PRIMARY KEY (`post_id`,`tag_id`)
);

The idea is to set values for 'extravalue' like this:

'no' ....................if unchecked
'yes' ..................if checked
'whatever'........... if checked and a string 'whatever' is inserted

In other words I would like to associate to each checkboxes an additional
input text field to be eventually filled only if the checkboxes are
previously checked

With a bit of javascript (look at this example: http://www.html.it/articoli/1756/esempio.html ) I think it could be possible but i can't figure out how to set the FormHelper options to show one text field beside each checkbox...
I've tried with something like markup injections using parameter "after[string]" but it works only for the last
checkbox of the list (or the first if i used 'before' parameter)...

Any suggestion ?

Thanks a lot in advance

fabio

Guest's picture

Thanks, this was exactly what I was looking for!

Guest's picture

I've had real problems with how to pick up data and get it saved properly and they really should do something about it in the cookbook. This has got be up to speed. Many humble thanks.

This is pretty much the best HABTM tutorial I've ever seen. Thank you for posting it. I'll be referring back to it frequently.

Guest's picture

Hi there....
My appologies, I realized that the $form->value question was already posted. I got it now, thanks for the reply on Jeff's comment.

Anyway, I have another question ... is there a way for only saving the HABTM and not the hole entity (in this case, the post) . A quick and ugly way is to always update with the same info (disabled form input or whatever...) .
What I'm looking for is something like

$this->Post->Tag->save($this->data[Tag])

Thanks

Guest's picture

Hi there.
First of all, thanks for this straight forward example, I'm kinda new to cakephp and still trying to get it's ways :D.
This post is one of the clearest applications of HABTM I've stumbled upon. There is one thing I'm not getting though...
When we use

$form->value('Tag.Tag')

the form helper is getting the value for the "tag" element on the "tag" form, right?.... so when cake outputs the view knows wich checkboxes must be checked (the ones saved on the HABTM relation)
How is the form helper doing this, or in other words.....where is he getting the info? if I do a var_dump() on the $tags array it only contains the name of the tags....
I can see that cake is actually making the correct query (joining the tables in the HABTM relation and returning the correct affected rows) ... but I don't get where both things connect....or how..

I'm trying to use this on a model of my own and can't get it to select the checkboxes....
Hope this is clear, my English is a little bit rusty these days...
thanks in advance!

Guest's picture

the current selected options come from:

$this->data, which is initially set here:
$this->data = $this->Post->read(null, $id);

but then after a submission it uses the posted data.

the form helper gets this data here:

echo $form->input('Tag',array(
'selected' => $html->value('Tag.Tag'),
));

brett's picture

Hi,
the example "HABTM Text Add" doesn't function! If you insert duplicate tags, you get following error:

Warning (512): SQL Error: 1062: Duplicate entry '1-1' for key 'PRIMARY' [CORE\cake\libs\model\datasources\dbo_source.php, line 525]

Code | Context

$sql = "INSERT INTO `posts_to_tags` (`post_id`,`tag_id`) VALUES (1,'1'), (1,'2'), (1,'3')"
$error = "1062: Duplicate entry '1-1' for key 'PRIMARY'"
$out = null

Query: INSERT INTO `posts_to_tags` (`post_id`,`tag_id`) VALUES (1,'1'), (1,'2'), (1,'3')

Guest's picture

thanks for pointing this out.

does it work if you remove this:

if ($tag) {
// use current tag
$this->data['Tag']['Tag'][$tag['Tag']['id']] = $tag['Tag']['id'];
}

brett's picture

No, if you try to add a duplicate tag then it does:

INSERT INTO `post_to_tags` (`tag_id`) VALUES (0)

so the next time you try it you have duplicate primary key problems. I don't know why it does that and I'm new to cake and find debugging it very difficult!

Guest's picture

what do you have inside $this->data just before the $this->Post->save() ?

brett's picture

Hi,
I'm searching a while for a good habtm - tutorial and only find 0815-examples. This ist the best tutorial about habtm that i have seen. Thank you man!

Guest's picture

Thanks for the code its a great help. Just had a question: In my application I also want to store the userid field. So essentially its multiple HABTM (Pages, Tags and Users)...the join table pages_tags has all three ids (page_id, tag_id, user_id, value1, value2..). However, when I place your code in the Add Page, it only saves the page_id and tag_id, not the user_id, value1, value2...(Primary key: (tag_id, page_id)) I've tried searching around and there seem to be some solutions but since I'm new to cakephp I haven't been able to get any of them working.

It would be neat if you could write an article about saving an extra field (User) in a Post-Tag HABTM.
thanks

You can leave your HABTM in place, but you also need to add some more relationships.

Page HasMany PageTag
Tag HasMany PageTag

Then you can do $this->Page->PageTag->save(data).

Hope this helps.

brett's picture

I was having trouble getting the checkboxes to be selected when the edit page loaded. I added the 'selected' attribute and it seemed to work well. I don't know how it works though... where does $form->value() come from? It's not in the manual or api.


echo $form->input('Tag',array(
'label' => 'Tags',
'type' => 'select',
'multiple' => 'checkbox',
'options' => $investments,
'selected' => $form->value('Tag.Tag')
)
);

Guest's picture

$form->value() gets its original data from the Controller->data[]

I think the issue you pointed out has something to do with naming the input "Tag" instead of "Tag.Tag". This was done to prevent the input from displaying as a select input.

brett's picture

Hi i'm trying your habtm-textfield example (the third), and when i use this code, all i get is a selectbox with all the tags (which i don't want), which is odd, because i explicitly stated it to be a 'text'. Any suggestions?

//the view
echo $form->create('Link');
echo $form->input('Tag.tags',array(
'type' => 'text',
'label' => __('Add Tags ', true),
'class' => "vlas",
//'after' => __('Seperate each tag with a comma. Eg: family, sports, icecream',true)
));

//in the controller
var $uses = array('Tag', 'Flashfile');
//--
$this->set("tags", $this->Link->Tag->find('list'));
//--

Guest's picture

I think you have to remove this from the controller:
$this->set("tags", $this->Link->Tag->find('list'));

Let me know how you go.

brett's picture

i wonder which line of the code that save the joinTable? in this case "posts_to_tags"

does it automatically update the joinTable?

or should i add the relationship manually with $this->ModelName->query()

thx

Guest's picture

By default cake will update the relationship table when you save. So the line would be:
$this->Post->save($this->data);

brett's picture

Thanks for the code its a great help. Just had a question: In my application I also want to store the userid field. So essentially its multiple HABTM (Pages, Tags and Users)...the join table pages_tags has all three ids (page_id, tag_id, user_id). However, when I place your code in the Add Page, it only saves the page_id and tag_id, not the user_id. I've tried searching around and there seem to be some solutions but since I'm new to cakephp I haven't been able to get any of them working.

It would be neat if you could write an article about saving an extra field (User) in a Post-Tag HABTM.

Guest's picture

Hello Fahd,

This is more of a simple example than a detailed guide to building an application.

It sounds like you need more associations, so just add extra HABTM associations and then make sure you output a $form->input for each relationship you want to update with the form.

If you want to prevent HABTM data from being deleted if it is not set in the form, you need something like this in your controller:

$this->Post->hasAndBelongsToMany['User']['unique'] = false; // prevent users from being unlinked from posts on save

or something like this in your model:

var $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'post_id',
'associationForeignKey' => 'user_id',
'unique' => false, // prevent users from being unlinked from posts on save
),
);

brett's picture

Thanks!

I'm using CakePHP 1.2 .

I was using the following in a similar form:

<?php echo $form->input('Foo',
array('label'=>'Foo,
'type'=>'select',
'multiple'=>'checkbox',
'options'=>$foo)); ?>

With this I didn't need the foreach in the form:

$checked = $form->value('Tag.Tag');
foreach ($tags as $id=>$label) {
echo $form->input("Tag.checkbox.$id", array(
'label'=>$label,
'type'=>'checkbox',
'checked'=>(isset($checked[$id])?'checked':false),
));

Nor did I need the foreach in the controller:

// get the tags from the checkbox data
$this->data['Tag']['Tag'] = array();
foreach($this->data['Tag']['checkbox'] as $k=>$v) {
if ($v) $this->data['Tag']['Tag'][] = $k;
}

However, Voila the list was displayed just fine and I could update the HABTM table just fine.

But ...

While what I hade created was fast it resisted customization for such things as displaying and updating in one form such things as:

Family / Parent / Children

Category / Subcategory

Interests / Skill Levels

Sometimes, we just have to do a little more coding.

Thanks for cataloguing this method so that I didn't have to redo the wheel.

Wayne

Guest's picture

thanks for the tip Wayne!

I had seen it used somewhere before but didn't look too closely before now. I have changed my demonstration to use the more "cakey" method, but left mine in there incase anyone wants to output singular checkboxes for additional control.

One thing I couldn't figure out, I want to be able to remove the lines from the controller required for the single checkbox. They are only there because I don't know how to draw the input.

EG:

// this will make select dropdowns, just because i changed the 1st argument from Tag.checkbox.$id to Tag.Tag.$id
// the same occurs for Tag.Tag and Tag.Tag.$i++
$checked = $form->value('Tag.Tag');
foreach ($tags as $id=>$label) {
echo $form->input("Tag.Tag.$id", array(
'label'=>$label,
'type'=>'checkbox',
'checked'=>(isset($checked[$id])?'checked':false),
));
}

brett's picture

But how to search for Page name and tags?

Guest's picture

For searches have a look here:
http://mrphp.com.au/node/1821

There is some code in the controller there called "filter by tag (habtm) - name or id". That should push you in the right direction.

brett's picture

i added some images so you can see how the form looks in each example

brett's picture

Hi, thk for share, but can I get table sample please?
excelf

Guest's picture

The table sample has been added. Its a very minimal example.

brett's picture

Feeling social? Share this page!