Reputation: 10781
I'm trying to figure out how to rollback the state of a changed entity while in the preUpdate
method (I'm using the annotation method if that makes a difference).
I've tried using the EntityManager::refresh($entity)
and while it does seem to revert the entity, it still goes ahead and saves the changes to the database.
I've read that I need to recalculate the change set by calling $em->getUnitOfWork()->computeChangeSet($em->getClassMetaData(get_class($this)), $this);
however this doesn't do the trick.
Is there anyway to get the UnitOfWork
to ignore the changes/re-calculate properly?
<?php
class Status extends Entity {
/**
* @PreUpdate
*/
public function preUpdate() {
if (!$this->canSave()) {
$this->reset();
}
}
public function reset() {
$em = self::getEntityManager();
$em->refresh($this);
$em->getUnitOfWork()
->computeChangeSet($em->getClassMetaData(get_class($this)), $this);
}
public function canSave() { return false; }
?>
<?php
// Bootstrap for testing/debugging
include 'common.php';
$log = \Zend_Registry::get('log');
$x = Status::find(31); // Retrieve entity from DB
$log->debug("Original: " . $x->getDateLastSeen() . "\n");
$x->setDateLastSeen(new \DateTime());
$log->debug("Set to: " . $x->getDateLastSeen() . "\n");
$x->save();
$log->debug("Saved to: " . $x->getDateLastSeen() . "\n");
Outputs:
2013-02-14T23:13:22+00:00 DEBUG (7): Original: 2013-02-14 23:08:22
2013-02-14T23:13:22+00:00 DEBUG (7): Set to: 2013-02-14 23:13:22
2013-02-14T23:13:22+00:00 DEBUG (7): Saved to: 2013-02-14 23:08:22
Everything looks okay, however when I look at my database log I see:
409705 Query UPDATE devices_statuses SET date_last_seen = '2013-02-14 23:13:22' WHERE id = 31
409705 Query commit
Upvotes: 1
Views: 2971
Reputation: 25440
This is already handled by the ORM itself (see https://github.com/doctrine/doctrine2/blob/2.3.2/lib/Doctrine/ORM/UnitOfWork.php#L970-L974 )
The problem here is that the DateTime
instance assigned to date_last_seen
(or better the field mapped to it) has a different object hash (check it with spl_object_hash()
).
For the ORM, this is a changeset. To effectively reset your instance, you will need to manually call Doctrine\ORM\UnitOfWork#clearEntityChangeSet(spl_object_hash($this))
.
Also, consider moving this code out of the entity into a dedicated event listener: your entity should not be aware of the EntityManager
or about the persistence layer in any way.
Upvotes: 2