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.
Architecture fit — This is a Symfony bundle, not a Laravel package, and that distinction drives the entire assessment. It targets a narrow but real gap: Doctrine ORM's cascade: [remove] does not fire for soft deletes, because a soft delete is a flush-time UPDATE, not a lifecycle removal. The bundle works by attaching a Doctrine event subscriber/listener that intercepts the soft-delete event and walks associations to mark children as deleted. Architecturally that means it sits inside your persistence layer and mutates UnitOfWork state — a high-blast-radius position for a dependency with 0 stars, 0 dependents, and a last release of 2023-02-21. Treat it as reference implementation, not as a library you adopt blind.
Integration feasibility — The mechanics are cheap: one Composer require, one bundle registration, one entity-level attribute/config. The real feasibility question is the compatibility matrix. A Feb-2023 release predates Symfony 7 (Nov 2023) and Doctrine ORM 3.0 (Feb 2024), so constraint widening is likely required before it will install on a current stack. It also presumes a specific soft-delete implementation (Gedmo SoftDeleteable or its own contract) — verify which, because that dictates whether it composes with your existing entity base classes and audit tooling. Assume a fork on day one.
Technical risk — Concentrated in correctness, not security:
Key questions — (1) Which Doctrine ORM and Symfony versions are formally supported, and does it load on ORM 3? (2) Which soft-delete implementation does it contract against? (3) Does it handle ManyToMany, self-referencing, and cyclic graphs, and with what recursion guard? (4) Is cascade applied pre-flush inside the caller's transaction? (5) Is there CI and test coverage for cascade semantics, or is the repo effectively a code sample? (6) What is the restore/undelete story — does it cascade symmetrically, and do unique constraints collide? (7) Is there a maintained fork or upstream successor?
Stack fit — Symfony + Doctrine ORM + soft delete is the only viable home. If the platform in question is Laravel-first, this package is a non-starter: Laravel's SoftDeletes trait has a completely different lifecycle, and the equivalent solution there is model-event hooks (deleting) or a first-party package such as soft-cascade. Confirm the actual stack before spending any evaluation cycles — the framing mismatch here is itself a signal that a decision-maker may be pattern-matching on the word "cascade" rather than on the runtime.
Migration path — Vendor the source into an internal namespace rather than depending on Packagist. The surface area is small enough that owning it is cheaper than managing a transitive dependency with one maintainer and zero downstream users. Concretely: copy the listener/subscriber into an internal bundle, widen Composer constraints, and replace the package dependency with your own.
Compatibility — Build a CI job that installs against your actual matrix (PHP 8.2/8.3, Symfony 6.4/7.x, Doctrine ORM 2.20/3.x, Gedmo version) before any application code is written. That job is the deliverable that tells you whether this is a two-day or two-month integration. Do not merge application wiring until it is green.
Sequencing
Maintenance — You will be the maintainer. A repository with zero stars and zero dependents generates no community pressure to fix Doctrine 3 or Symfony 7 breakage, and the original author has no obligation to respond. Budget recurring fork-rebase effort at every framework upgrade, or eliminate that cost by internalizing the code.
Support — No SLA, no vendor, GitHub issues only. That is acceptable for internal tooling and unacceptable for anything on a revenue path. Decide which this is before integration, not after.
Scaling — Cascade cost scales with graph breadth, not with the single row you deleted. Bulk operations (offboarding a tenant, archiving a workspace) will hydrate entire object trees, hold long transactions, and risk lock contention. Plan for application-level chunking and batch processing above the listener; the package itself offers no async or queue story. Watch query counts on delete paths the same way you watch them on read paths.
Failure modes — Ranked by severity: (1) silent partial cascade leaving orphaned live children under a soft-deleted parent; (2) infinite recursion on cyclic or self-referencing graphs; (3) missing join-table cleanup on many-to-many, producing phantom membership after "delete"; (4) unique-constraint collisions on restore; (5) listener ordering conflicts with audit/workflow subscribers that cause double-writes or skipped events; (6) timeout and transaction rollback on large graphs, which at least fails loudly. Each should have a monitoring signal — a nightly integrity query that counts children of soft-deleted parents is the cheapest possible insurance and should ship with the integration, not after it.
Ramp-up — The API learning curve is trivial: one bundle registration and one attribute. The actual cost is conceptual — engineers must understand Doctrine's UnitOfWork, flush-time semantics, and the difference between removal and soft deletion to reason about failures. A competent Symfony developer is productive in half a day; debugging a partial cascade without documentation takes considerably longer. Write the cascade contract down (which associations are covered, what happens on cycles, how restore behaves) as part of the integration, and treat that document as the primary deliverable alongside the code.
How can I help you explore Laravel packages today?