267 lines
6.3 KiB
Markdown
267 lines
6.3 KiB
Markdown
# 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
|
|
|
|
Update **2011-04-04**
|
|
|
|
- Made single listener, one instance can be used for any object manager
|
|
and any number of them
|
|
|
|
**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)
|
|
|
|
<a name="including-extension"></a>
|
|
|
|
## Setup and autoloading
|
|
|
|
Read the [documentation](http://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/annotations.md#em-setup)
|
|
or check the [example code](http://github.com/Atlantic18/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);
|
|
```
|
|
<a name="entity-mapping"></a>
|
|
|
|
## 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
|
|
<?php
|
|
namespace Entity;
|
|
|
|
use Gedmo\Mapping\Annotation as Gedmo;
|
|
use Doctrine\ORM\Mapping as ORM;
|
|
|
|
/**
|
|
* @ORM\Entity
|
|
* @Gedmo\Loggable
|
|
*/
|
|
class Article
|
|
{
|
|
/**
|
|
* @ORM\Column(name="id", type="integer")
|
|
* @ORM\Id
|
|
* @ORM\GeneratedValue(strategy="IDENTITY")
|
|
*/
|
|
private $id;
|
|
|
|
/**
|
|
* @Gedmo\Versioned
|
|
* @ORM\Column(name="title", type="string", length=8)
|
|
*/
|
|
private $title;
|
|
|
|
public function getId()
|
|
{
|
|
return $this->id;
|
|
}
|
|
|
|
public function setTitle($title)
|
|
{
|
|
$this->title = $title;
|
|
}
|
|
|
|
public function getTitle()
|
|
{
|
|
return $this->title;
|
|
}
|
|
}
|
|
```
|
|
|
|
<a name="document-mapping"></a>
|
|
|
|
## Loggable Document example:
|
|
|
|
``` php
|
|
<?php
|
|
namespace Document;
|
|
|
|
use Gedmo\Mapping\Annotation as Gedmo;
|
|
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
|
|
|
|
/**
|
|
* @ODM\Document(collection="articles")
|
|
* @Gedmo\Loggable
|
|
*/
|
|
class Article
|
|
{
|
|
/** @ODM\Id */
|
|
private $id;
|
|
|
|
/**
|
|
* @ODM\Field(type="string")
|
|
* @Gedmo\Versioned
|
|
*/
|
|
private $title;
|
|
|
|
public function __toString()
|
|
{
|
|
return $this->title;
|
|
}
|
|
|
|
public function getId()
|
|
{
|
|
return $this->id;
|
|
}
|
|
|
|
public function setTitle($title)
|
|
{
|
|
$this->title = $title;
|
|
}
|
|
|
|
public function getTitle()
|
|
{
|
|
return $this->title;
|
|
}
|
|
}
|
|
```
|
|
|
|
<a name="yaml-mapping"></a>
|
|
|
|
## 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
|
|
```
|
|
|
|
<a name="xml-mapping"></a>
|
|
|
|
## Xml mapping example
|
|
|
|
``` xml
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
|
xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
|
|
|
|
<entity name="Mapping\Fixture\Xml\Loggable" table="loggables">
|
|
|
|
<id name="id" type="integer" column="id">
|
|
<generator strategy="AUTO"/>
|
|
</id>
|
|
|
|
<field name="title" type="string" length="128">
|
|
<gedmo:versioned/>
|
|
</field>
|
|
<many-to-one field="status" target-entity="Status">
|
|
<join-column name="status_id" referenced-column-name="id"/>
|
|
<gedmo:versioned/>
|
|
</many-to-one>
|
|
|
|
<gedmo:loggable log-entry-class="Gedmo\Loggable\Entity\LogEntry"/>
|
|
|
|
</entity>
|
|
</doctrine-mapping>
|
|
```
|
|
|
|
<a name="basic-examples"></a>
|
|
|
|
## Basic usage examples:
|
|
|
|
``` php
|
|
<?php
|
|
$article = new Entity\Article;
|
|
$article->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
|
|
<?php
|
|
// first load the article
|
|
$article = $em->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
|
|
<?php
|
|
// first check our log entries
|
|
$repo = $em->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
|