How do I use Unix timestamps with the Doctrine Timestampable behavior? I found the following code snippet here, but I\'d rather not manually add this everywhere:
This is a question that might get an answer easier than what I first thought, actually...
Let's begin by what you have now :
Doctrine_Record
Test
, for my example(s).Test
model, you want to use the Timestampable
Behaviour, but with UNIX timestamps, and not datetime
valuesA solution to this problem would be to not use the default Timestampable
behaviour that comes with Doctrine, but another one, that you will define.
Which means, in your model, you will have something like this at the bottom of setTableDefinition
method :
$this->actAs('MyTimestampable');
(I suppose this could go in the setUp
method too, btw -- maybe it would be it's real place, actually)
What we now have to do is define that MyTimestampable
behaviour, so it does what we want.
As Doctrine's Doctrine_Template_Timestampable
already does the job quite well (except for the format, of course), we will inherit from it ; hopefully, it'll mean less code to write ;-)
So, we declare our behaviour class like this :
class MyTimestampable extends Doctrine_Template_Timestampable
{
// Here it will come ^^
}
Now, let's have a look at what Doctrine_Template_Timestampable
actually does, in Doctrine's code source :
created_at
and updated_at
fields)$this->addListener(new Doctrine_Template_Listener_Timestampable($this->_options));
Let's have a look at the source of this one ; we notice this part :
if ($options['type'] == 'date') {
return date($options['format'], time());
} else if ($options['type'] == 'timestamp') {
return date($options['format'], time());
} else {
return time();
}
This means if the type of the two created_at
and updated_at
fields is not date
nor timestamp
, Doctrine_Template_Listener_Timestampable
will automatically use an UNIX timestamp -- how convenient !
As you don't want to define the type
to use for those fields in every one of your models, we will modify our MyTimestampable
class.
Remember, we said it was extending Doctrine_Template_Timestampable
, which was responsible of the configuration of the behaviour...
So, we override that configuration, using a type
other than date
and timestamp
:
class MyTimestampable extends Doctrine_Template_Timestampable
{
protected $_options = array(
'created' => array('name' => 'created_at',
'alias' => null,
'type' => 'integer',
'disabled' => false,
'expression' => false,
'options' => array('notnull' => true)),
'updated' => array('name' => 'updated_at',
'alias' => null,
'type' => 'integer',
'disabled' => false,
'expression' => false,
'onInsert' => true,
'options' => array('notnull' => true)));
}
We said earlier on that our model was acting as MyTimestampable
, and not Timestampable
... So, now, let's see the result ;-)
If we consider this model class for Test
:
class Test extends Doctrine_Record
{
public function setTableDefinition()
{
$this->setTableName('test');
$this->hasColumn('id', 'integer', 4, array(
'type' => 'integer',
'length' => 4,
'unsigned' => 0,
'primary' => true,
'autoincrement' => true,
));
$this->hasColumn('name', 'string', 32, array(
'type' => 'string',
'length' => 32,
'fixed' => false,
'primary' => false,
'notnull' => true,
'autoincrement' => false,
));
$this->hasColumn('value', 'string', 128, array(
'type' => 'string',
'length' => 128,
'fixed' => false,
'primary' => false,
'notnull' => true,
'autoincrement' => false,
));
$this->hasColumn('created_at', 'integer', 4, array(
'type' => 'integer',
'length' => 4,
'unsigned' => 0,
'primary' => false,
'notnull' => true,
'autoincrement' => false,
));
$this->hasColumn('updated_at', 'integer', 4, array(
'type' => 'integer',
'length' => 4,
'unsigned' => 0,
'primary' => false,
'notnull' => false,
'autoincrement' => false,
));
$this->actAs('MyTimestampable');
}
}
Which maps to the following MySQL table :
CREATE TABLE `test1`.`test` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(32) NOT NULL,
`value` varchar(128) NOT NULL,
`created_at` int(11) NOT NULL,
`updated_at` int(11) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
We can create two rows in the table this way :
$test = new Test();
$test->name = 'Test 1';
$test->value = 'My Value 2';
$test->save();
$test = new Test();
$test->name = 'Test 2';
$test->value = 'My Value 2';
$test->save();
If we check the values in the DB, we'll get something like this :
mysql> select * from test;
+----+--------+----------------+------------+------------+
| id | name | value | created_at | updated_at |
+----+--------+----------------+------------+------------+
| 1 | Test 1 | My Value 1 | 1248805507 | 1248805507 |
| 2 | Test 2 | My Value 2 | 1248805583 | 1248805583 |
+----+--------+----------------+------------+------------+
2 rows in set (0.00 sec)
So, we are OK for the creation of rows, it seems ;-)
And now, let's fetch and update the second row :
$test = Doctrine::getTable('Test')->find(2);
$test->value = 'My New Value 2';
$test->save();
And, back to the DB, we now get this :
mysql> select * from test;
+----+--------+----------------+------------+------------+
| id | name | value | created_at | updated_at |
+----+--------+----------------+------------+------------+
| 1 | Test 1 | My Value 1 | 1248805507 | 1248805507 |
| 2 | Test 2 | My New Value 2 | 1248805583 | 1248805821 |
+----+--------+----------------+------------+------------+
2 rows in set (0.00 sec)
The updated_at
field has been updated, and the created_at
field has not changed ; which seems OK too ;-)
So, to make things short, fit in a couple of bullet points, and summarize quite a bit :
MyTimestampable
, and not the default Timestampable
I will let you do some more intensive tests, but I hope this helps !
Have fun :-)
Its very simple. Just create a Setter method for your field with a datetime parameter and use the tostring method to store it as integer.
One method would be to use doctorine's listeners to create a unix timestamp equivalent when the record is fetched and before it is saved:
class Base extends Doctrine_Record_Listener
{
public function preHydrate(Doctrine_Event $event)
{
$data = $event->data;
$data['unix_created_at'] = strtotime($data['created_at']);
$data['unix_updated_at'] = strtotime($data['updated_at']);
$event->data = $data;
}
}
This could be your base class that you extend in anything that needs created_at and updated_at functionality.
I'm sure with a little bit more tinkering you could loop through $data and convert all datetime fields 'unix_'.$field_name.
Good luck