doctrine/mongodb-odm-softdelete
Adds soft delete support to Doctrine MongoDB ODM. Mark documents as deleted without removing them, with automatic filtering of deleted records from queries and options to restore or include trashed documents. Integrates cleanly with ODM repositories and event system.
Installation Add the package via Composer:
composer require doctrine/mongodb-odm-softdelete
Ensure doctrine/mongodb-odm is also installed (v2.x+ recommended).
Enable Soft Deletes
Extend your document with SoftDeletable trait:
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Doctrine\ODM\MongoDB\SoftDelete\SoftDeletable;
#[MongoDB\Document]
class User
{
use SoftDeletable;
// ...
}
First Use Case Soft-delete a record:
$user = $dm->find(User::class, $id);
$user->delete(); // Soft-deletes (sets `deletedAt` timestamp)
Query soft-deleted records:
$deletedUsers = $dm->createQueryBuilder(User::class)
->field('deletedAt')->exists(true)
->getQuery()
->execute();
Soft Delete + Restore
// Soft-delete
$user->delete();
// Restore (set `deletedAt` to null)
$user->restore();
Querying Soft-Deleted Records
Use SoftDeleteQueryBuilder for filtered queries:
$qb = $dm->createQueryBuilder(User::class)
->where('deletedAt')->exists(false); // Only active records
Bulk Soft Deletes
$qb = $dm->createQueryBuilder(User::class)
->field('status')->equals('inactive');
$users = $qb->getQuery()->execute();
foreach ($users as $user) {
$user->delete();
}
$dm->flush();
onSoftDelete/onSoftRestore via Doctrine events.Missing deletedAt Field
Ensure your document has a deletedAt field (auto-generated by the trait):
#[MongoDB\Field(type: 'date')]
protected ?\DateTimeInterface $deletedAt = null;
Query Performance
Avoid exists(false) on large collections—index deletedAt for speed:
#[MongoDB\Index(name: 'deletedAt_idx', fields: ['deletedAt' => 'asc'])]
Manual Deletion
Calling $dm->remove($user) bypasses soft-delete. Use $user->delete() instead.
deletedAt: Verify timestamps are set correctly in MongoDB.$qb->getQuery()->getDebugQuery() to inspect generated queries.Custom Fields
Override getDeletedAtField() to use a different field name.
Custom Logic
Extend SoftDeletable trait or use events to add pre/post-delete logic.
Time Zones
Ensure deletedAt uses UTC to avoid timezone-related issues.
How can I help you explore Laravel packages today?