6

如何使用带有 Doctrine Timestampable 行为的 Unix 时间戳?我在这里找到了以下代码片段,但我不想在任何地方手动添加它:

$this->actAs('Timestampable', array(
'created' => array('name' => 'created_at',
    'type'    =>  'integer',
    'format'  =>  'U',
    'disabled' => false,
    'options' =>  array()),
'updated' => array('name'    =>  'updated_at',
    'type'    =>  'integer',
    'format'  =>  'U',
    'disabled' => false,
    'options' =>  array())));
4

3 回答 3

33

这个问题可能比我最初想象的更容易得到答案,实际上......

让我们从你现在拥有的开始:

  • 一个模型类,它扩展Doctrine_Record
    • Test对于我的例子,我将调用这个类。
    • 在此Test模型中,您希望使用Timestampable行为,但使用 UNIX 时间戳,而不是datetime
    • 而且你想要这个,而不必在你的模型中编写大量的配置内容。
      (我可以理解:在某处忘记一行并在数据库中错误数据的风险较小)
  • 一个已配置的项目和一切
    • 这意味着你知道你的教义
    • 而且我不会谈论基础知识

解决此问题的方法是不使用TimestampableDoctrine 附带的默认行为,而是使用您将定义的另一种行为。
这意味着,在您的模型中,您将在方法底部有类似的内容setTableDefinition

$this->actAs('MyTimestampable');

(我想这也可以在setUp方法中使用,顺便说一句——实际上它可能是真实的地方)


我们现在要做的是定义这种MyTimestampable行为,让它做我们想做的事。
由于 DoctrineDoctrine_Template_Timestampable已经很好地完成了这项工作(当然格式除外),我们将继承它;希望这意味着要编写更少的代码;-)

所以,我们像这样声明我们的行为类:

class MyTimestampable extends Doctrine_Template_Timestampable
{
    // Here it will come ^^
}

现在,让我们看看Doctrine_Template_Timestampable在 Doctrine 的代码源中实际做了什么:

  • 一些配置(两个created_atupdated_at字段)
  • 以下行注册了一个监听器:


$this->addListener(new Doctrine_Template_Listener_Timestampable($this->_options));

让我们看看这个的来源;我们注意到这部分:

if ($options['type'] == 'date') {
    return date($options['format'], time());
} else if ($options['type'] == 'timestamp') {
    return date($options['format'], time());
} else {
    return time();
}

这意味着如果两个created_atandupdated_at字段的类型不是datenor timestampDoctrine_Template_Listener_Timestampable将自动使用一个UNIX时间戳——多么方便!


由于您不想type为每个模型中的这些字段定义要使用的,我们将修改我们的MyTimestampable类。
请记住,我们说它正在扩展Doctrine_Template_Timestampable,它负责行为的配置......

因此,我们使用typedateand覆盖该配置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)));
}

我们之前说过,我们的模型是作为MyTimestampable,而不是Timestampable......所以,现在,让我们看看结果;-)

如果我们考虑这个模型类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');
    }
}

映射到以下 MySQL 表:

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

我们可以通过这种方式在表中创建两行:

$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();

如果我们检查数据库中的值,我们将得到如下信息:

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)

所以,我们似乎可以创建行;-)


现在,让我们获取并更新第二行:

$test = Doctrine::getTable('Test')->find(2);
$test->value = 'My New Value 2';
$test->save();

而且,回到数据库,我们现在得到了这个:

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)

updated_at字段已更新,字段created_at未更改;这似乎也不错;-)


所以,为了让事情简短,适合几个要点,并总结了很多:

  • 我们的模型类作为我们自己的MyTimestampable,而不是默认的Timestampable
  • 我们的行为扩展了 Doctrine 的行为
  • 并且只覆盖它的配置
    • 所以我们可以随心所欲地使用它,每个模型中只有一行代码。


我会让你做一些更密集的测试,但我希望这会有所帮助!
玩得开心:-)

于 2009-07-28T19:02:13.133 回答
2

一种方法是在获取记录时和保存之前使用医生的侦听器创建等效的 unix 时间戳:

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;
    }
}

这可能是您在需要 created_at 和 updated_at 功能的任何东西中扩展的基类。

我敢肯定,只要稍加修改,您就可以遍历 $data 并转换所有日期时间字段 'unix_'.$field_name。

祝你好运

于 2009-07-28T17:45:50.790 回答
0

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.

于 2020-03-06T06:31:29.457 回答