如何在Symfony中为Doctrine禁用软删除(Soft-deleteable)过滤器

14

安装和使用Doctrine 2的SoftDeleteable行为扩展非常容易。问题通常在于尝试禁用它以用于某些代码部分,然后再次启用。您可能想要这样做来:

  1. 加载已软删除的实体
  2. 完全从数据库中删除实体,绕过软删除过滤器

那么如何禁用它呢?

4个回答

33

1. 如何加载软删除实体

根据文档,禁用实体管理器的筛选器:

$em->getFilters()->disable('softdeleteable');
$object = $em->find('AppBundle:Object', 1); // soft-deleted entity will be loaded
重新启用软删除的方法如下:
$em->getFilters()->enable('softdeleteable');

注意:$em->clear(); 如果实体已经使用禁用软删除过滤器加载,则在此行之前可能需要清除。

2.如何完全从数据库中移除实体

尽管文档没有提到,但如果您需要删除实体并绕过软删除过滤器,第一种解决方案不起作用。需要从实体管理器的事件侦听器中删除过滤器:

// 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);
}

参考资料:


5
该过滤器只是一个Doctrine查询,因此它与刷新过程没有真正的连接。更简单的硬删除方法是运行 $em->remove($object); $em->flush($object); 两次。第一次刷新会将 deletedAt 设置为现在。第二次刷新将识别先前已设置 deletedAt 并将忽略实际删除 - 正如您可以在这里看到的 https://github.com/Atlantic18/DoctrineExtensions/blob/master/lib/Gedmo/SoftDeleteable/SoftDeleteableListener.php#L63-L71。 - qooplmao
@qooplmao 我尝试使用最新的标签(2.4.13),但它不起作用。也许现在只能使用主分支。 - Aurelijus Rozenas
@qooplmao 您的方法非常有效。我认为您应该把它发布为答案,因为第一次我忽略了它。Aurelijus的答案很详细,但最终是不必要的。我已经在v2.5.5中尝试过了。 - aalaap
如果不起作用,请尝试使用“soft-deleteable”而不是“softdeleteable”。因此,应该是:$em->getFilters()->disable('soft-deleteable'); - Luco

3

你可以使用服务来禁用和重新启用软删除筛选器行为:

<?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);
    }
}

使用方法:

$this->softDeleteFilter->removeSoftDeleteFilter($this->entityManager);
$this->entityManager->remove($entity);
$this->entityManager->flush();
$this->softDeleteFilter->undoRemoveSoftDeleteFilter($this->entityManager);

1

小提醒:

如果您想使用Gedmo Softdeletable硬删除实体,则必须在相应注释中设置hardDelete=true,请参见:

@Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false, hardDelete=true)

编辑:hardDelete=true默认为真

有了这个,您就不必禁用监听器/过滤器。 如果您设置了hardDelete=false,则上面建议的双重删除将无法正常工作。

来源:


1
然而,默认情况下hardDelete为真。 - Aurelijus Rozenas

-3

正如之前的评论所述,由qooplmao发布:一个简单且有效的解决方案是:

// 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();

我再次发布它,以便让更多人看到,因为它像魔法一样运行...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接