headsnet/domain-events-bundle
Symfony bundle for domain events: define and dispatch events from your domain, register subscribers, and defer delivery until after Doctrine transactions commit, keeping business logic decoupled from infrastructure.
Architecture fit. The first thing to flag is a scoping mismatch: headsnet/domain-events-bundle is a Symfony bundle, not a Laravel/PHP package in the Laravel sense. It hooks into the Symfony kernel and Doctrine lifecycle. Laravel already solves this problem natively (the ShouldDispatchAfterCommit contract, per-listener $afterCommit, and DB::afterCommit()), so the architectural fit for our Laravel services is poor-to-indirect — this is at best a pattern to borrow, not a dependency to install. If any part of our estate runs Symfony, the fit there is good.
Integration feasibility. Low for Laravel. Adoption would mean either (a) pulling Symfony/Doctrine components into a Laravel app, which duplicates and competes with the framework's own dispatcher, or (b) reimplementing the deferred-publish pattern on top of Laravel's native after-commit hooks. Option (b) is cheap and low-risk; option (a) is not recommended.
Technical risk. v0.4.5 is a behavioral change disguised as a patch. PR #46 changes when domain events are published: events raised inside an active transaction are now held and released on commit rather than dispatched immediately. Because the package is pre-1.0 (0.4.x), semver gives us no protection — a patch bump can carry a semantic change, and it did. Concrete risks:
Key questions. (1) Which mechanism detects the active transaction — Doctrine postFlush/onFlush, or an EntityManager decorator? Does it see DBAL-level or manually opened transactions, or only ORM-managed ones? (2) What is the rollback behavior — discard, or publish anyway? (3) How are nested transactions and savepoints handled? (4) Is there an opt-out per event or per listener for the immediate-dispatch case? (5) Any memory bound on the buffer during long-running transactions? (6) Was this released as 0.4.5 with no deprecation path or upgrade note — and is that the maintainer's normal practice?
Stack fit. Do not adopt for the Laravel services. Encode the intent of #46 using Laravel's native primitives: implement ShouldDispatchAfterCommit on events that must not fire on rollback, set $afterCommit on listeners where appropriate, and use DB::afterCommit() for closures. Where we need the package's semantics on Laravel, we get them for free from the framework — with framework-level support and no extra dependency.
Migration path. If we do have Symfony/Doctrine services consuming this bundle, pin to 0.4.5 deliberately, not by floating constraint. If we are not ready to absorb the deferred-dispatch behavior, hold at 0.4.4 and pin exactly while we characterize the change.
Compatibility. Verify Composer constraints (PHP version, Symfony/Doctrine major versions) before any pin — the release note carries none of this. Also check whether the change assumes Doctrine ORM specifically; if our Symfony services use DBAL directly or a non-Doctrine transaction manager, the detection may not fire and we would get the old behavior silently, which is worse than a clean failure.
Sequencing.
ShouldDispatchAfterCommit.Maintenance. Pre-1.0, small maintainer footprint (headsnet org, single contributor on this PR), thin release notes. Every bump requires reading the diff rather than trusting the version number. Budget recurring review time, not a one-off.
Support. No commercial backing; upstream response times unknown. Our exposure is bounded only if adoption is limited to non-critical Symfony paths — another argument for not threading it through Laravel services.
Scaling. The buffer is per-process and unbounded by anything documented. Long transactions — batch jobs, imports, queue workers with wide transactional scopes — will accumulate events in memory and then flush them as a synchronous burst on commit, pushing listener work into the commit path and inflating tail latency. For any high-volume path, pair deferred dispatch with queued listeners so the commit does not block on downstream side effects.
Failure modes. Ranked by likelihood and blast radius:
Ramp-up. The Laravel team gains nothing to learn here — the native hooks are already familiar. The Symfony team needs a short but real briefing on transaction boundaries, savepoint semantics, and the difference between "event raised" and "event published"; that distinction is the whole substance of this release and is easy to get wrong. Expect a half-day of pairing plus the test suite above before the first production bump.
How can I help you explore Laravel packages today?