web-dev-qa-db-ja.com

symfonyでdoctrineのソフト削除(ソフト削除可能)フィルターを無効にする方法

Doctrine 2のSoftDeleteable動作拡張機能のインストールと使用は非常に簡単です。問題は通常、一部のコード部分でそれを無効にして再度有効にすることです。これを行うと、次のことができます。

  1. ソフト削除されたエンティティをロードする
  2. ソフト削除フィルターを完全にバイパスしてデータベースからエンティティを削除する

それを無効にする方法は?

13

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

参照:

20

サービスを使用して、ソフト削除フィルターの動作を無効化および再有効化できます。

<?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_はデフォルトでtrueです

これにより、リスナー/フィルターを無効にする必要はありません。 _hardDelete=false_を使用している場合、上記の二重削除は機能しません。

ソース:

0
Mirgen

以前のコメント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();

チャームのように機能するので、少しボットをもっと見やすくするために、もう一度投稿しました...

0