Force delete doctrine entity when using SoftDeleta

2019-02-28 17:37发布

I'm using SoftDeletable trait in entities from https://github.com/KnpLabs/DoctrineBehaviors/#softDeletable It's working fine, but sometimes I'd like to force delete the entity. How can I do that?

When I use $em->remove($entity), it gets soft-deleted but I need to remove it completely from the database.

4条回答
做个烂人
2楼-- · 2019-02-28 17:56

I have writte 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
     */
    private $eventName;

    /**
     * @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 === 'onFlush') {
                        $this->eventName = $eventName;
                        $this->originalEventListener = $listener;
                        $em->getEventManager()->removeEventListener($eventName, $listener);
                    }
                }
            }
        }
    }

    /**
     * @param EntityManagerInterface $em
     */
    public function undoRemoveSoftDeleteFilter(EntityManagerInterface $em)
    {
        if (empty($this->originalEventListener) || empty($this->eventName)) {
            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($this->eventName, $this->originalEventListener);
    }
}

usage:

$this->softDeleteFilter->removeSoftDeleteFilter($this->entityManager);
$this->entityManager->remove($issue);
$this->entityManager->flush();
$this->softDeleteFilter->undoRemoveSoftDeleteFilter($this->entityManager);
查看更多
Root(大扎)
3楼-- · 2019-02-28 18:08

Just remove the subscriber from the EventManager and add it back after the remove() / flush() operation.

// get the event-manager
$eventManager = $this->get('doctrine')->getEventManager();

// get the listener
$subscriber = $this->get('knp.doctrine_behaviors.softdeletable_subscriber');

// remove the the subscriber for all events
$eventManager->removeEventListener($subscriber->getSubscribedEvents(), $subscriber);

// remove the entity
$em->remove($entity);
$em->flush();

// add it back to the event-manager
$eventManager->addEventSubscriber($subscriber);
查看更多
叼着烟拽天下
4楼-- · 2019-02-28 18:16

I found simple solution. Entity will be softdeleted at first, but if it is already been soft deleted it will be hard deleted so my simple solution was:

$entity->setDeletedAt(new DateTime());
$entityManager->remove($entity);
$entityManager->flush();

Of course you need to disable 'softdelete' filter first and deletedAt is a sofdelete field.

查看更多
你好瞎i
5楼-- · 2019-02-28 18:21

Since nifr's answer doesn't work anymore in the current version of the behaviors, I had a deeper look at the problem and got to that solution:

$em = $this->getDoctrine()->getManager();

// initiate an array for the removed listeners
$originalEventListeners = array();

// cycle through all registered event listeners
foreach ($em->getEventManager()->getListeners() as $eventName => $listeners) {
    foreach ($listeners as $listener) {
        if ($listener instanceof Knp\DoctrineBehaviors\ORM\SoftDeletable\SoftDeletableSubscriber) {

            // 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($entity);
$em->flush();

// re-add the removed listener back to the event-manager
foreach ($originalEventListeners as $eventName => $listener) {
    $em->getEventManager()->addEventListener($eventName, $listener);
}

See also https://stackoverflow.com/a/22838467/2564552

查看更多
登录 后发表回答