CakePHP1.3.6:HABTMの関係にあるデータを保存する

CakePHPのHABTM(hasAndBelongsTOMany)が面白いので興味本位に見てきたが、さて、データを登録するときにどうしたらいいのだろ、と思った。

これまで使ってきたItemとCategoryであれこれやってみた。
下のようなItem登録画面から、Categoryをマルチで選択して、登録する。このときに、ItemとCategoryの関係性(アソシエーション)も保存する。

結局、うまくいったのは、scaffoldでの登録画面のソースと、こちらの記事のおかげ。感謝です。

Itemをメンテナンスするscaffoldの画面ソースをみると、Category登録のselectタグのnameが

name=data["Category"]["Category"][]

となっていて、あれれと思った。
普通なら、data["Category"]["id"]とかになっていそう。

まず、ビュー(items/add.ctp)を以下のように書く。ここで、(a)をCategoryとだけ書くのがポイント。これで、name=data["Category"]["Category"]となる。(a)の部分を"Category.id"なんて書いてしまうと、name=data["Category"]["id"][]というHTMLが生成されて失敗する。

<h2>商品の登録</h2>
<?php 
echo $form->create(null,array('type'=>'post','action'=>'add'));
?>
<table>
<?php 
echo "<tr><th>商品名</th>";
echo "<td>{$form->text('Item.name',array('size'=>'20'))}{$form->error('Item.name')} </td>";
echo "</tr>";
echo "<tr><th>カテゴリー</th>";
echo "<td>{$form->select("Category", // ...(a)
		$cus['data'], 		 // array('id'=>'Customer.name')
		$cus['selected'],     // selected 
		array('multiple'=>true,'empty'=>false))}</td>";
echo "</tr>";
echo "<tr><th>メモ</th>";
echo "<td>{$form->textarea('Item.memo')}</td>";
echo "</tr>";
echo $form->end('登録');
?>

</table>
<a href=".">リストに戻る</a>

これができれば、あとは簡単。items_controller.phpのaddアクションは以下のようにすればよい。
selectボックスを選択すれば、Item登録時にCategoryとのアソシエーションが登録され、選択しなければ、アソシエーションは(当たり前だけど)保存されない。
ここで、selectボックスの値をセットするために、初めてfind('list')を使ってみた。(b)のようにかけば、idをキーにするnameのリストが取得できる。

	/**
	 * 
	 * データの追加
	 * 
	 */
	function add(){
		$this->set('title_for_layout', "商品の登録");
		if(!empty($this->data)){
			// サニタイズ
			$this->data["Item"] 	= MyConverter::getRequestParams($this->data["Item"]);
			$this->data["Category"]["Category"] 
				= MyConverter::getRequestParams($this->data["Category"]["Category"]);
			
			// 登録
			if($this->Item->saveAll($this->data)){
				// 登録できたらリダイレクト
				$this->redirect('.');
			}else{
				$this->Session->setFlash('データの保存に失敗しました');
			}
		}
		// カテゴリーリストの作成; array('id'=>'name')の作成
		$category = $this->Category->find('list',array('fields'=>array('id','name'))); // ... (b)

		// selectボックス用データの生成
		$ret = array('data'=>$category,'selected'=>null);
		$this->set('cus',$ret);
	}