Use case: We have two tables: Preferences and Countries. While editing preferences user should be able to select multiple countries and save the selection.


Let’s start with database, here is the SQL script to store preferences, countries and many-to-many relations between them:

CREATE TABLE `countries` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `unique_name` (`name`)
);
CREATE TABLE `preferences` (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  PRIMARY KEY  (`id`)
) ;
CREATE TABLE `preferences_countries` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `preference_id` int(11) DEFAULT NULL,
  `country_id` int(11) DEFAULT NULL,
  PRIMARY KEY  (`id`)
);

There are no tricks with model creation so we can use the ‘cake bake’ to create our Preference class that will look like this /app/models/preference.php:

<?php
class Preference extends AppModel {
 
var $name = 'Preference';
var $useTable = 'preferences';
var $actsAs   = array('extendAssociations'); 
 
var $hasAndBelongsToMany = array(
		'Country' => array('className' => 'Country',
			'joinTable' => 'preferences_countries',
			'foreignKey' => 'preference_id',
			'associationForeignKey' => 'country_id',
			'unique' => true,
		)
);
 
}
?>

Note, the extendAssociations behaviour is used, you can download it from here (1) and place in to /app/models/behaviors. Next we have to add action to the controller to read and save our associations, therefore we will place the all-in-one edit method in to our /app/controllers/preference_controller.php:

function edit($id = null) {
	if (!empty($this->data)) { //post
		if (!$id) { //create
			$this->Preference->create();
		}
		if ($this->Preference->save($this->data)) {
 
			$this->Preference->habtmDeleteAll('Country', $this->Preference->id); 
			$this->Preference->habtmAdd('Country', $this->Preference->id, 
				$this->data['Preference']['country']); 
 
			$this->Session->setFlash(__('-controllers-preferences-edit-success', true));
			$this->redirect(array('action'=>'index')); //success
		}
		else {
			$this->Session->setFlash(__('-controllers-preferences-edit-failed', true));
		}
	} else { //get
		$this->data = $this->Preference->find();
	}
 
	$preferenceCountry = $this->getSelectedItems($this->data['Country']);
	$this->set(compact('industries','positions','countries', 'preferenceCountry'));
}
 
function getSelectedItems($data)
{
	$return = array();
	foreach ($data as $row) {
		$return[$row['name']] = $row['id'];
	}
	return $return;
}

Note, we have modified the getSelectedItems function to fit Cake 1.2 expecatations. For Cake 1.1 the code was (2):

$return[$row['id']] = $row['name'];

Finally the last part is to place select box in to the view, here is the code:

debug ($preferenceCountry);
echo $form->input('country', array (
			'type' => 'select', 'multiple' => 'true',
			'selected' => $preferenceCountry,
			'label' => __('-models-skill-country', true), 
		)
	);

That’s it. Now you should be able to see list of countries at the /preferences/edit url, select multiple countries and save your selections in to the database. Happy baking! ;)

Refferences:

1. HABTM Add & Delete Behavior
2. Editing hasAndBelongsToMany (HABTM) Relationships in CakePHP

Posted by Rostislav Palivoda, filed under PHP. Date: April 9, 2008, 10:56 am |

3 Responses

  1. neltron Says:

    hello!
    i have problems with redirect function, i got this message:

    Warning (2): Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\test_music\models\behaviors\extend_associations.php:1)

    I use the “HABTM Add & Delete Behavior” of the refferences.

    thanks for your help

  2. Rostislav Palivoda Says:

    Well, this error message usually is a result of html output call after the response stream is closed. You can comment code out line by line while your controller method will not stop to produce this error message. Buy the way, try to Google this error message to find more about this problem. Hope this helps.

  3. Maciek Says:

    Here is better solution:

    http://mrphp.com.au/code/code-category/cakephp/cakephp-1-2/working-habtm-form-data-cakephp

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.