# Loggable behavioral extension for Doctrine2
**Loggable** behavior tracks your record changes and is able to
manage versions.
Features:
- Automatic storage of log entries in database
- ORM and ODM support using same listener
- Can be nested with other behaviors
- Objects can be reverted to previous versions
- Annotation, Yaml and Xml mapping support for extensions
[blog_reference]: http://gediminasm.org/article/loggable-behavioral-extension-for-doctrine2 "Loggable extension for Doctrine2 tracks record changes and version management"
[blog_test]: http://gediminasm.org/test "Test extensions on this blog"
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 [Loggable repository](http://github.com/l3pp4rd/DoctrineExtensions "Loggable extension on Github") is available on github
- Last update date: **2012-01-02**
**Portability:**
- **Loggable** 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 **Loggable**
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
- Basic usage [examples](#basic-examples)
## 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.
### Loggable annotations:
- **@Gedmo\Mapping\Annotation\Loggable(logEntryClass="my\class")** this class annotation
will store logs to optionally specified **logEntryClass**. You will still need to specify versioned fields with the following annotation.
- **@Gedmo\Mapping\Annotation\Versioned** tracks annotated property for changes
### Loggable username:
In order to set the username, when adding the loggable listener you need to set it this way:
``` php
$loggableListener = new Gedmo\Loggable\LoggableListener;
$loggableListener->setAnnotationReader($cachedAnnotationReader);
$loggableListener->setUsername('admin');
$evm->addEventSubscriber($loggableListener);
```
## Loggable Entity example:
**Note:** that Loggable interface is not necessary, except in cases there
you need to identify entity as being Loggable. The metadata is loaded only once when
cache is active
``` php
id;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
}
```
## Loggable Document example:
``` php
title;
}
public function getId()
{
return $this->id;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
}
```
## Yaml mapping example
Yaml mapped Article: **/mapping/yaml/Entity.Article.dcm.yml**
```
---
Entity\Article:
type: entity
table: articles
gedmo:
loggable:
# using specific personal LogEntryClass class:
logEntryClass: My\LogEntry
# without specifying the LogEntryClass class:
# loggable: true
id:
id:
type: integer
generator:
strategy: AUTO
fields:
title:
type: string
length: 64
gedmo:
- versioned
content:
type: text
```
## Xml mapping example
``` xml
```
## Basic usage examples:
``` php
setTitle('my title');
$em->persist($article);
$em->flush();
```
This inserted an article and inserted the logEntry for it, which contains
all new changeset. In case if there is **OneToOne or ManyToOne** relation,
it will store only identifier of that object to avoid storing proxies
Now lets update our article:
``` php
find('Entity\Article', 1 /*article id*/);
$article->setTitle('my new title');
$em->persist($article);
$em->flush();
```
This updated an article and inserted the logEntry for update action with new changeset
Now lets revert it to previous version:
``` php
getRepository('Gedmo\Loggable\Entity\LogEntry'); // we use default log entry class
$article = $em->find('Entity\Article', 1 /*article id*/);
$logs = $repo->getLogEntries($article);
/* $logs contains 2 logEntries */
// lets revert to first version
$repo->revert($article, 1/*version*/);
// notice article is not persisted yet, you need to persist and flush it
echo $article->getTitle(); // prints "my title"
$em->persist($article);
$em->flush();
// if article had changed relation, it would be reverted also.
```
Easy like that, any suggestions on improvements are very welcome