Symfony2 / Doctrine - 禁用Softdeleteable过滤器每隔一次只能工作

时间:2014-08-21 20:19:57

标签: php symfony filter doctrine soft-delete

我使用的是Softdeleteable doctrine过滤器,但我有一种方法可以删除数据库中所有应该在删除记录之前禁用过滤器的记录。它似乎每隔一段时间运行一次(一旦记录删除了它的值)。

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

任何人都知道为什么会出现这种情况?

1 个答案:

答案 0 :(得分:1)

据我所知,softdeleteable过滤器只会在查询中添加内容以供选择和不选择,因此在删除之前启用和/或禁用它并不会真正做任何事情。

你需要做2次尝试删除任何东西的原因是因为......

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
            }

            //...
        }
    }
}

决定对象是否实际被删除的唯一因素是它是否已被&#34; softdeleted&#34;先前。这意味着无论你使用过滤器做什么,听众都将首先进行软删除,然后在下一次传递中进行硬删除。

我想解决此问题的最简单方法是在刷新实际删除之前为deletedAt(或您的deletedAt字段)设置日期。

额外信息

ORM不会直接执行替换为UPDATE的DELETE操作。

删除模型后,ORM会将其计划删除,然后由侦听器拦截,然后再次使用更新的deletedAt字段集进行保留。

假设您的fieldName设置为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)
            );
        }
    }
}