Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Doctrine Cascade Soft Delete Bundle Laravel Package

wernerdweight/doctrine-cascade-soft-delete-bundle

wernerdweight/doctrine-cascade-soft-delete-bundle adds cascade soft-delete support to Doctrine entities in Symfony, helping related records be marked as deleted alongside their parent while respecting entity associations and configurable cascade behavior.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Confirm the layer you're building on. This bundle is a thin Symfony wrapper around soft-delete cascade behavior; it assumes gedmo/doctrine-extensions (SoftDeleteable filter/listener) is already installed and configured on your entities. Set that up first — the bundle does nothing useful without an active soft-delete extension.
  2. Install: composer require wernerdweight/doctrine-cascade-soft-delete-bundle. Given the last release is February 2023 and there are no dependents, verify the doctrine/orm, symfony/framework-bundle, and PHP version constraints against your project before committing — you may need --with-all-dependencies and a pinned minor.
  3. Register the bundle in config/bundles.php:
    WernerDweight\DoctrineCascadeSoftDeleteBundle\DoctrineCascadeSoftDeleteBundle::class => ['all' => true],
    
  4. Read DependencyInjection/Configuration.php and the entity listener/service wiring first. This is a small, low-traffic package; the config schema and service definitions are the most reliable documentation of what it actually supports (config keys, tagged services, event subscriptions). Do that before trusting any README examples.
  5. First use case: a Category entity with a children OneToMany, where soft-deleting the parent should also soft-delete its descendants in one flush. Annotate/attribute the association (or register the entity in the bundle config — the package exposes a marker so the listener knows which associations to walk), call $em->remove($parent) + $em->flush(), and assert deletedAt is set on children.

Implementation Patterns

  • Marker on the association, not the entity. The cascade is about which relations should propagate a soft-delete. Apply the bundle's marker attribute/annotation to the collection property ($children) or list associations in config, not to the whole class — this keeps the propagation graph explicit and auditable.
  • Single flush, same UnitOfWork. Drive everything through the normal remove() → flush() cycle. The listener participates in preSoftDelete/preRemove events, so all cascaded children are scheduled as UPDATEs inside the same transaction. Don't call flush() manually between levels.
  • Repository-level convenience. Wrap the pattern in a softDeleteWithCascade(Entity $e) method on a base repository (or a small domain service) so controllers don't need to know the bundle exists. This also gives you one seam to swap if you later replace the package.
  • Bulk operations. If you soft-delete many roots at once, use DQL/UPDATE only if you accept bypassing the listener; otherwise loop and rely on the cascade to keep behavior consistent. Document which path is used where.
  • Integration tests via KernelTestCase. Write a functional test that boots the kernel, loads fixtures with a parent and two children, soft-deletes the parent, clears the EM, and asserts all three deletedAt fields are non-null and that find() no longer returns them. Since the package has zero community traction, this test is your contract.
  • Admin/UI integration. Because SoftDeleteable filters deleted rows globally, cascade-deleted children will disappear from listings automatically — good. But if your UI shows a "trash" or "restore" view that disables the filter, children will appear there too; make sure filters are toggled consistently.

Gotchas and Tips

  • Requires SoftDeleteable to be enabled per entity. If @Gedmo\SoftDeleteable (or the attribute) is missing on the child class, the listener will issue a real DELETE for it via Doctrine's native cascade, silently destroying data. Audit every entity in the cascade graph.
  • Recursion and cycles. Self-referencing trees or bidirectional relations can loop. The bundle typically guards with an in-memory visited set, but confirm this by testing a circular reference (A→B→A); if it isn't guarded, you'll get an infinite loop or a stack overflow on flush.
  • deletedAt provenance is lost. A child deleted via cascade looks identical to one deleted directly. If you need to distinguish (e.g., restore only parents), add a cascadeDeleted boolean or deletedByParent FK yourself — the bundle won't do it for you.
  • Performance fan-out. Each propagated delete is an UPDATE. A tree of 10k nodes becomes 10k UPDATEs plus hydration. Use Doctrine\ORM\Query::HINT_REFRESH/iterate if needed, or batch at the tree root level with a documented exception path.
  • Doctrine UoW re-entrancy. If you subscribe your own preRemove/preUpdate listeners, ordering matters. Register your listener with a lower priority than the cascade listener (check the bundle's services.yaml for the tag priority) so you see the final state, not intermediate.
  • Version pinning. With 0 stars, 0 dependents, and a 2023 release, assume no maintenance. Pin the exact version in composer.json, and watch out for deprecations against newer Doctrine ORM (3.x attribute mapping vs. annotations) and Symfony 7 — the bundle's DI config may still reference removed classes.
  • Extension points. The useful override surface is usually (a) the config schema (add/remove entities from the cascade graph) and (b) replacing the listener service with your own subclass via services.yaml decorates: or setAlias. Prefer decorating over forking.
  • Debugging. Enable Doctrine SQL logging and verify the flush emits UPDATE ... SET deleted_at = ... only, never DELETE FROM. If you see DELETE, either the marker is missing or the SoftDeleteable filter is disabled for that entity.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib