これは平成最後の月。
CakePHP2.x系。入力チェックが通らないたび、フォームの内容が編集前に戻ってしまう不具合を直したときの話。
単純にまず、DBがイケてなかったんです。
INT id
INT type
VARCHAR(255) value
どこからどう見てもEAV。Entity Attribute Value。
何故よくないかのDB設計理論的な難しい説明は置いとく。
DB構造はその時動かす権限がなかった。(もし権限があったらその根本原因から直してしまいたかった)
で、その不具合が発生している画面を見て。
・DBから持ってきたデータ構造
・フォームへ渡すときのデータ構造
・フォームの初期値を表示するとき
これらが全部バラバラで往生した…。
DBからとってきたときの配列:
[ 0=> ['Model'=> [id => 1, type => 1, value => 5]], 1=> ['Model'=> [id => 2, type => 2, value => "someaddress@example.com"]], 2=> ['Model'=> [id => 3, type => 2, value => "anotheraddress@example.com"]] ]
これを加工して,typeをキーにしてビューに渡すけれど:
[ 1=> [ 0=> ['id'=>1, 'value'=>5] ], 2=> [ 0=> ['id'=>2, 'value"=>"someaddress@example.com"], 1=> ['id'=>3, 'value'=>"anotheraddress@example.com"] ] ]
ビューでさらに取り出す:
(Formヘルパに’value’で渡している)
$this->Form->input('Model.type_1.value',['type'=>'text', 'value'=> $this->request->data[1][0]['value']); $this->Form->input('Model.type_2.0.value,['type'=>'text', 'value'=>$this->request->data[2][0]['value']]); $this->Form->input('Model.type_2.1.value,['type'=>'text', 'value'=>$this->request->data[2][1]['value']]);
(あと、idをそれぞれhiddenフォームで送っていたりする)
フォームを送信すると、入ってくるのは…
[ 'Model'=> [ 'type_1'=> ['id'=> 1, 'value'=>5], 'type_2'=> [ 0=> ['id'=> 2, 'value'=> 'someaddress@example.com], 1=> ['id'=> 3, 'value'=> 'anotheraddress@example.com]] ] ] ]
当然、DBからデータを取ってきたときとも最初フォームに渡したときとも違う構造。
このままではフォームの次の値が取れないから、前のコードではリクエスト関係なくDBからその都度データ読み込んで来ていた。
エラー値ならエラー値のままフォームに残しておく仕様なのに…。
とりあえず、その時はビューに渡すときの構造と受け取る時のデータ構造をそろえた。
(そうでないと変換が双方向に必要になるんで)
そろえれば使えなくはない。
Formヘルパに渡すvalue要素も要らなくなるし、入力チェックが通らないときフォームの初期値を作るためだけにDBを読みに行かなくていい。
でも、それでもやっぱりEAVはイケてない…。
この構造の時、まず絶対に1つしかないパラメータをこう…ひとつテーブルにして
INT model_id
INT type1_val
で、複数登録する必要がありそうな情報だけテーブルを分けてこう…。
INT model_mail_id
VARCHAR type2_mail
そしたら、DBからとってきた構造をパースしてフォームに渡す必要って本来それほどないはずなんです…。
僕がDB設計するときには、後輩に同じような愚痴を語らせないためにも、
あと、DB設計理論以上にそもそもコーディングがめちゃくちゃ往生するので、できることならEAVは避けていきたいという話でした。