Installing and using SoftDeleteable behavior extension for Doctrine 2 is quite easy. The problem usually is trying to disable it for some code part and enabling again. You may w
As per the documentation, disable filter for entity manager:
$em->getFilters()->disable('softdeleteable');
$object = $em->find('AppBundle:Object', 1); // soft-deleted entity will be loaded
To enable soft-delete again:
$em->getFilters()->enable('softdeleteable');
Note: $em->clear();
may be required before this line, if entity was already loaded with disabled soft-delete filter.
Even though it is not mentioned in documentation, the first solution does not work if you need to remove entity and bypass soft-delete filter. Filter needs to be removed from entity manager's event listeners:
// initiate an array for the removed listeners
$originalEventListeners = [];
// cycle through all registered event listeners
foreach ($em->getEventManager()->getListeners() as $eventName => $listeners) {
foreach ($listeners as $listener) {
if ($listener instanceof \Gedmo\SoftDeleteable\SoftDeleteableListener) {
// store the event listener, that gets removed
$originalEventListeners[$eventName] = $listener;
// remove the SoftDeletableSubscriber event listener
$em->getEventManager()->removeEventListener($eventName, $listener);
}
}
}
// remove the entity
$em->remove($object);
$em->flush($object); // or $em->flush();
// re-add the removed listener back to the event-manager
foreach ($originalEventListeners as $eventName => $listener) {
$em->getEventManager()->addEventListener($eventName, $listener);
}
References:
Just a small reminder.
When you want to hard delete entity with Gedmo Softdeletable you have to have hardDelete=true
in the respective annotation, see:
@Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false, hardDelete=true)
EDIT: hardDelete=true
is true by default
With this, you dont have to disable the listener/filter. If you have hardDelete=false
, the double remove suggested above will not work.
Source:
You can use a service to disable and reenable the soft delete filter behaviour:
<?php
namespace App\Util;
use Doctrine\ORM\EntityManagerInterface;
use Gedmo\SoftDeleteable\SoftDeleteableListener;
class SoftDeleteFilter
{
/**
* @var string
*/
const EVENT_NAME = 'onFlush';
/**
* @var object
*/
private $originalEventListener;
/**
* @param EntityManagerInterface $em
*/
public function removeSoftDeleteFilter(EntityManagerInterface $em)
{
foreach ($em->getEventManager()->getListeners() as $eventName => $listeners) {
foreach ($listeners as $listener) {
if ($listener instanceof SoftDeleteableListener) {
if ($eventName === self::EVENT_NAME) {
$this->originalEventListener = $listener;
$em->getEventManager()->removeEventListener($eventName, $listener);
}
}
}
}
}
/**
* @param EntityManagerInterface $em
*/
public function undoRemoveSoftDeleteFilter(EntityManagerInterface $em)
{
if (empty($this->originalEventListener)) {
throw new \Exception('can not undo remove, soft delete listener was not removed');
}
// re-add the removed listener back to the event-manager
$em->getEventManager()->addEventListener(self::EVENT_NAME, $this->originalEventListener);
}
}
usage:
$this->softDeleteFilter->removeSoftDeleteFilter($this->entityManager);
$this->entityManager->remove($entity);
$this->entityManager->flush();
$this->softDeleteFilter->undoRemoveSoftDeleteFilter($this->entityManager);
As in a former comment by qooplmao posted: A simple and working solution is:
// Remove an entity entirely from the DB (skip soft delete)
$this->entityManager->remove($entity);
$this->entityManager->flush();
// Just run it a second time :-)
$this->entityManager->remove($entity);
$this->entityManager->flush();
Just posted it again to give it a little bot more visibility as it works like a charme...