baptistedonaux
2/19/2015 - 11:32 AM

Soft Delete Symfony/Doctrine

Soft Delete Symfony/Doctrine

# src/namespace/mybundle/Resources/config/services.yml
services:
    kernel.listener.doctrine:
        class: Namespace\MyBundle\Listener\DoctrineListener
        public: false
        tags:
            - { name: doctrine.event_listener, event: preFlush, method: preFlush }
# app/config/config.yml
doctrine:
    orm:
        filters:
            deleted:
                class: 'Namespace\MyBundle\Repository\Filters\DeletedFilter'
                enabled: true
<?php
namespace Namespace\MyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

class Entity
{
    /**
     * @var datetime $deletedAt
     *
     * @ORM\Column(name="deletedAt", type="datetime", nullable=true)
     */
    private $deletedAt;

    /**
     * Set deletedAt
     *
     * @param  \DateTime $deletedAt
     * @return Plan
     */
    public function setDeletedAt($deletedAt)
    {
        $this->deletedAt = $deletedAt;

        return $this;
    }

    /**
     * Get deletedAt
     *
     * @return \DateTime
     */
    public function getDeletedAt()
    {
        return $this->deletedAt;
    }
}
<?php
namespace Namespace\MyBundle\Listener;

use Doctrine\ORM\Event\PreFlushEventArgs;

class DoctrineListener
{
    public function preFlush(PreFlushEventArgs $event) {
        $em = $event->getEntityManager();

        foreach ($em->getUnitOfWork()->getScheduledEntityDeletions() as $object) {
            if (method_exists($object, "getDeletedAt")) {
                if ($object->getDeletedAt() instanceof \Datetime) {
                    continue;
                } else {
                    $object->setDeletedAt(new \DateTime());
                    $em->merge($object);

                    $em->persist($object);
                }
            }
        }
    }
}
<?php
namespace Namespace\MyBundle\Repository\Filters;

use Doctrine\ORM\Mapping\ClassMetaData;
use Doctrine\ORM\Query\Filter\SQLFilter;

class DeletedFilter extends SQLFilter
{
    public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
    {
        if ($targetEntity->hasField("deletedAt")) {
            $date = date("Y-m-d h:m:s");

            return $targetTableAlias.".deletedAt < '".$date."' OR ".$targetTableAlias.".deletedAt IS NULL";
        }

        return "";
    }
}