save(), saveAll()の$fieldList設定
前日、関連モデルがある場合の$fieldListは、[テーブル名].[フィールド名]で設定と記載しましたが、むしろ間違いでした。
$fieldListの設定には、テーブル名を入れてはいけません。
以下、$fieldListチェックの動作検証です。
$fieldListチェックの解析
$fieldListチェックは、以下のsave()内で行われています。
cake/libs/model/model.php 1218行目
foreach ($v as $x => $y) { if ($this->hasField($x) && (empty($this->whitelist) || in_array($x, $this->whitelist))) { list($fields[], $values[]) = array($x, $y); } }
saveAll()も、内部でsave()を繰り返し実行なので$fieldListチェックは同じ箇所で行われています。
上記、$vは$this->data[Model]。
例えば Characterを保存する際には、こんなデータが入ってきます。
var_dump($v)
array(9) { ["public_flag"]=> string(6) "public" ["id"]=> string(1) "4" (中略) ["modified"]=> string(19) "2010-01-29 10:52:28" }
$xは$vのキーなので、出力するとこうなります。
string(11) "public_flag" string(2) "id" (中略) string(8) "modified"
一方$this->whitelistは、$fieldListの設定、プラスcreted/modifiedが入っています*1。
この条件で
$this->hasField($x)
$x=POSTのkeyと同名のfieldがテーブルに存在して、かつ
(empty($this->whitelist) ||
$fieldListの設定がない場合、あるいは
in_array($x, $this->whitelist))
$xが$this->whiteListに含まれている場合。
・・・3つめのロジックがポイントでした。
in_array("public_flag", array("public_flag", "id", "modified")) は trueですが、
in_array("public_flag", array("Character.public_flag", "Character.id", "modified")) は falseです。
と、言う事で前日の記載は誤りで、むしろ$fieldListの設定にテーブル名は入れてはいけないという結論に達しました。
動作確認時に誤認したものと思われます・・・・
saveAll()の場合の$fieldList
saveAllの場合、保存するモデルごとにsave()が発行されますが、
$fieldListは全て同じものを使っています。
なので、モデルAとモデルBを同時にsaveAllする場合は、両方の$fieldListをarray_mergeしてセットします。
ここで、疑問に思うのは
「AとBに同じfield名のカラムがあって、Aは更新OKだけどBは更新したくない」という場合。
・・・・field名が被らないように設計しましょう、と? ^^;
*1:$fieldListを設定しない場合は、created/modifiedも入ってきません