0

我正在使用 Softdeleteable 学说过滤器,但是我有一种方法可以从数据库中删除所有记录,该方法应该在删除记录之前禁用过滤器。它似乎只在每隔一次运行时才起作用(一旦记录具有 deleteAt 值)。

<?php
/**
 * Created by PhpStorm.
 * User: toby
 * Date: 08/07/2014
 * Time: 17:29
 */

namespace Client\ComponentBundle\Entity;


use Doctrine\ORM\EntityRepository;

abstract class BaseEntityRepository extends EntityRepository
{
    /**
     * Attempts to delete all records from a table
     *
     * @param bool $bypassSoftDelete
     *
     * @return bool
     */
    public function deleteAll( $bypassSoftDelete = false )
    {
        $softdeleteableFilter = 'softdeleteable';
        $filters              = $this->getEntityManager()->getFilters();

        if ($bypassSoftDelete && $filters->isEnabled( $softdeleteableFilter )) {
            $filters->disable( $softdeleteableFilter );
        }

        $entities = $this->findAll();
        foreach ($entities as $entity) {
            $this->getEntityManager()->remove( $entity );
        }

        $this->getEntityManager()->flush();

        if ($bypassSoftDelete) {
            $this->getEntityManager()->getFilters()->enable( $softdeleteableFilter );
        }
    }
}

有人知道为什么会这样吗?

4

1 回答 1

1

As far as I know, the softdeleteable filter only adds stuff into your query for selects and what not, so enabling and/or disabling it before a remove doesn't really do anything.

The reason you are needing to do the 2 attempts to delete anything is because of this...

Gedmo\SoftDeleteable\SoftDeleteableListener

/**
 * If it's a SoftDeleteable object, update the "deletedAt" field
 * and skip the removal of the object
 *
 * @param EventArgs $args
 * @return void
 */
public function onFlush(EventArgs $args)
{
    //...

    //getScheduledDocumentDeletions
    foreach ($ea->getScheduledObjectDeletions($uow) as $object) {
        //...

        if (isset($config['softDeleteable']) && $config['softDeleteable']) {

            $reflProp = $meta->getReflectionProperty($config['fieldName']);
            $oldValue = $reflProp->getValue($object);

            <!-- THIS BIT -->
            if ($oldValue instanceof \Datetime) {
                continue; // want to hard delete
            }

            //...
        }
    }
}

The only thing that decides whether or not the object actually gets deleted is if it has been "softdeleted" previously. This mean that no matter what you do with the filter, the listener will first softdelete, followed by a hard delete on the next pass.

I guess the easiest way to get around this would be to set a date for your deletedAt (or your deletedAt field) prior to flushing the actual remove.

Extra Info

The ORM doesn't directly perform a DELETE operation that is replaced with an UPDATE.

When you remove a model the ORM schedules it for deletion, this is then intercepted by the listener and then persisted again with the updated deletedAt field set.

Assuming your fieldName is set to deletedAt

Gedmo\SoftDeleteable\SoftDeleteableListener

public function onFlush(EventArgs $args)
{
    //..

    // Get all entities that are scheduled for deletion
    foreach ($ea->getScheduledObjectDeletions($uow) as $object) {
        // Check softdeleteable is enabled for model
        if (isset($config['softDeleteable']) && $config['softDeleteable']) {
            // Get current value of deletedAt
            $reflProp = $meta->getReflectionProperty($config['fieldName']);
            $oldValue = $reflProp->getValue($object);

            // If deletedAt is already set, drop out of update process,
            // otherwise continue on with "softdelete"
            if ($oldValue instanceof \Datetime) {
                continue; // want to hard delete
            }

            // Dispatch "PRE_SOFT_DELETE" event
            $evm->dispatchEvent(
                self::PRE_SOFT_DELETE,
                $ea->createLifecycleEventArgsInstance($object, $om)
            );

            // Set deletedAt field to now
            $date = new \DateTime();
            $reflProp->setValue($object, $date);

            // Persist model and schedule for extra update, moving 
            // model from "scheduledForDeletion" to "scheduledForUpdate"
            $om->persist($object);
            $uow->propertyChanged($object, $config['fieldName'], $oldValue, $date);
            $uow->scheduleExtraUpdate($object, array(
                $config['fieldName'] => array($oldValue, $date)
            ));

            // Dispatch "POST_SOFT_DELETE" event
            $evm->dispatchEvent(
                self::POST_SOFT_DELETE,
                $ea->createLifecycleEventArgsInstance($object, $om)
            );
        }
    }
}
于 2014-08-22T08:43:25.717 回答