trejder
trejder

Reputation: 17495

Timestamp field can only by updated via behavior in Yii

In my model, I have a field named timestamp (MySQL type: timestamp) defined in safe validator and I'm unable to write it manually. Each time I call:

$model->timestmap = time();
$model->save();

model is saved (row created / updated), that is -- it passes validation without errors, but timestamp field is filled with default value of 0000-00-00 00:00:00 (I decided to remove default on update CURRENT_TIMESTAMP attribute, I don't want MySQL to handle this).

However, when I remove above code and attach CTimestampBehavior instead, field is being filled with correct values on both update and create, without any problems.

What can be happening or what am I missing? How can behavior update field without problems, while my manual attempt fails? Is this because column type is timestamp, not datetime or int?

I was always told, that first clue, why some attribute isn't saved, is because it is not listed among safe validator list or because it is listed on unsafe validator list. But this one is listed on safe list.

Upvotes: 0

Views: 1174

Answers (3)

Blizz
Blizz

Reputation: 8400

As the other answers already suggested:

The timestamp needs to be converted into a MySQL compatible date format string somehow upon saving and the other way around when loading. Now you already discovered that the CTimestampBehavior does this for you but unfortunately it doesn't care about loading. IMO the best solution for you is something along the way of:

public function beforeSave()
{
   $this->timestamp = date('Y-m-d H:i:s', $this->timestamp);
   return parent::beforeSave();
}

public function afterSave()
{
   // Turn it back into a unix timestamp in case you want to continue working with the record
   $this->timestamp = CDateTimeParser::parse($this->timestamp, 'yyyy-MM-dd hh:mm:ss');
   parent::afterSave();
}

public function afterFind()
{
   $this->timestamp = CDateTimeParser::parse($this->timestamp, 'yyyy-MM-dd hh:mm:ss');
   return parent::afterFind();
}

It's a lot of work for a stupid timestamp and so for myself I have an auto type conversion behaviour that I link to my models. This behaviour uses the table metadata to take care of everything automatically. Might be a good idea to invest in that. I've thought about making mine open source but it's a bit of a mess atm ;)

But the code above will give you unix times to work with during executing and whilst saving it will temporary convert into a mysql datetime string

Hope that helps.

Upvotes: 1

Andrii Mishchenko
Andrii Mishchenko

Reputation: 2694

I usually use $model->timestamp = date('Y-m-d H:i:s'), it works perfectly

Upvotes: 2

Michiel
Michiel

Reputation: 2203

Your database field is a datetime field (i assume, looking at your default value), but your filling it with a unix timestamp. Try it with an CDbExpression instead:

$model->timestamp = new CDbExpression('NOW()');
$model->save();

Upvotes: 4

Related Questions