Seems that in my application, model is not causing MySQL to update field that contains “on update CURRENT_TIMESTAMP” in structure’s attribute. This field is properly populated by MySQL only when a new record is created using model. But each updates to existing one does not update it. Field name is on list of safe validator, but still nothing.
Is this a normal behaviour? Or maybe my modified beforeSave method of this particular model is causing these problems (but how and why?):
public function beforeSave()
{
if(parent::beforeSave())
{
$this->user_id = Yii::app()->user->id;
return true;
}
else return false;
}
or something else?
I had to add line:
$this->date_changed = date('Y-m-d H:i:s');
to above method to achieve saving update date also, not only create date. And I don’t understand, what is going on here?
I’m new to Yii, but just thinking about it, and maybe somebody else could expound on this, could it be that Yii::AR is populating the ‘date_changed’ field with the previous value on update and this is causing MySQL to think that you are setting the value manually. You may need to set the value to null in your beforeSave() function.
I found somewhere on this site that to save dates as null, you need to change manually set them in the beforeSave() function.
jkofsky got it right… if you tell the database to store a value for a field… it does so only if you don’t send any value for that field (if you think about this it makes sense)…
What happens on update is that you first read the record… so that all the fields (even the update field) gets it’s values… then you edit the fields in some form… the update fields is not edited… so it has the value read from the database… then when you save the record… you are actually sending the old value to the database…
So now you can think about many solutions:
set manually the value like you wrote above (a behavior can be used for this), but then the setting “on update CURRENT_TIMESTAMP” in the database does not have it’s value…
set this field to null before saving
when saving data, specify what attributes you want to save (leaving update out)
Thanks for the idea. From my point of view there is no difference, if I set this field with current time formatted to format supported by MySQL (using date()) or if I set it to NULL and let MySQL updated the field. I would be more happy to get answer, why AR is not setting this itself, but you’re right - we need to wait for more experienced users or someone out of dev team.
BTW: Does anyone have any idea, why using just time() in this field instead of date() (as in above example):
$this->date_changed = time();
zeroed this field, and - as I further investigated - this was caused by time() returning empty string, if called like this:
die(time());
and only returning proper value (current timestamp), when called like this:
die('"'.time().'"');
Because I was little surprised, as up until yesterday I thought that there is no difference and time() should always return timestamp.
You mean that if I just open the update view and click "Update" which will force ActiveRecord to generate update SQL, but data sent with this update will be exactly the same as already kept in DB, there will be no current-timestamp update?
Good point! I haven’t thought about it. I need to double check it, but even so, I’m pretty sure that date was not updated no matter if I changed some data or not.
I was just thinking about this. With an onUpdate CURRENT_TIMESTAMP in the database, would it be just a simple matter of changing the form to display a textLabel() for the value instead of a textField()?
My thinking is to have the form send a null to the field, and that’s the ony way I can think off. Any comments?
But I’m not using additional form field. I’ve added beforeSave() method to my model, where I set timestamp field (currently to current date, maybe set to NULL there as well). I think this is more efficient than changing controller code, but I may be wrong.
Thanks outrage. I was thinking along the lines of the gii generated _form file. It puts a textField() in for everything, and IF you still wanted to display it on the form one could maybe use a textLabel() in stead. Other wise just cut the whole section out and not have the field display at all. I was just thinking that if the “timestamp_field” wasn’t in the $_POST[], Yii would “send” a null.
Thank you for sharing possible solutions, but the two first have a problem: the "date updated" field always gets updated even if there are no changes in the other fields.
In the first case, it’s because you’re manually assigning the value, and in the second case, it’s because you’re trying to update the row with a null value in the “automatic” field, so this by itself is a change and it’s why MySQL updates the “automatic” field.
This is not the desired behavior of this type of fields. The automatic date field should be updated only when there are actual changes in the other fields in the row.
So, would anyone please advise on how to tell the model not to assign any value (not even null) to an automatic date field, so MySQL do the work with the expected behavior?
I found that in the CActiveRecord.save function of you can specify which attributes you want to save, and this may work but… it would be frustrating having to specify the whole list of attributes in every controller action that saves the model. It would be awful for code readability and maintainability on models with many attributes. An added "bonus" of that would be that changes in the DB field names would have more impact in code changes.
Is there a way to specify in the model class (not in the controller) that there’s one field that should not be assigned any value when saving the model?
Somebody please advise. This thread has 2000+ views so it would be helpful for many people for sure.
This is how I have solved this problem (after a lot of trial and error!)
This solution works for both Inserts and Updates.
Add the following beforeSave() method to your CActiveRecord class:
public function beforeSave() {
[b]unset($this->timestamp_column);[/b]
return parent::beforeSave();
}
‘timestamp_column’ refers, of course, to the MySQL column that you have configured with UPDATE CURRENT TIMESTAMP.
Important note: The important thing here is to use unset(), not just set the property to null. Setting the property to null will cause a null value to be stored into the TIMESTAMP column. So, you have to use unset() so that no action whatsoever is taken with respect to this column, allowing MySQL to its automatic TIMESTAMP thing.
There’s probably a more elegant way to solve this problem, but this is the only way I could figure out how to do it. If there’s a better way I’d love to hear it.