CakePHP2で入力項目の値を配列で取得すると、不思議な現象が起きて、僕が大切なことに気づいた(という無理やりな)話

日付などの入力内容を配列で受け取る

CakePHP2のFormHelperのdateメソッドを使うと、要素のname属性が
「data[モデル名][要素名][year]、data[モデル名][要素名][month]、data[モデル名][要素名][day]」になる。
この入力項目をPOSTで取得すると、コントローラで受け取ったとき、$this->dataには配列で格納され便利だ。
ただ、CakePHPが実装してくれているバリデーションルールは配列には対応していないため、
スムーズに入力チェックできない。

疑問

僕はこれがずっと気になっていて、何か方法があるんだろうと思っていたが、
方法が見つけられず、腑に落ちないまま、入力チェックする前に要素を連結するか、
配列に対応した入力チェックのルールを作成してやり過ごしていた。

不思議な現象との遭遇

しかし別の作業者からの相談で、不思議な現象があることを知った。
“配列が入ることを想定した入力チェック”が思った結果を返さないとのことで
確認したところ、入力チェックには連結済みの文字列が渡っていた。
特別連結処理を行っているようにも見えないため値をトレースしたところ、
アクション開始時の$this->dataには配列で格納されていた入力項目が、
モデルのsetメソッドで保持させたときに自動で連結されていた。

やはり、CakePHP2には、配列の入力項目を自動で連結する機能があったのだ。

明らかになった自動連結の条件

Model->set()にPOSTデータをセットするとき、以下の条件に合致すれば自動で連結される。
1.入力チェックに使用するモデルはテーブルと紐づいている必要あり。
2.対象の入力要素と同名のカラム名のカラムがテーブル上にある。
3.そのカラムの型が’datetime’, ‘timestamp’, ‘date’, ‘time’のどれかである。

今まで気づかなかった理由

僕は普段、機能レベルのモデルを作成し、そこでバリデーションルールを書いていて、
テーブルレベルのモデルは別に用意していた。
機能レベルのモデルはuseTable = falseにして使用していたので、
スキーマが取れず、入力項目の配列が自動で連結され文字列になることは無かった。

おしまい

僕は正直、今の時期にCakePHP2をいじることに、あんまり乗り気じゃなかった。
これまですでに結構触っているし、CakePHP3があるのに今さらやっても得るものはないと思っていた。けれど、今回些細だけど発見があった。そりゃそうだ。勝手に決めつけていただけで他にもあるはずだ。今回のことをきっかけに、前向きに仕事に取り組もうと気持ちを新たにした。えらい。はなまる。他の人も見習っていいよ。

以上

余談

ちなみに日付の構造を文字列に変換する仕組みは
Model::deconstruct()で、publicなので普段から呼び出せるものの、
schemaに依存しているのでそちらを何とかしないと使えなさそう。
http://book.cakephp.org/2.0/ja/models/model-attributes.html#schema