Soft delete implementation on Doctrine


We need to change Doctrine 2 remove() method so it wont delete record, instead we add flag or timestamp on some field, marking it deleted , 1 year ago

We need to change Doctrine 2 remove() method so it wont delete record, instead we add flag or timestamp on some field, marking it deleted

There are three things we need to create or change, the first one is the entity, we need to add property, setter and getter for the deletion flag field, create Doctrine Event Subscriber and Doctrine SQL Filter. In this tutorial, im using User entity as sample and deletion flag will contain date time of the deletion, not boolean true or false.

Add Flag Field to Entity

I use the flag on several entities, so I create a trait instead of adding property, setter and getter to several entities. To use it, just add Use trait name on entities

trait SoftDelete
{
    /**
     * @Column(name="deletedAt", type="datetime", nullable=true)
     */
    private $deletedAt;
    
    public function getDeletedAt()
    {
        return $this->deletedAt;
    }

    public function setDeletedAt($deletedAt)
    {
        $this->deletedAt = $deletedAt;
    }
}

Event Subscriber

This class will subscribe to Doctrine event, particulary the pre flush on flush event. This class will subscribe, and on deletion of some record on entity (remove), it will update some field and persist the entity.

use Doctrine\ORM\Events;
use Doctrine\Common\EventSubscriber;
use Doctrine\Common\EventManager;

class DeleteEventSubscriber implements EventSubscriber
{
    public function preFlush(PreFlushEventArgs $args)
    {
        $em  = $args->getEntityManager();
        $uow = $em->getUnitOfWork();

        foreach ($uow->getScheduledEntityDeletions() as $deletedEntity) 
        {   
            // only for this entity
            if ($deletedEntity instanceof Entity\User) 
            {
                // set deleted date time
                $deletedEntity->setDeletedAt(new \DateTime('now'));
                $em->persist($deletedEntity);
            }
        }
    }

    public function getSubscribedEvents()
    {
        return array(Events::preFlush);
    }
}

Add the Event Subsciber class into event manager, before create an Entity Manager.

$evm = new EventManager();
$eventSubscriber = new DeleteEventSubscriber();
$evm->addEventSubscriber($eventSubscriber);

// Create EntityManager
$this->em = EntityManager::create($connectionOptions, $config, $evm);

After this subscriber successfully implemented to Doctrine, removing record will add date time on deletedAt field instead of deleting it. And you can call remove() method as usual

$this->em->remove($user);
$this->em->flush();

Doctrine SQL Filter

This filter will filter query to entities and add where deletedAt is null. Still TODO now :D