SoftDeletable
Soft delete: remove() does not delete the row but stores the deletion time in deletedAt.
Entity
use Doctrine\ORM\Mapping as ORM;
use Ufo\DoctrineBehaviors\Contract\Entity\SoftDeletableInterface;
use Ufo\DoctrineBehaviors\Model\SoftDeletable\SoftDeletableTrait;
#[ORM\Entity]
class Category implements SoftDeletableInterface
{
use SoftDeletableTrait;
#[ORM\Id, ORM\GeneratedValue, ORM\Column]
private ?int $id = null;
}
The bundle maps deletedAt (datetime, nullable).
How it works
In onFlush every SoftDeletableInterface entity scheduled for deletion gets delete() (the current time in deletedAt) and is persisted again — an UPDATE runs instead of DELETE.
There is no query filter: find(), repositories and DQL return "deleted" entities too. Filter them out yourself — with a deletedAt IS NULL condition or an isDeleted() check.
Doctrine performs cascade removal of related entities as usual: only those that also implement SoftDeletableInterface are soft-deleted.
Usage
$entityManager->remove($category);
$entityManager->flush();
$category = $categoryRepository->find($id); // the entity is still there
$category->isDeleted(); // true
Restore
$category->restore(); // deletedAt = null
$category->isDeleted(); // false
$entityManager->flush();
Delete at a given time
$category->setDeletedAt(new \DateTime('+1 day'));
$category->isDeleted(); // false — until the date comes
$category->willBeDeleted(); // true
$entityManager->flush();
| Method | Returns |
|---|---|
isDeleted() |
true if deletedAt is set and has already come |
willBeDeleted(?DateTimeInterface $at = null) |
true if deletedAt is set (and, when $at is passed, not later than it) |
getDeletedAt() |
?DateTimeInterface |