可软删除行为和真正删除实体

12

我正在使用DoctrineExtensionsStofDoctrineExtensionsBundle来获取软删除行为。

在我的应用程序前端,它的运行非常良好。

在后端,我需要选项来“硬”删除实体。

我已经在我的管理控制器中禁用了过滤器(我使用的是SonataAdmin):

$filters = $this->getModelManager()->getEntityManager($this->getClass())->getFilters();

if (array_key_exists('softdeleteable', $filters->getEnabledFilters())) {
    $filters->disable('softdeleteable');
}

这样做是有效的(软删除的实体会显示在列表中),但是当我尝试删除它时,实体确实再次被软删除了。我该如何强制进行“硬”删除?

4个回答

13

你不需要禁用过滤器 - 它只是在选择记录时用于过滤记录。相反,你必须禁用监听器:

// $em is your EntityManager
foreach ($em->getEventManager()->getListeners() as $eventName => $listeners) {
    foreach ($listeners as $listener) {
        if ($listener instanceof \Gedmo\SoftDeleteable\SoftDeleteableListener) {
            $em->getEventManager()->removeEventListener($eventName, $listener);
        }
    }
}

然后调用

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

在此之后,您如何重新启用它? - Jessica
@Jessica,你可以使用addEventListener函数。http://api.symfony.com/2.4/Symfony/Bridge/Doctrine/ContainerAwareEventManager.html#method_addEventListener - Dmytro
非常感谢,我的做法是存储我删除的任何事件的名称,然后循环遍历它们并重新添加。 - Jessica
如果您的实体管理器拥有更多操作,那么它们都将被硬删除,个人而言,我不喜欢这种选择。当您只执行一个实体的删除操作时,它是有用的,但不适合多个操作。(例如:$ customEntityManager-> softDelete($a); $ customEntityManager-> hardDelete($b); $ customEntityManager-> flush();)两者都将被硬删除。 - Gonzalo1987
这看起来非常繁琐,而且用户体验很差。 - Toskan

7

启用软删除后,无需创建监听器或其他内容即可进行永久删除。

原始的软删除事件包含此行:

$reflProp = $meta->getReflectionProperty($config['fieldName']);
$oldValue = $reflProp->getValue($object);
if ($oldValue instanceof \Datetime) {
    continue; // want to hard delete
}

所有这些意味着,如果您:
$entity->setDeletedAt(new \Datetime());
$em->flush();

然后:
$em->remove($entity);
$em->flush();

在那时,它将被永久删除。

如果你在调用 ->remove($entity) 后的 ->flush() 中已经有一个有效的日期存在于 deletedAt 字段中,你的实体将会被永久删除。


同意。但这是一种不好的行为,对吗?至少完全不透明。“天哪,我在我的实体上调用了两次REMOVE OMG OMG”... - Toskan

3

这不是最优雅的方法:你总是可以使用 SQL 进行真正的删除,它会绕过软删除

$em->createQuery("DELETE MyEntity e WHERE e = :et")->setParameter('et',$entity)->execute();

不够优雅?我认为还好,不是吗?只需将其作为一个函数添加到存储库中即可。这比双重删除->硬删除更透明。 - Toskan

0

虽然这个问题有点老,但也许对某些人有用:

创建自己的事件监听器可能是更好的解决方案:

class SoftDeleteableListener extends BaseSoftDeleteableListener
{

/**
 * @inheritdoc
 */
public function onFlush(EventArgs $args)
{
    $ea = $this->getEventAdapter($args);
    $om = $ea->getObjectManager();
    //return from event listener if you disabled filter: $em->getFilters()->disable('softdeleteable');
    if (!$om->getFilters()->isEnabled('softdeleteable')) {
        return;
    }

    parent::onFlush($args);
}

}

并在您的配置文件中添加:

gedmo.listener.softdeleteable:
    class: AppBundle\EventListener\SoftDeleteableListener
    tags:
        - { name: doctrine.event_subscriber, connection: default }
    calls:
        - [ setAnnotationReader, [ @annotation_reader ] ]

来源:https://github.com/Atlantic18/DoctrineExtensions/issues/1175


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