7

Is it possible to compare the state of an entity object between the current "dirty" version (an object that has some of its properties changed, not yet persisted) and the "original" version (the data still in the database).

My assumption was that I could have a "dirty" object, then pull a fresh one from the DB and compare the two. For instance:

$entity = $em->getRepository('MyContentBundle:DynamicContent')->find($id);

$editForm = $this->createContentForm($entity);
$editForm->bind($request);

if ($editForm->isValid()) {
    $db_entity = $em->getRepository('MyContentBundle:DynamicContent')->find($id);

    // compare $entity to $db_entity

    $em->persist($entity);
    $em->flush();

    return $this->redirect($this->generateUrl('content_edit', array('id' => $id)));
}

But in my experience, $entity and $db_entity are always the same object (and have the same data as $entity, after the form $request bind). Is there a way to get a fresh version of the $entity alongside the "dirty" version for comparison's sake? The solutions I've seen all pull the needed data before the form bind happens, but I'd rather not have that limitation.

Update: To clarify, I'm looking not only for changes to the entities' properties but also its related collections of entities.

Dave Lancea
  • 1,669
  • 1
  • 16
  • 19
  • I ask specifically so Ican make a better solution to removing items from a Symfony2 form collection. [The current solution](http://symfony.com/doc/2.0/cookbook/form/form_collections.html#templates-modifications) where you pull the values before the bind seems too limiting and not conducive to making a nice function to handle it. – Dave Lancea Mar 13 '13 at 14:54
  • This is a duplicate of http://stackoverflow.com/questions/9057558/any-built-in-way-to-get-all-the-changed-fields-in-doctrine-2/9057705#9057705 – Ocramius Mar 13 '13 at 15:20
  • I should expand the scope of my question, since I'm not just looking for changes to the entity itself, but also changes to the related collections within the entity. Using UnitOfWork only helps with the former. However, its looking like Alex's suggestion of using $em->clear() before doing another find() will get the "fresh" entity I'm looking for. – Dave Lancea Mar 13 '13 at 15:40
  • that's not possible outside of the flush cycle (without losing your currently managed entities) You may want to check http://stackoverflow.com/questions/15281614/how-can-i-tell-if-the-current-transaction-will-change-any-entities-with-doctrine/15374589 – Ocramius Mar 13 '13 at 15:48
  • You won't be able to get more than what I answered in a non dirty way... – Gmajoulet Mar 13 '13 at 17:39

2 Answers2

12

You can get what has changed on the entity through Doctine's UnityOfWork. It is quite simple : after you persisted the entity, Doctrine knows what to update in the database. You can get these informations by doing :

// Run these AFTER persist and BEFORE flush
$uow = $em->getUnitOfWork();
$uow->computeChangeSets();
$changeset = $uow->getEntityChangeSet($entity);
Gmajoulet
  • 700
  • 4
  • 8
  • 1
    Can this be called in a controller? Because when I attempt this, it does not show any changes for my entity (just empty array). – Chadwick Meyer Jul 14 '14 at 23:47
  • 2
    Be sure you read the warning related to this method in this post: http://stackoverflow.com/questions/9057558/is-there-a-built-in-way-to-get-all-of-the-changed-updated-fields-in-a-doctrine-2 – tiho Feb 09 '15 at 03:25
7

After you flush the $em it happens (it is commited) in database.. so... you might want to retrieve the $db_entity before flush()


  1. I am not sure what you want.. but you can also use merge instead of persist.

    • merge is returning the object modified - id generated and setted
    • persist is modifying your instance
  2. If you want to have the object modified and not persisted use it before flush.

  3. EntityManager is giving you the same instance because you didn't $em->clear()
    • flush is commiting all changes (all dirty objects)
    • clear is clearing memory cache. so when you find(..., $id) , you will get a brand new instance
  4. Is clone keyword working for you? like in this example:

$entity = $em->find('My\Entity', $id);
$clonedEntity = clone $entity;

And you might also want to read this: Implementing Wakeup or Clone

Alex
  • 2,126
  • 3
  • 25
  • 47
  • Whoops, my example was bad and I've updated it. The $db_entity should be retrieved before the persist() and flush(). Even when doing that, $entity and $db_entity are the same. – Dave Lancea Mar 13 '13 at 15:14
  • added another solution to my post (the `clone` part) – Alex Mar 13 '13 at 17:51