CakePHPで「create時は必須入力」「update時は任意入力」のvalidationをする

CakePHPでDBにデータを保存するときにはmodelの$validate変数を使ってバリデーションをすると思うのですが、
ちょっとやり方がわからなくてハマった所があったのでメモ。


前提

  • 簡単に話を進めるためにtitleとstatusというカラムをもつテーブルがあったと仮定する

やりたいこと

  1. 始めのinsert時にはtitleに入力がないとダメ
  2. statusはデフォルト値1を自動入れるのでinsert時に入力がなくてもOK
  3. insert時もupdate時もtitleは空文字入力禁止
  4. update時にstatusだけ更新したい

まず、やりたいことを実現するために「タイトルが空文字ではダメ」「タイトルは必須入力」という以下のルールを書きました。

    public $validate = array(
        'title' => array(
            'not_empty' => array(
                'rule' => 'notEmpty',
                'required' => true,
                'last' => true,
            ),
           // その他のルール ...
        ),
   );

これを書いたことにより、insert時にtitleがないとエラーになります。
ただ、このままだと、update時にstatusだけ更新したくて

$this->MyModel->save(array('status' => 1));

みたいに書いたとしても「titleがないから保存できないよ」ってエラーが出てしまい更新できません。




そこで、「じゃあcreate時だけrequiredになってくれればいいよ」と思い、以下のように'on' => 'create'を付けました。

    public $validate = array(
        'title' => array(
            'not_empty' => array(
                'rule' => 'notEmpty',
                'required' => true,
                'on' => 'create',
                'last' => true,
            ),
           // その他のルール ...
        ),
   );

この状態でさっきと同様にupdateしてみると「おぉ。上手くいく!」という感じで更新できました。
ただ、今度は下のようにupdate時にtitleを空文字で設定されるとそのまま更新されてしまいます。

$this->Review->save(array(
    'status' => 1,
    'title' => '',           // タイトルが空になっちゃう!!
));

titleが空文字で保存されてしまったら元も子もなく、
「あー、findでデータを持って来てDBにあるデータと同じ値を設定しようかなぁ」
と思ったのですが、それもイマイチだなぁと思い現段階のベター解が以下になりました。

    public $validate = array(
        'title' => array(
            'not_empty_create' => array(
                'rule' => 'notEmpty',
                'required' => true,
                'on' => 'create',
                'last' => true,
            ),
            'not_empty_update' => array(
                'rule' => 'notEmpty',
                'on' => 'update',
                'last' => true,
            ),
           // その他のルール ...
        ),
   );

'not_empty'というルールを'on'を使い、

  • insert時の'not_empty_create'

  • update時の'not_empty_update'

に分け、create時の時だけ'required' => trueにするという方法。
ちょっと冗長な感じですが、同じデータを更新するよりはいいかなぁと。



何か他にやりようがありそうな気もするんですけど、ググるキーワードが思いつかず断念しました。
とりあえず作業を続けます。
あと、MacBook Air 11インチ欲しい!