# Timestampable behavior extension for Doctrine 2
**Timestampable** behavior will automate the update of date fields
on your Entities or Documents. It works through annotations and can update
fields on creation, update, property subset update, or even on specific property value change.
Features:
- Automatic predefined date field update on creation, update, property subset update, and even on record property changes
- ORM and ODM support using same listener
- Specific annotations for properties, and no interface required
- Can react to specific property or relation changes to specific value
- Can be nested with other behaviors
- Annotation, Yaml and Xml mapping support for extensions
[blog_reference]: http://gediminasm.org/article/timestampable-behavior-extension-for-doctrine-2 "Timestampable extension for Doctrine 2 helps automate update of dates"
[blog_test]: http://gediminasm.org/test "Test extensions on this blog"
Update **2012-06-26**
- Allow multiple values for on="change"
Update **2012-03-10**
- Add [Timestampable traits](#traits)
Update **2011-04-04**
- Made single listener, one instance can be used for any object manager
and any number of them
**Note:**
- You can [test live][blog_test] on this blog
- Public [Timestampable repository](http://github.com/l3pp4rd/DoctrineExtensions "Timestampable extension on Github") is available on github
- Last update date: **2012-01-02**
**Portability:**
- **Timestampable** is now available as [Bundle](http://github.com/stof/StofDoctrineExtensionsBundle)
ported to **Symfony2** by **Christophe Coevoet**, together with all other extensions
This article will cover the basic installation and functionality of **Timestampable** behavior
Content:
- [Including](#including-extension) the extension
- Entity [example](#entity-mapping)
- Document [example](#document-mapping)
- [Yaml](#yaml-mapping) mapping example
- [Xml](#xml-mapping) mapping example
- Advanced usage [examples](#advanced-examples)
- Using [Traits](#traits)
## Setup and autoloading
Read the [documentation](http://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup)
or check the [example code](http://github.com/l3pp4rd/DoctrineExtensions/tree/master/example)
on how to setup and use the extensions in most optimized way.
## Timestampable Entity example:
### Timestampable annotations:
- **@Gedmo\Mapping\Annotation\Timestampable** this annotation tells that this column is timestampable
by default it updates this column on update. If column is not date, datetime or time
type it will trigger an exception.
Available configuration options:
- **on** - is main option and can be **create, update, change** this tells when it
should be updated
- **field** - only valid if **on="change"** is specified, tracks property or a list of properties for changes
- **value** - only valid if **on="change"** is specified and the tracked field is a single field (not an array), if the tracked field has this **value**
**Note:** that Timestampable interface is not necessary, except in cases there
you need to identify entity as being Timestampable. The metadata is loaded only once then
cache is activated
``` php
id;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function setBody($body)
{
$this->body = $body;
}
public function getBody()
{
return $this->body;
}
public function getCreated()
{
return $this->created;
}
public function getUpdated()
{
return $this->updated;
}
public function getContentChanged()
{
return $this->contentChanged;
}
}
```
## Timestampable Document example:
``` php
id;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function setBody($body)
{
$this->body = $body;
}
public function getBody()
{
return $this->body;
}
public function getCreated()
{
return $this->created;
}
public function getUpdated()
{
return $this->updated;
}
public function getContentChanged()
{
return $this->contentChanged;
}
}
```
Now on update and creation these annotated fields will be automatically updated
## Yaml mapping example:
Yaml mapped Article: **/mapping/yaml/Entity.Article.dcm.yml**
```
---
Entity\Article:
type: entity
table: articles
id:
id:
type: integer
generator:
strategy: AUTO
fields:
title:
type: string
length: 64
created:
type: date
gedmo:
timestampable:
on: create
updated:
type: datetime
gedmo:
timestampable:
on: update
```
## Xml mapping example
``` xml
```
## Advanced examples:
### Using dependency of property changes
Add another entity which would represent Article Type:
``` php
id;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
}
```
Now update the Article Entity to reflect published date on Type change:
``` php
type = $type;
}
public function getId()
{
return $this->id;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function getCreated()
{
return $this->created;
}
public function getUpdated()
{
return $this->updated;
}
public function getPublished()
{
return $this->published;
}
}
```
Yaml mapped Article: **/mapping/yaml/Entity.Article.dcm.yml**
```
---
Entity\Article:
type: entity
table: articles
id:
id:
type: integer
generator:
strategy: AUTO
fields:
title:
type: string
length: 64
created:
type: date
gedmo:
timestampable:
on: create
updated:
type: datetime
gedmo:
timestampable:
on: update
published:
type: datetime
gedmo:
timestampable:
on: change
field: type.title
value: Published
manyToOne:
type:
targetEntity: Entity\Type
inversedBy: articles
```
Now few operations to get it all done:
``` php
setTitle('My Article');
$em->persist($article);
$em->flush();
// article: $created, $updated were set
$type = new Type;
$type->setTitle('Published');
$article = $em->getRepository('Entity\Article')->findByTitle('My Article');
$article->setType($type);
$em->persist($article);
$em->persist($type);
$em->flush();
// article: $published, $updated were set
$article->getPublished()->format('Y-m-d'); // the date article type changed to published
```
Easy like that, any suggestions on improvements are very welcome
### Creating a UTC DateTime type that stores your datetimes in UTC
First, we define our custom data type (note the type name is datetime and the type extends DateTimeType which simply overrides the default Doctrine type):
``` php
setTimeZone(self::$utc);
return $value->format($platform->getDateTimeFormatString());
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
if ($value === null) {
return null;
}
if (is_null(self::$utc)) {
self::$utc = new \DateTimeZone('UTC');
}
$val = \DateTime::createFromFormat($platform->getDateTimeFormatString(), $value, self::$utc);
if (!$val) {
throw ConversionException::conversionFailed($value, $this->getName());
}
return $val;
}
}
```
Now in Symfony2, we register and override the **datetime** type. **WARNING:** this will override the **datetime** type for all your entities and for all entities in external bundles or extensions, so if you have some entities that require the standard **datetime** type from Doctrine, you must modify the above type and use a different name (such as **utcdatetime**). Additionally, you'll need to modify **Timestampable** so that it includes **utcdatetime** as a valid type.
```
doctrine:
dbal:
types:
datetime: Acme\DoctrineExtensions\DBAL\Types\UTCDateTimeType
```
And our Entity properties look as expected:
``` php
## Traits
You can use timestampable traits for quick **createdAt** **updatedAt** timestamp definitions
when using annotation mapping.
**Note:** this feature is only available since php **5.4.0**. And you are not required
to use the Traits provided by extensions.
``` php