CakePHP1.3 saveAllの複数レコード保存と複数モデルの保存の挙動についての注意

CakePHPの動作が難解なのでめも。

1.同一モデルの複数レコードの保存
※insertしたいのでidは指定しない
$data = array(
  'Article' => array(
    '0' => array(
        'name' => 'a',
        'price' => 1000),
    '1' => array(
        'name' => 'b',
        'price' => 5000)));

$this->Article->saveAll($data);

2.単一レコードに結びつく複数モデルの保存
Categoryに結びつくArticleを作成
$data = array(
  'Category' => array(
    'id' => 1),
  'Article' => array(
    '0' => array(
      'name' => 'a',
      'price' => 1000),
    '1' => array(
      'name' => 'b',
      'price' => 5000)));
$this->Article->saveAll($data);

ここで一つ問題が発生
Articleモデルのarticle.phpのvalidateに下記のような記述をした。

$validate = array( 
   'category_id' => array(
        'notempty' => array(
           'rule' => array('notempty')
         ),
      ),

saveAllは第二引数のオプションに何もしないと、一度すべてのデータに対してのvalidateを行ってから保存処理を行うが、validate処理時にまだArticle.category_idが割り当てられていないためにValidationエラーが発生する。なので下記のように設定してみる。

$this->Article->saveAll($data, array('validate' => true));

validateのタイミングが各レコードの更新直前に変わり、category_idが割り当てられた上でvalidateされるのでvalidateエラーが発生しない。ただし、レコードを更新しながらvalidateを行うので途中で何らかのvalidateエラーが発生した場合は直前まで保存したレコードにロールバック処理が発生する。大量に更新するのであれば自分で事前にcategory_idを割り当てておくべきかもしれない。

もう一点注意が必要な挙動を発見した。
saveAllで'validate' => trueを設定しているとvalidateでエラーが発生してもなぜかsaveAllが真値を返してしまう。つまり下記の処理は
validateエラーが発生しても必ずtrueを返してしまう。

if($this->Article->saveAll($data, array('validate' => true))) {
   return true;
} else {
   return false;
}

validateErrorsにはエラーメッセージが格納されるので下記のような処理にするといいかもしれない。
if (!empty($this->Article->validationErrors)
  && $this->Article->saveAll($data, array('validate' => true))) {
   return true;
} else {
   return false;
}

Trackback URL for this post:

http://www.mrk.jp/trackback/604

コメント

はじめまして、Google検索結果から飛んできました! 「

はじめまして、Google検索結果から飛んできました!

「1.同一モデルの複数レコードの保存」ですが、

$this->Article->saveAll($data);

ではなく、

$this->Article->saveAll($data['Article']);

ではないでしょうか?

僕のほうでも少しハマってしまったのですが、調べてみると後者のようにしないと複数レコードを一括保存できませんでした。
参考にしていただければ幸いです!

遅くなりました。 コメントありがとうございます。 ここ最近

遅くなりました。
コメントありがとうございます。

ここ最近プログラムから離れてしまっていて、もう忘れてしまっていました。。。
今度開発するとき参考にさせていただきます。

ですよねー cookbookのsaveAllの項目にはAr

ですよねー
cookbookのsaveAllの項目にはArticleを含む連想配列を第1引数に渡すような例が書かれていますが、
実際には、本文中にあるように
> 単一のモデルに複数のレコードを保存するためには、$data は整数のインデックスがついた配列である必要があります。
としないと更新してくれないですねぇ。

新しいコメントの投稿

このフィールドの内容は非公開にされ、公表されることはありません。
  • ウェブページアドレスとメールアドレスは、自動的にハイパーリンクに変換されます。
  • 使用できるHTMLタグ: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • 行と段落は自動的に折り返されます。

書式オプションに関するより詳しい情報...