概要
いやー焦った。ほんとに焦った。
今日出社したらCakePHPで作った社内システムのデータが一部消えてたんですよ*1 !
考えられる原因はただ一つ。昨日みんなの仕事が終わった後に*2 CakeをRC4からstableに更新したのが原因だと思われます。
もしかしたら他にもこんな状況に陥る人がいるかもしれないからここにメモしておきますね。
あ?俺もなった?って人がいたらコメントくれると嬉しいです。
追記:原因が判明しました!
アソシエーションのconditionsを「array(“フィールド”=> “値”)」と書かなくてはならないところ「”フィールド = 値”」と書いていたのが原因でした。詳細は続きを読むでご参照ください。
問題
状況を詳しく説明するとこうです。
「案件モデル」からhasManyで「画像モデル」アソシエートしていて、
つまり案件に対して複数の画像が登録できるようにしているというわけですね。
そして、案件を削除したらその案件に紐付いた画像も一緒に削除したいので、アソシエーションにdependent => trueをセットしています。
今までは案件を削除したら、何の問題も無くその案件に紐付いた画像だけがちゃんと削除されていたんだけど、stableに更新したら案件の削除によってすべての画像が削除されてしまったというのが今回の問題。
「案件モデル」からは別のモデルもアソシエーションしてるんですが、問題が起こっているのは「画像モデル」だけ。
原因を調べてみると「画像モデル」へのアソシエーションだけ「conditions」が設定されていたんですよね。
「”画像モデル.use_flag = 1″」
今までの(RC4まで)CakeだとアソシエーションにセットしたconditionsはModel::findには影響してもModel::deleteには影響しなかったと思うのですよ。
というかそれが当たり前の挙動だと思ってたんだけど、stableにしたらもともとのアソシエーションを無視して、どうも「”画像モデル.use_flag” => “1”」この条件だけで削除してるっぽい。
とりあえずconditionsをコメントアウトして、システムはDBのバックアップから復元して何とかなってるんだけど、これ仕様ではないですよね?
なぜこんなことになるのかまだ原因は調べてないのですが、Model::_deleteDependentあたりが怪しいのかなぁ?と。
もしかして僕の書き方が間違っているのかもしれないから一応案件モデルのソースを貼っておきますね。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?PHP class Order extends AModel { var $name = 'Order' ; var $hasOne = array ( "Memo" => array ( "className" => "Memo" , "conditions" => "" , "order" => "" , "dependent" => true, "foreignKey" => "_order_id" ) ); var $hasMany = array ( "Mail" => array ( "className" => "Mail" , "conditions" => "" , "order" => "id DESC" , "dependent" => true, "foreignKey" => "_order_id" ), "Image" => array ( "className" => "Image" , /*"conditions" => "Image.use_flag = 1",*/ "order" => "Image._image_type_id ASC, Image.id ASC" , "dependent" => true, ), ); } ?> |
なにかお気づきの点などありましたらご指摘いただけると幸いです。
あとで前のバージョンのModelクラスとdiffとってみるので、またわかったことがあれば追記しますね。
追記1
/cake/lib/model/model.phpのdiffを見てみたけどまったく問題なかった。というより変更点はほとんど無いんだね。722行目のif文に条件が1つ追加されているだけだった。念のため追加された条件削っても全削除現象を確認できたからModelクラスは関係無いことが確認できました。
もしかして文字コードがらみで文字化けが起こってるとか凡ミスの気がしてきた…。引き続き調べたいと思います。
追記2
やっとわかった!!
アソシエーションのconditionsはarray(“Image.use_flag” => “1”)と書いてあげなくてはいけなかったんですね!ずっと配列で指定できないもんだと思ってました*3 。
_deleteDependentメソッドで、foreignKey = idとアソシエーションのconditionsをマージする
1 2 3 | if ( $data [ 'conditions' ]) { $conditions = array_merge ( $data [ 'conditions' ], $conditions ); } |
という部分があるんだけど、アソシエーションのconditions($data[‘conditions’]ね)が配列じゃないからarray_mergeでエラーが起こって$conditionsがnullになってたんだね。
だからforeignKeyもuse_flagも無視して全てのImageモデルのデータを削除しちゃったんだ。
いや?わかってよかった。みなさんもお気をつけください。