14

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 want to do this to:

  1. load entity that is soft-deleted
  2. remove entity from database entirely bypassing soft-delete filter

So how to disable it?

Aurelijus Rozenas
  • 2,176
  • 2
  • 28
  • 40

4 Answers4

32

1. How to load soft-deleted entity

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.

2. How to remove entity from database entirely

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:

Community
  • 1
  • 1
Aurelijus Rozenas
  • 2,176
  • 2
  • 28
  • 40
  • 5
    The filter is just a doctrine query so it has no real connection to the flushing process. A far easier way to hard delete would be to to run the the `$em->remove($object); $em->flush($object);` twice. The first flush would set the `deletedAt` to now. The second would recognise that the `deletedAt` has been set previously and will ignore actually delete - ass you can see here https://github.com/Atlantic18/DoctrineExtensions/blob/master/lib/Gedmo/SoftDeleteable/SoftDeleteableListener.php#L63-L71. – qooplmao Jul 05 '16 at 08:19
  • @qooplmao I tried this with latest tag (2.4.13) and it does not work. Maybe only with master branch now. – Aurelijus Rozenas Jul 08 '16 at 08:42
  • @qooplmao Your method works perfectly well. I think you should post it as an answer, as I ended up ignoring it the first time. Aurelijus' answer is informative, but ultimately unnecessary. I tried it with v2.5.5. – aalaap Jan 06 '17 at 07:19
  • If it doesn't work try "soft-deleteable" instead of "softdeleteable". So it should be: `$em->getFilters()->disable('soft-deleteable');` – Luco Nov 09 '18 at 18:53
3

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);
Sebastian Viereck
  • 5,455
  • 53
  • 53
1

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:

Mirgen
  • 140
  • 3
  • 18
-3

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...