Use o timestamp Unix no Timestampable de Doutrina
-
19-09-2019 - |
Pergunta
Como uso timestamps do Unix com o comportamento da Doutrina Timestampable? Eu encontrei o seguinte snippet de código aqui, mas prefiro não adicionar manualmente em todos os lugares:
$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())));
Solução
Esta é uma pergunta que pode obter uma resposta mais fácil do que eu pensava, na verdade ...
Vamos começar pelo que você tem agora:
- uma classe modelo, que se estende
Doctrine_Record
- Vou chamar essa aula
Test
, para o meu (s) exemplo (s). - Nisso
Test
modelo, você deseja usar oTimestampable
Comportamento, mas com timestamps Unix, e nãodatetime
valores - E você quer isso sem ter que escrever muitas coisas de configuração em seus modelos.
(Eu posso entender isso: Menos risco de esquecer uma linha em algum lugar e em dados errados no banco de dados)
- Vou chamar essa aula
- Um projeto que está configurado e tudo
- O que significa que você conhece coisas com doutrina
- e que não vou falar sobre o básico
Uma solução para esse problema seria não usar o padrão Timestampable
comportamento que vem com doutrina, mas outra, que você definirá.
O que significa que, em seu modelo, você terá algo assim na parte inferior de setTableDefinition
método:
$this->actAs('MyTimestampable');
(Suponho que isso possa ir no setUp
Método também, btw - talvez seja o lugar real, na verdade)
O que agora temos que fazer é definir isso MyTimestampable
comportamento, então faz o que queremos.
Como doutrina Doctrine_Template_Timestampable
Já faz o trabalho muito bem (Exceto pelo formato, é claro), nós herdaremos dele; Felizmente, isso significará menos código para escrever ;-)
Então, declaramos nossa aula de comportamento como esta:
class MyTimestampable extends Doctrine_Template_Timestampable
{
// Here it will come ^^
}
Agora, vamos dar uma olhada no que Doctrine_Template_Timestampable
Na verdade, na fonte de código da doutrina:
- um pouco de configuração (os dois
created_at
eupdated_at
Campos) - E a linha a seguir, que registra um ouvinte:
$this->addListener(new Doctrine_Template_Listener_Timestampable($this->_options));
Vamos dar uma olhada na fonte deste; Notamos esta parte:
if ($options['type'] == 'date') {
return date($options['format'], time());
} else if ($options['type'] == 'timestamp') {
return date($options['format'], time());
} else {
return time();
}
Isso significa se o tipo dos dois created_at
e updated_at
campos não é date
nem timestamp
, Doctrine_Template_Listener_Timestampable
Usará automaticamente um registro de data e hora do UNIX - que conveniente!
Como você não deseja definir o type
Para usar para esses campos em todos os seus modelos, modificaremos nosso MyTimestampable
classe.
Lembre -se, dissemos que estava se estendendo Doctrine_Template_Timestampable
, responsável pela configuração do comportamento ...
Então, substituímos essa configuração, usando um type
outro que não seja date
e 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)));
}
Dissemos anteriormente que nosso modelo estava agindo como MyTimestampable
, e não Timestampable
... Então, agora, vamos ver o resultado ;-)
Se considerarmos esta classe modelo para 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');
}
}
Que mapeia para a seguinte tabela 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
Podemos criar duas linhas na tabela desta maneira:
$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();
Se verificarmos os valores no banco de dados, conseguiremos algo assim:
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)
Então, estamos bem para a criação de linhas, ao que parece ;-)
E agora, vamos buscar e atualizar a segunda linha:
$test = Doctrine::getTable('Test')->find(2);
$test->value = 'My New Value 2';
$test->save();
E, de volta ao banco de dados, agora entendemos o seguinte:
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)
o updated_at
o campo foi atualizado e o created_at
O campo não mudou; O que parece ok também ;-)
Então, para resumir as coisas, se encaixe em alguns pontos de bala e resume um pouco:
- Nossa classe modelo atua como nossa
MyTimestampable
, e não o padrãoTimestampable
- Nosso comportamento estende o único da doutrina
- E apenas substitui sua configuração
- Para que possamos usá -lo como queremos, com apenas uma linha de código em cada um de nossos modelos.
Vou deixar você fazer testes mais intensivos, mas espero que isso ajude!
Divirta-se :-)
Outras dicas
Um método seria usar os ouvintes da Doctorine para criar um timestamp Unix equivalente quando o registro for buscado e antes de ser salvo:
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;
}
}
Essa pode ser a sua classe base que você se estende em qualquer coisa que precise da funcionalidade criada e atualizada_at.
Tenho certeza de que, com um pouco mais de mexer, você pode atravessar $ dados e converter todos os campos de dados 'Unix _'. $ Field_name.
Boa sorte