データベース

記事のデータを入れる「Posts」、タグ(カテゴリー)データを入れる「Tags」、関連付け用の「PostsTags」があります。

Posts

id bigint(20)
name varchar(100)

Tags

id bigint(20)
name varchar(100)

PostsTags

post_id bigint(20)
tag_id varchar(100)

最低限こんなとこでしょうか。

Model

hasAndBelongsToMany(HABTM)はpostに設定します。

models > post.php

  1. class Post extends AppModel {
  2. public $name = 'Post';
  3. public $hasAndBelongsToMany = array(
  4. 'Tag' => array(
  5. 'className' => 'Tag',
  6. 'joinTable' => 'posts_tags',
  7. 'foreignKey' => 'post_id',
  8. 'associationForeignKey' => 'tag_id',
  9. 'fields' => array('id','name'),
  10. 'unique' => true
  11. ),
  12. );
  13. }

models > tag.php

  1. class Tag extends AppModel {
  2. public $name = 'Tag';
  3. }

models > posts_tag.php

  1. class PostsTag extends AppModel {
  2. public $name = 'PostsTag';
  3. }

Controler

controllers > posts_controller.php

  1. class PostsController extends AppController {
  2. public $name = "posts";
  3. public $uses = array("Post", "Tag", "PostsTag");
  4. /* レコードの追加
  5. ============================================== */
  6. function add() {
  7. if (!empty($this->data)) {
  8. $this->Post->save($this->data);
  9. }
  10. //Tagデータを渡す
  11. $tagData = $this->Tag->find('list');
  12. $this->set('tagData', $tagData);
  13. }
  14. }

チェックボックで配列になってるからうーん、、、とか深く考えないで「save($this->data)」だけでCakePHPが勝手に処理してくれるっぽいです。

View

views > posts > add.php

  1. echo $form->create('Post', array('type' => 'post'));
  2. echo $form->input('Tag', array(
  3. 'type'=>'select',
  4. 'multiple' => 'checkbox',
  5. 'options' => $tagData,
  6. 'label' => 'タグ));
  7. echo $form->end('投稿');

フォームヘルパーにはチェックボックス用の「$form->checkbox」もありますが、配列から一気に作りたいときは「$form->input」を使います。
「options」にコントローラーから受け取った「tagData」を入れます。

データ更新(アップデータ)

次にすでに登録してあるデータの更新(アップデータ)です。

controllers > posts_controller.php

  1. function admin_update($id = null) {
  2. $this->Post->id = $id;
  3. if (empty($this->data)) {
  4. $this->data = $this->Post->read();
  5. $this->set('result', $this->data);
  6. //Tagを渡す
  7. $tagData = $this->Tag->find('list');
  8. $this->set('tagData', $tagData);
  9. }
  10. elseif (!empty($this->data)) {
  11. $this->Post->save($this->data);
  12. }
  13. }

コントローラーは特に特別なことないですね。

views > posts > update.php

  1. echo $form->create(null, array('type' => 'post', 'action' => './update'));
  2. echo $form->input('Tag', array(
  3. 'type'=>'select',
  4. 'multiple' => 'checkbox',
  5. 'options' => $tagData,
  6. 'label' => 'タグ'));
  7. echo $form->end('投稿');

ビューはPostsTagsで関連してるところはselectedでチェックして、、、とか深く考える必要ありませんでした。
新規追加(add.php)と同じで、関連付けされているタグには勝手にチェックされて表示してくれます。

チェックボックスのバリデーション

最後にチェックボックスのバリデーションを行います。

postモデルに以下を追加します。

models > post.php

  1. public $validate = array(
  2. 'Tag' => array(
  3. 'multiple' => array(
  4. //'rule' => array('multiple',array('min' => 1, 'max' => 2)),
  5. 'rule' => array('multiple',array('min' => 1)),
  6. 'message' => '1つ以上選択してください。'
  7. ),
  8. )
  9. );
  10. function beforeValidate() {
  11. foreach($this->hasAndBelongsToMany as $k=>$v) {
  12. if(isset($this->data[$k][$k])) {
  13. $this->data[$this->alias][$k] = $this->data[$k][$k];
  14. }
  15. }
  16. return true;
  17. }
引用元:HABTM form validation in CakePHP

コントローラーです。
何もしなかったらチェックボックのエラーが表示できなかったので、わざわざメッセージを取得しています。

controllers > posts_controller.php

  1. $this->Post->save($this->data);
  2. if ($this->Post->validates()) {
  3. $this->redirect('/posts/');
  4. } else {
  5. $this->set('result', $this->data["Post"]);
  6. //エラーメッセージを取得
  7. $errors = $this->Post->invalidFields();
  8. if(!empty ($errors['Tag'])) {
  9. $this->set('tagerror', $errors['Tag']);
  10. }
  11. }
  12. }

Viewのチェックボックの取得したエラーメッセージをチェックボックスの下に表示させています。

views > posts > add.php

  1. echo $form->input('Tag', array('type'=>'select','multiple' => 'checkbox', 'options' => $tagData,'label' => 'カテゴリー'));
  2. //タグエラーがあったら表示
  3. if(!empty ($tagerror)) {
  4. echo '<div class="error-message">';
  5. print_r($tagerror);
  6. echo '</div>';
  7. }

これで一応1つも選択されてなかったときにエラー表示されます。
もっと上手いやり方があると思いますが僕のスキルではこの程度でした。