Cakephp's beforeSave not retaining new data when using saveAll?
I have a relatively simple entries model with just five fields:
- id
- type (what datatype this entry is)
- amount (how many of whatever type it is)
- unit (the unit of the type)
- date (the datettime when this entry was entered)
- user_id (the id of the user who enters
So, nothing fancy. Now a single form can have multiple entries (both already existing ones and new ones just created), the form is extended via ajax calls.
When I submit the form $this->data
looks like this:
Array
(
[Entry] => Array
(
[date] => 2011-01-07
[0] => Array
(
[id] => 1
[type] => Eat
[amount] => 1 Steak, one baked potatoe
[unit] => lunch
[time] => Array
(
[hour] => 13
[min] => 31
)
)
[1] => Array
(
[type] => weight
[amount] => 78.5
[unit] => KG
[time] => Array
(
[hour] => 22
[min] => 22
)
)
)
)
The first entry in $this->data['Entry']['date']
is the date that shall be used by ALL the entries. And since also the user_id is missing I created a "beforeSave" function in the entry-model. It looks like this:
function beforeSave() {
App::import('Component','Session');
$this->Session = new SessionComponent();
if (isset($this->data) && isset($this->data['Entry'])) {
$date = $this->data['Entry']['date'];
unset($this->data['Entry']['date']);
foreach ($this->data['Entry'] as $n => $entry) {
if (is_array($entry)) {
$this->data['Entry'][$n]['date'] = $date . ' ' . $entry['time']['hour'] . ':' . $entry['time']['min'] . ':00';
$this->data['Entry'][$n]['user_id'] = $this->Session->read('Auth.User.id');
}
}
debug($this->data);
}
return true;
}
I remove the date, add it together with the time entry of the user, thus creating a mysql datetime entry and add the user_id of the logged in user. Straightforward, really. The resulting array (as output by that last debug()
) looks like the following:
Array
(
[Entry] => Array
(
[0] => Array
(
[id] => 1
[type] => Eat
[amount] => 1 Steak, 1 baked potatoe
[unit] => lunch
开发者_如何学运维 [time] => Array
(
[hour] => 09
[min] => 31
)
[date] => 2011-01-07 09:31:00
[user_id] => 2
)
[1] => Array
(
[type] => Weight
[amount] => 78.5
[unit] => KG
[time] => Array
(
[hour] => 22
[min] => 22
)
[date] => 2011-01-07 22:22:00
[user_id] => 2
)
)
)
So it look exactly like I want it to look and it should be easily saved. But when I use $this->Entry->saveAll($this->data['Entry']
) to save all the entries, not only does it not work, but when I debug $this->data
directly after the saveAll, it looks exactly like before the saveAll function - the date is back in the array, the entries do not have a date or user_id entry.
I can see that beforeSave is called, I can see that it changes $this->data
, but somewhere between the end of beforeSave and the usage of "saveAll" all my changes get lost and $this->data
is reverted to it's original state. Therefore no saving takes place.
I had similar problem trying to implement some sanitization with hasMany through. As it turns out the problem lies in how saveAll() works. The $this->data in controller isn't the same as $this->data in Model::beforeSave() callback and the two are not synchronized. When You call Model::saveAll() passing $this->data from the controller You explicitly give the model "the old version" of data array. And when You look into saveAll definition in cake/libs/model/model.php it just does:
if (empty($data)) {
$data = $this->data
}
and nothing more to sync up the modified $data array in model and passed by parameter $data form the controller. The solution is to not pass the data to saveAll() but instead set the data on model first using Model::set() and then call Model::saveAll() (without the $data parameter).
When we call SaveAll, doesn't pass updated/submitted data to model's beforeSave. To come out from this issue,
create tmp_data array in model
i.e.
var $tmp_data = array();
before saveall call, set this variable, i.e.
$this->model->tmp_data = $this->data;
$this->model->saveAll();
Then, amend code for model->beforeSaveBefore
Instead of $this->data use $this->tmp_data
You're not getting tripped up on validation are you?
Try
$this->Entry->saveAll($data,array('validate'=>false));
If it works then the problem lies in validation
However don't forget that you need to use create() before saving for single models if no primary key is specified. Maybe the mixing of new and existing data in the saveAll() is the issue.
as far as I know saveAll() updateAll() and deleteAll() dont trigger any callbacks by default
you need to enable them manually (last parameter of the method)
精彩评论