フォームヘルパーのチェックボックスメソッドを使うと、言うまでもなくチェックボックスをページ内に設置することができる。
cakeのヘルパーは何かと便利で、余計なことをしなければ勝手に値を保持してくれたり自動的にhidden要素を作ってくれたりするのだけど、この自動的にhidden要素を作ってくれるおかげで、新規登録のときは問題なくても、編集のときにうまいことアップデートが行われなくてちょっと困った。
SQL文を見ても、編集画面でチェックボックスの欄に何の手も加えないでアップデートを行った場合、一度DELETEを実行して、全く同じ値をINSERTしているような結果になっていた。一意な値であるidだけが編集のたびにインクリメントされていく感じ。
例えばHABTMでProgramとCategoryというテーブルが結びついていたとして、一つのプログラムに対しいくつかのカテゴリをチェックボックスにチェックを入れて登録するようなサイトがあったとする。
HABTM用のテーブル(CategoriesProgram)に、idの他にprogram_idとcategory_idの二つしかない場合なら、正直DELETEとINSERTを繰り返すのでもたいして問題はない。ただ、もしもそれ以外のカラムがあった場合、そしてそれは登録画面や編集画面から入力する要素ではなかった場合、UPDATEじゃないと値がクリアされてしまう。
具体的なことを言うと、今回の僕はカテゴリごとにプログラムの並び順を指定するsortっていうカラムをCategoriesProgramテーブルに足しておいたのだけど、編集を行うと常にこのsortがデフォルト値である0になってしまうから、都合が悪いなぁというお話。livedoorブログなんかでもサイドバーに表示する項目の並び順を自分で指定したりすることができるのだけど、イメージとしてはあんな感じ。
通常は、編集画面などではhidden要素でidの値を渡してやったりすればUPDATEが行われるのだけど、チェックボックスに関してはなぜかこれがうまくいかなくて、まあ僕の書き方が間違っていただけかもしれないけど、とりあえず僕の中ではUPDATEはできねえっていう結論に達したので、少々回りくどい方法を取った。
// CategoriesProgramテーブルからprogram_idが$idの値であるものを全部取ってくる。
$param = array('conditions' => array('program_id' => $id));
$categories = $this->CategoriesProgram->find('all', $param);
// データをいったんunsetする。
($this->data['Category']['Category']には全チェックボックスの値が配列で入っている)
$data = $this->data['Category']['Category'];
unset($this->data['Category']['Category']);
// すでにデータがあるものは入力しない
foreach($data as $val) {
$flg = '';
if($val != 0) {
foreach($categories as $category) {
if($category['CategoriesProgram']['category_id'] == $val) {
$flg = true;
}
}
if(!flg) {
$this->data['Category']['Category'][] = $val;
}
}
}
いきなりここだけ書いても分かりづらいかもしれないけど、要はデータを登録する前に送られてきたデータを一度unsetして、入力したいデータだけを再度$this->data[‘Category’][‘Category’]に入れ直しているわけです。foreach文の中でやっているのは、DBの中にあるデータと入力フォームから送られてきたデータを比較して、同じだったら$this->dataには値を入れないようにしているということ。UPDATEがうまくできないのなら、いっそのこと何もするなよ的なことです。新しいデータに関してだけINSERTを行っておくれよってことですね。
これの他に、チェックのついていたものが外された場合に、DBからその値をDELETEするプログラムも書いておく必要があるけど、それはここでは省略。
しかし、他のフォームは普通にUPDATEができるのにチェックボックスだけできないってこともないと思うので、実際はこんなことをやらなくてもいいような気はするんですが……何がいけなかったのかな?
LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。