CakePHPの入力欄が自動でカラムに紐づかない時に疑うこと
Formヘルパーで出力するフォーム系のinputやらselectやらtextareaやらの入力欄。 規定ではデータベースのカラムの型やカラム名に応じた形で自動的に出力されるけど、うまいこと設定されない場合は全部input type="text"で出力される。 何が原因でうまいこと設定されていないのか、疑うべきチェックポイント。
エンティティーを渡し(せ)ていない
アソシエーションが正しくない
この2点を疑ってみて。
エンティティーを渡し(せ)ていない
CakePHP2を使ったことがある場合に1回くらい引っかかるかもしれない問題。
CakePHP2の場合、
<?=$this->Form->create('User')?>
のように、テーブル名を渡してフォームを開始していた。 でもCakePHP3では、エンティティーを渡すことになっている。
<?=this->Form->create($user)?>
もちろん、その前にコントローラー側でビューに渡す変数としてエンティティーを用意しなければいけない。
// リクエストデータからユーザーエンティティーを作成 $user = $this->Users->newEntity ( $this->request->data ); // ユーザーエンティティーをビューに渡す $this->set('user', $user);
リクエストデータ?なにそれ。 例えば、ユーザーが全ての入力を完了して送信ボタンを押したけど、サーバー側でバリデーションをした結果入力エラーとなったため、エラーメッセージを出して再入力を促す場合。 いちいちまっさらなエンティティーでフォームを表示するのは不親切なので、入力内容はそのままお返しするから必要なところだけ直してね、とする。 初回の処理でリクエストデータがなければ無視されるので安心。
アソシエーションが正しくない
今回の例でいうところの、ユーザーテーブル自体に存在するカラムを編集するinputの場合はいいけど、そのレコードに紐づく別のテーブルのデータを入力する場合。
テーブルクラスでアソシエーションを定義する。
アソシエーションを含めたエンティティーを生成する。
フォームヘルパーに正しく関連レコードを指定する。
という点を確認。
1. テーブルクラスでアソシエーションを定義する。
CakePHPのアソシエーションの概念についてはCakePHP 2のCakebookで丁寧な説明が読める。 http://book.cakephp.org/2.0/ja/models/associations-linking-models-together.html
CakePHP 3での書き方についてはここで。まだ英語版しかないけど、上を読んだ後なら本文飛ばしてサンプルコードだけ読めばOK。 http://book.cakephp.org/3.0/en/orm/associations.html
一点、hasAndBelongsToMany(HABTM) が belongsToMany と呼び名が変わった。端的でいいよね。
深追いすると趣旨がブレるので参考文献の紹介程度にしておく。
2. アソシエーションを含めたエンティティーを生成する。
エンティティー生成の際、関連テーブルもエンティティーに含めたネストされたエンティティーを生成する。
// リクエストデータからユーザーエンティティーを作成 $user = $this->Users->newEntity ( $this->request->data, [ 'contain' => 'Avatars' ]);
こんな感じで、例えばUser has one Avatarなエンティティーを生成。
アバターのさらにその先に別のテーブルを持つ場合はこう。
// リクエストデータからユーザーエンティティーを作成 $user = $this->Users->newEntity ( $this->request->data,[ 'contain' => [ 'Avatars', 'Avatars.Tags' ] ]);
Avatar belongs to many Tagsな想定で。ここはアソシエーションの種類が変わっても特に書き方に差はない。 ちょっとうまいこと架空のアソシエーションが思い浮かばなくてよく分からないサンプルになってるけどお許し。
余談 ちなみに'Avatars.Tags'だけでもちゃんとAvatarsとTagsを含めてくれる。個人的に階段状に書いていくのが整理されていて見やすい。
階段 A A.B A.B.C A.D A.D.E
本当は A.B.C A.D.E だけでも動くけど、Aを2回書いている時点で1回しか書かないことを徹底できないくらいなら最初からやりたくない。
3. フォームヘルパーに正しく関連レコードを指定する。
<?=$this->Form->input('-この部分-')?>
の指定方法。
まず、ユーザーテーブル (createメソッドに渡したエンティティー自体) のカラムの場合、何も工夫せずにカラム名をドン。
<?=$this->Form->input('name')?>
次にhasOneまたはbelongsToなテーブルのカラムの場合。 アソシエートされたエンティティーは、親エンティティーに対して小文字表記のプロパティー名で追加されるので、inputに渡す際もそれに従う。hasOneまたはbelongsToの場合は小文字表記に加えて単数形となる。 (表記はアソシエーション設定時に任意の名称に変更可能。)
<?=$this->Form->input('avatar.title')?>
アバターにタイトルなんかつけるかよ。
次が迷いがち。 hasManyまたはbelongsToManyなテーブルのカラムの場合、複数形の小文字表記に加えて、インデックスを指定してからカラム名をドン。
<?=$this->Form->input('avatar.tags.0.name')?>
アバターに紐づく複数のタグのうち、0番目のレコードのnameカラムですよ、と読む。 アバターにタグなんかつけるかよ。 0番目というのは本当にデータベース全体の話ではなく、今画面上で編集中のレコードのうち0番目。すでにひとつタグがついているアバターに対して、新規に0番目を編集すれば2つのタグができるし、エンティティー生成時にすでにあるタグをfindしてからエンティティーを作った場合は0番目に既存のタグの名前が表示され編集できる。 (その場合はふつうforeachとかで既存のタグ数分ループして複数の入力欄を出すのだろう。)















