CakePHPを使って開発してると、何かとバリデーションのお世話になると思うんです。
僕もようやく最近はbehaviorとかいうやつの存在を理解し始めたので、独自のバリデーションルールをライブラリ化とかしたりしてるんですけど、まあそれは今回は関係なくて、デフォルトのバリデーションルールの中に、日付の形式をチェックしてくれる「date」ってバリデーション関数があるんですよ。
で、こいつが上手く動かなかったんですよ。
CakePHPのフォームヘルパーを使って、YYYY-MM-DDの日付けをデータとして送信するフォームを作ったんですけど、なぜかバリデーションに引っかかるんですよ。
ざっくり書くと、こんな感じのをモデルとビューに作りました。
こんな感じ。
一応これで正しく動作するはずなんですが、どうしても動かなかった。
で、実際にバリデーションを行ってるところでどんなデータが飛んできてるのかってのを検証してみたんですが、その結果が↓これ。
dateのバリデーションは年月日までしかチェックしてくれないので、早い話が年月日の後ろに時分秒の値がどんな形であれ入ってると、正規表現的にアウトなんですね。
だから要は上のデータが「2011-07-06」ってなればいいわけなんですけど、この辺りはCakeのモデルさんが気を利かせて勝手に変換してるらしくて、僕自身は特に何もしてない。
本来なら上記のビューみたいな書き方をすると、飛んで来る値は配列なんですよ。
みたいなね。でもバリデーション前にこの配列を自動で変換してくれるみたいで、それ自体はありがたいことなんですけど、なぜか余計な「00:00:00」までつけ足してくれちゃう始末。
でもね、ちゃんと動く場合もあるんですよ。時分秒をつけないで、普通に年月日だけ変換してくれた場合も、かつてあったんですよ。
どうしてそうなったりならなかったりするのかが全然分からなくて、Cakeのバージョンの違いなのかな~とか思ったんですけど、どうやらこれはデータベースの構造が関係しているらしいです。
データベースで該当のカラムを、上記の場合だと「date」ですね、そのカラムの種別をDATE型にするかDATETIME型にするかってのが、今回の分かれ目だったようです。
種別をDATE型にしておくと、Cakeのモデルが年月日の形に、「2011-07-06」みたいな形に自動変換してくれる。一方、DATETIME型にしておくと、Cakeのモデルが「2011-07-06 00:00:00」という、まさにDATETIMEの形に自動変換してくれるようなんです。
いやぁ、まさかデータベースの型によってCake側が受け渡すデータの形を変えるとかあまり思ってなかったんで、全然気づきませんでした。
まあでも考えてみたら、こっちから「2011-07-06」ってデータを渡して、それをDATETIME型のカラムにINSERTするとなったら、INSERT前にどっかのタイミングでデータの形を「2011-07-06 00:00:00」とかにしなきゃいけないもんね。それくらいのことはやってて当然か。
知ってしまえばたいして難しくも何ともない問題なんですけど、まだまだこーゆーちょっとしたことに足を掬われることが多いっすなぁ。
僕もようやく最近はbehaviorとかいうやつの存在を理解し始めたので、独自のバリデーションルールをライブラリ化とかしたりしてるんですけど、まあそれは今回は関係なくて、デフォルトのバリデーションルールの中に、日付の形式をチェックしてくれる「date」ってバリデーション関数があるんですよ。
で、こいつが上手く動かなかったんですよ。
CakePHPのフォームヘルパーを使って、YYYY-MM-DDの日付けをデータとして送信するフォームを作ったんですけど、なぜかバリデーションに引っかかるんですよ。
ざっくり書くと、こんな感じのをモデルとビューに作りました。
//ビュー
<?php echo $form->year('date' , date('Y') , date('Y')+1) ?>年
<?php echo $form->month('date' ,null, array('monthNames' => false)) ?>月
<?php echo $form->day('date') ?>日
//モデル
$validate = array(
'date' => array(
'rule' => 'date',
'message' => '日付けの入力が不正です。',
),
);
こんな感じ。
一応これで正しく動作するはずなんですが、どうしても動かなかった。
で、実際にバリデーションを行ってるところでどんなデータが飛んできてるのかってのを検証してみたんですが、その結果が↓これ。
2011-07-06 00:00:00
dateのバリデーションは年月日までしかチェックしてくれないので、早い話が年月日の後ろに時分秒の値がどんな形であれ入ってると、正規表現的にアウトなんですね。
だから要は上のデータが「2011-07-06」ってなればいいわけなんですけど、この辺りはCakeのモデルさんが気を利かせて勝手に変換してるらしくて、僕自身は特に何もしてない。
本来なら上記のビューみたいな書き方をすると、飛んで来る値は配列なんですよ。
//$this->dataの中身
array(
[date] => array(
[year] => 2011
[month] => 07
[day] => 06
)
)
みたいなね。でもバリデーション前にこの配列を自動で変換してくれるみたいで、それ自体はありがたいことなんですけど、なぜか余計な「00:00:00」までつけ足してくれちゃう始末。
でもね、ちゃんと動く場合もあるんですよ。時分秒をつけないで、普通に年月日だけ変換してくれた場合も、かつてあったんですよ。
どうしてそうなったりならなかったりするのかが全然分からなくて、Cakeのバージョンの違いなのかな~とか思ったんですけど、どうやらこれはデータベースの構造が関係しているらしいです。
データベースで該当のカラムを、上記の場合だと「date」ですね、そのカラムの種別をDATE型にするかDATETIME型にするかってのが、今回の分かれ目だったようです。
種別をDATE型にしておくと、Cakeのモデルが年月日の形に、「2011-07-06」みたいな形に自動変換してくれる。一方、DATETIME型にしておくと、Cakeのモデルが「2011-07-06 00:00:00」という、まさにDATETIMEの形に自動変換してくれるようなんです。
いやぁ、まさかデータベースの型によってCake側が受け渡すデータの形を変えるとかあまり思ってなかったんで、全然気づきませんでした。
まあでも考えてみたら、こっちから「2011-07-06」ってデータを渡して、それをDATETIME型のカラムにINSERTするとなったら、INSERT前にどっかのタイミングでデータの形を「2011-07-06 00:00:00」とかにしなきゃいけないもんね。それくらいのことはやってて当然か。
知ってしまえばたいして難しくも何ともない問題なんですけど、まだまだこーゆーちょっとしたことに足を掬われることが多いっすなぁ。