doctrine/mongodb-odm-softdelete-bundle
Installation:
appKernel.php (Symfony 2.0.x only).deleted_field_name in config.yml (e.g., deletedAt).Doctrine\ODM\MongoDB\SoftDelete is autoloaded.First Use Case:
@SoftDelete:
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Doctrine\ODM\MongoDB\SoftDelete\SoftDelete;
/**
* @MongoDB\Document
* @SoftDelete
*/
class User {}
$user = $dm->getRepository('AppBundle:User')->find(1);
$user->delete(); // Triggers soft-delete (sets `deletedAt` to current timestamp)
$dm->getRepository('AppBundle:User')->findAll(); // Excludes soft-deleted by default
$dm->getRepository('AppBundle:User')->findAllWithDeleted(); // Includes soft-deleted
Soft-Deletion in Controllers:
// Soft-delete a user
$user = $dm->find('AppBundle:User', $id);
$user->delete(); // Sets `deletedAt` without removing from DB
$dm->flush();
// Restore a soft-deleted user
$user = $dm->getRepository('AppBundle:User')->findWithDeleted($id);
$user->setDeletedAt(null); // Explicitly restore
$dm->flush();
Querying with Soft-Deletes:
$users = $dm->getRepository('AppBundle:User')->findAll();
$users = $dm->getRepository('AppBundle:User')->findAllWithDeleted();
$query = $dm->createQueryBuilder('AppBundle:User')
->field('deletedAt')->equals(null) // Explicitly filter
->getQuery();
Bulk Soft-Deletion:
$users = $dm->getRepository('AppBundle:User')->findBy(['active' => true]);
foreach ($users as $user) {
$user->delete();
}
$dm->flush();
Event Listeners:
// In a service or listener
$user->addPreDeleteListener(function ($user) {
// Log or send notifications before soft-delete
});
Symfony Forms:
SoftDelete with DataTransformer to handle soft-deletion in forms.$form->add('softDelete', CheckboxType::class, [
'mapped' => false,
'label' => 'Soft Delete',
]);
Then manually handle the soft-delete logic in the form submit handler.APIs:
deleted flag:
$user = $dm->getRepository('AppBundle:User')->findWithDeleted($id);
$data = [
'id' => $user->getId(),
'deleted' => $user->getDeletedAt() !== null,
];
Testing:
$user = new User();
$user->delete(); // Simulate soft-delete
$this->assertNotNull($user->getDeletedAt());
Symfony 2.0.x Only:
stof/doctrine-extensions-bundle for modern setups).Missing deletedAt Field:
deletedAt field is not defined in your document, soft-delete will fail silently. Ensure your document has:
/**
* @MongoDB\Field(type="date")
*/
private $deletedAt;
Query Caching Issues:
@Cache), ensure your cache invalidation logic accounts for soft-deletes.Repository Method Confusion:
findAllWithDeleted() is not a standard Doctrine method. Use:
$dm->getRepository('AppBundle:User')->createQueryBuilder()
->getQuery()
->execute();
Or extend the repository to add custom methods.Transaction Rollbacks:
deletedAt field may be left in an inconsistent state. Always wrap in transactions:
$dm->beginTransaction();
try {
$user->delete();
$dm->flush();
$dm->commit();
} catch (\Exception $e) {
$dm->rollBack();
throw $e;
}
Check for Silent Failures:
deletedAt field directly:
$user = $dm->find('AppBundle:User', $id);
var_dump($user->getDeletedAt()); // Should return a DateTime or null
Enable Doctrine Logging:
config.yml to debug queries:
doctrine_mongodb:
logging: true
deletedAt filters).Field Name Mismatch:
deleted_field_name in config.yml matches your document’s field (e.g., deletedAt).Custom Soft-Delete Logic:
delete() method in your document:
public function delete()
{
$this->setDeletedAt(new \DateTime());
// Add custom logic (e.g., log deletion)
}
Add Soft-Delete to Existing Documents:
trait SoftDeletable
{
public function delete()
{
$this->setDeletedAt(new \DateTime());
}
}
Then use it in your document:
use Doctrine\ODM\MongoDB\SoftDelete\SoftDeletable;
class User {
use SoftDeletable;
// ...
}
Global Soft-Delete Filter:
$dm->getEventManager()->addEventListener(
'preFind',
function ($event) {
$query = $event->getQuery();
$query->field('deletedAt')->equals(null);
}
);
Alternative Field Names:
deleted_field_name in config.yml to match your preference (e.g., isDeleted as a boolean):
doctrine_mongodb_softdelete:
deleted_field_name: isDeleted
Then update your document to handle boolean logic.How can I help you explore Laravel packages today?