Gedmo\Loggable logs data that doesn't have changed

rabudde picture rabudde · Apr 26, 2013 · Viewed 8.7k times · Source

I'm using Symfony2.2 with StofDoctrineExtensionsBundle (and so Gedmo DoctrineExtensions). I've a simple entity

/**
 * @ORM\Entity
 * @Gedmo\Loggable
 * @ORM\Table(name="person")
 */
class Person {
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

[...]

    /**
     * @ORM\Column(type="datetime", nullable=true)
     * @Assert\NotBlank()
     * @Assert\Date()
     * @Gedmo\Versioned
     */
    protected $birthdate;
}

When changing an attribute for an existing object, a log entry is done in table ext_log_entries. An entry in this log table contains only changed columns. I can read the log by:

$em = $this->getManager();
$repo = $em->getRepository('Gedmo\Loggable\Entity\LogEntry');
$person_repo = $em->getRepository('Acme\MainBundle\Entity\Person');

$person = $person_repo->find(1);
$log = $repo->findBy(array('objectId' => $person->getId()));
foreach ($log as $log_entry) { var_dump($log_entry->getData()); }

But what I don't understand is, why the field birthdate is always contained in a log entry, even it's not changed. Here some examples of three log entries:

array(9) {
  ["salutation"]=>
  string(4) "Herr"
  ["firstname"]=>
  string(3) "Max"
  ["lastname"]=>
  string(6) "Muster"
  ["street"]=>
  string(14) "Musterstraße 1"
  ["zipcode"]=>
  string(5) "00000"
  ["city"]=>
  string(12) "Musterhausen"
  ["birthdate"]=>
  object(DateTime)#655 (3) {
    ["date"]=>
    string(19) "1893-01-01 00:00:00"
    ["timezone_type"]=>
    int(3)
    ["timezone"]=>
    string(13) "Europe/Berlin"
  }
  ["email"]=>
  string(17) "[email protected]"
  ["phone"]=>
  NULL
}

array(2) {
  ["birthdate"]=>
  object(DateTime)#659 (3) {
    ["date"]=>
    string(19) "1893-01-01 00:00:00"
    ["timezone_type"]=>
    int(3)
    ["timezone"]=>
    string(13) "Europe/Berlin"
  }
  ["phone"]=>
  string(9) "123456789"
}

array(2) {
  ["birthdate"]=>
  object(DateTime)#662 (3) {
    ["date"]=>
    string(19) "1893-01-01 00:00:00"
    ["timezone_type"]=>
    int(3)
    ["timezone"]=>
    string(13) "Europe/Berlin"
  }
  ["phone"]=>
  NULL
}

I want to log only really changed data. Is there any option I've not seen yet? It seems to be related to the fact, that birthdate is a DateTime object, doesn't it?

EDIT It is not related to the DateTime object. This occurs even in other entities. I've another entity containing a simple value:

/**
 * @ORM\Entity
 * @Gedmo\Loggable
 * @ORM\Entity(repositoryClass="Acme\MainBundle\Repository\ApplicationRepository")
 * @ORM\Table(name="application")
 */
class Application {

[...]

    /**
     * @ORM\Column(type="integer")
     * @Assert\NotBlank(groups={"FormStepOne", "UserEditApplication"})
     * @Gedmo\Versioned
     */
    protected $insurance_number;
}

When opening the edit form in browser an saving without modification, the log table contains:

update  2013-04-26 11:32:42     Acme\MainBundle\Entity\Application  a:1:{s:16:"insurance_number";s:7:"1234567";}
update  2013-04-26 11:33:17     Acme\MainBundle\Entity\Application  a:1:{s:16:"insurance_number";s:7:"1234567";}

Why?

Answer

calumbrodie picture calumbrodie · May 9, 2013

This might be a similar issue to the one I encountered when using another of these extensions (timestampable), namely: that the default change tracking policy used in doctrine (it tries to auto detect changes) sometimes marks entities as dirty, when they are not (for me this was happening when my entity contained a datetime object, which is understandable given that this is an object which needs to be constructed when pulling it from the database). This isn't a bug or anything - it's expected behaviour and there are a few ways around it.

Might be worth trying to implement an alternative change tracking policy on the entities you want to log and seeing if that fixes things - I would guess that this behaviour (logging) doesn't kick in unless the entity state is dirty, which you can avoid by implementing change tracking yourself manually:

http://docs.doctrine-project.org/en/latest/cookbook/implementing-the-notify-changetracking-policy.html

Don't forget to update your entity:

YourBundle\Entity\YourThing:
    type: entity
    table: some_table
    changeTrackingPolicy: NOTIFY

See this thread:

https://github.com/Atlantic18/DoctrineExtensions/issues/333#issuecomment-16738878