duanchuopi2298 2014-08-21 20:19
浏览 50

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

I'm using the Softdeleteable doctrine filter, however I have a method to remove all records from the database that should disable the filter before removing records. It only seems to work every other time it's run though (once the records have deletedAt values).

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

Anyone any idea why this might be the case?

  • 写回答

1条回答 默认 最新

  • duanhuilao0787 2014-08-22 08:43
    关注

    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...

    <kbd>Gedmo\SoftDeleteable\SoftDeleteableListener</kbd>

    /**
     * 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

    <kbd>Gedmo\SoftDeleteable\SoftDeleteableListener</kbd>

    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)
                );
            }
        }
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 关于大棚监测的pcb板设计
  • ¥15 stm32开发clion时遇到的编译问题
  • ¥15 lna设计 源简并电感型共源放大器
  • ¥15 如何用Labview在myRIO上做LCD显示?(语言-开发语言)
  • ¥15 Vue3地图和异步函数使用