The Soft Deleteable behavior allows you to "soft delete" objects by marking them as deleted with a timestamp instead of removing them from the database.
- Getting Started
- Configuring Soft Deleteable Objects
- Using Traits
- Working with Filters
- Bulk Delete Support
- Time-Aware Soft Deletion
- "Hard Delete" Soft Deleted Records
The soft deleteable behavior can be added to a supported Doctrine object manager by registering its event subscriber when creating the manager.
use Gedmo\SoftDeleteable\SoftDeleteableListener;
$listener = new SoftDeleteableListener();
// The $om is either an instance of the ORM's entity manager or the MongoDB ODM's document manager
$om->getEventManager()->addEventSubscriber($listener);When an entity is soft-deleted, it remains managed by Doctrine and can still be queried by its primary key as it stays
in the identity map.
To automatically remove such entities after a flush, enable the $handlePostFlushEvent option:
$listener = new SoftDeleteableListener(true);This detaches soft-deleted entities from the identity map but may cause issues if a deleted entity is still referenced
by another managed entity with cascade persist, as later flush() calls may treat it as new and attempt to re-insert
it.
Enable this option only if you need deleted entities to be fully detached after flushing.
To automatically filter out soft-deleted records from all queries, you need to register and enable the appropriate filter for your object manager.
use Doctrine\ORM\Configuration;
use Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter;
// Register the filter during configuration
$config = new Configuration();
$config->addFilter('soft-deleteable', SoftDeleteableFilter::class);
// Enable the filter (usually in your application bootstrap)
$em->getFilters()->enable('soft-deleteable');use Doctrine\ODM\MongoDB\Configuration;
use Gedmo\SoftDeleteable\Filter\ODM\SoftDeleteableFilter;
// Register the filter during configuration
$config = new Configuration();
$config->addFilter('soft-deleteable', SoftDeleteableFilter::class);
// Enable the filter (usually in your application bootstrap)
$dm->getFilterCollection()->enable('soft-deleteable');The soft deleteable extension can be configured with annotations, attributes, or XML configuration (matching the mapping of your domain models). The full configuration for annotations and attributes can be reviewed in the linked documentation.
The below examples show the basic configuration for the extension, marking a class as soft deleteable.
<?php
namespace App\Entity;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
#[ORM\Entity]
#[Gedmo\SoftDeleteable]
class Article
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: Types::INTEGER)]
public ?int $id = null;
#[ORM\Column(type: Types::STRING)]
public ?string $title = null;
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
public ?\DateTimeImmutable $deletedAt = null;
}<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
<entity name="App\Model\Article" table="articles">
<id name="id" type="integer" column="id">
<generator strategy="AUTO"/>
</id>
<field name="title" type="string"/>
<field name="deletedAt" type="datetime_immutable" nullable="true"/>
<gedmo:soft-deleteable field-name="deletedAt"/>
</entity>
</doctrine-mapping>Note
Support for annotations is deprecated and will be removed in 4.0.
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* @ORM\Entity
* @Gedmo\SoftDeleteable
*/
class Article
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
public ?int $id = null;
/**
* @ORM\Column(type="string")
*/
public ?string $title = null;
/**
* @ORM\Column(type="datetime_immutable", nullable=true)
*/
public ?\DateTimeImmutable $deletedAt = null;
}The soft deleteable extension supports the following field types for the deletion timestamp field:
- Date (
dateanddate_immutable) - Time (
timeandtime_immutable) - Date/Time (
datetimeanddatetime_immutable) - Date/Time with timezone (
datetimetzanddatetimetz_immutable) - Timestamp (
timestamp)
The soft deleteable extension provides traits which can be used to quickly add a deletion timestamp field, and optionally the mapping configuration, to your models. This trait is provided as a convenience for common configurations.
Gedmo\SoftDeleteable\Traits\SoftDeleteableadds a$deletedAtproperty with getter and setterGedmo\SoftDeleteable\Traits\SoftDeleteableDocumentadds a$deletedAtproperty with getters and setters and mapping annotations and attributes for the MongoDB ODMGedmo\SoftDeleteable\Traits\SoftDeleteableEntityadds a$deletedAtproperty with getters and setters and mapping annotations and attributes for the ORM
Once you have configured your soft deleteable objects and registered the appropriate filter, you can control the visibility of soft-deleted records using the filter system.
// Enable the filter to hide soft-deleted records (recommended for most use cases)
$em->getFilters()->enable('soft-deleteable');
// Disable the filter to show all records, including soft-deleted ones
$em->getFilters()->disable('soft-deleteable');
// Check if the filter is enabled
$isEnabled = $em->getFilters()->isEnabled('soft-deleteable');You can enable or disable the filter for specific object types using the enable and disable methods on the filter classes. For example, when using the ORM:
// Get the filter instance
$filter = $em->getFilters()->enable('soft-deleteable');
// Disable filtering for a specific entity (show all records, including soft-deleted)
$filter->disableForEntity(Article::class);
// Re-enable filtering for a specific entity
$filter->enableForEntity(Article::class);For MongoDB ODM users, replace "Entity" with "Document" in the method names (i.e. enableForDocument and disableForDocument).
Note
This feature is only available with the ORM.
The soft deleteable extension includes a query walker that automatically converts DQL DELETE statements into UPDATE statements that set the deletion timestamp, allowing you to perform bulk soft-deletion operations.
To use DQL DELETE queries with soft deleteable entities, you need to specify the SoftDeleteableWalker as a custom output walker:
use Doctrine\ORM\Query;
use Gedmo\SoftDeleteable\Query\TreeWalker\SoftDeleteableWalker;
// Create a DQL DELETE query
$query = $em->createQuery('DELETE FROM App\Entity\Article a WHERE a.category = :category');
$query->setParameter('category', $category);
// Set the query walker to convert the DELETE query to UPDATE
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, SoftDeleteableWalker::class);
// Execute the query
$query->execute();The soft deleteable extension supports "time-aware" deletion, where you can schedule objects for deletion at a future time.
#[ORM\Entity]
#[Gedmo\SoftDeleteable(timeAware: true)]
class Article
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: Types::INTEGER)]
public ?int $id = null;
#[ORM\Column(type: Types::STRING)]
public ?string $title = null;
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
public ?\DateTimeImmutable $deletedAt = null;
}// Schedule an article for deletion in the future
$article = new Article();
$article->setTitle('Scheduled for deletion');
$article->setDeletedAt(new \DateTimeImmutable('+1 week')); // Delete in 1 week
$em->persist($article);
$em->flush();
// The article will be visible now (deletion time hasn't passed)
$found = $em->getRepository(Article::class)->findOneBy(['title' => 'Scheduled for deletion']);
assert($found !== null); // Found because deletion time is in the future
// After the scheduled time passes, the article will be automatically filtered out
// (without needing to run any cleanup processes)By default, the soft deleteable extension allows soft deleted records to be "hard deleted" (fully removed from the database)
by deleting them a second time. However, by setting the hardDelete parameter in the configuration to false, you can
prevent soft deleted records from being deleted at all.