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 Domain Events Laravel Package

vanio/doctrine-domain-events

A Doctrine ORM integration that lets your entities record and dispatch domain events. Collect events during persistence, then release them after flush via a configurable dispatcher, keeping your domain model decoupled from infrastructure.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The framing of this as a "Laravel/PHP package" is the first thing to correct: vanio/doctrine-domain-events is a Doctrine ORM extension, not an Eloquent/Laravel package. It targets applications that use Doctrine\ORM\EntityManager as their persistence layer. Laravel's default ORM is Eloquent, so for a standard Laravel application the architectural fit is poor by default and neutral-to-good only for a Laravel app that has already committed to Doctrine via a bridge such as laravel-doctrine/orm. The capability it enables — publishing domain events from entities and, critically, calling flush() inside a listener triggered by a flush — is genuinely valuable in a DDD-style codebase, because re-entrant flush into Doctrine's UnitOfWork has historically been a sharp edge. That value, however, is value delivered to Doctrine users, and Laravel teams have cheaper native analogues (model observers, DB::afterCommit, queue-backed listeners, or an outbox table).

Integration feasibility. Feasible but non-trivial. The work is not "install this package"; it is "adopt Doctrine ORM in Laravel, then install this package." The real integration surface is the bridge (laravel-doctrine/orm) and its Laravel-version compatibility, plus binding the EntityManager and wiring the package's event dispatch into the container. The package itself is small and MIT-licensed, so source-level auditing is cheap — that is the main mitigating factor. Expect a spike, not a ticket.

Technical risk. Elevated, on four counts:

  • Adoption signals are effectively zero. 6 stars, 0 dependents, low composite score. There is no ecosystem evidence of production use, no third-party validation, and no downstream projects surfacing edge cases. You would be an early adopter of unproven infrastructure.
  • Vendor concentration. Published by a single commercial org (Vanio) as one of a family of Doctrine extensions. One team's priorities are the entire support model.
  • Coupling to non-public Doctrine internals. Re-entrant flush necessarily manipulates UnitOfWork state and commit ordering — exactly the area Doctrine has been actively revising (ORM 2.14+ event changes, ORM 3.x). This is the part of Doctrine least protected by BC guarantees.
  • Intrinsic correctness risk. "Flush inside flush" means recursion, partial visibility of uncommitted state, and rollback semantics that are easy to get subtly wrong — and that will not fail loudly in tests.

Key questions to put to the maintainer (or answer by reading the source):

  1. Which Doctrine ORM versions are supported — is ORM 3.x in the matrix, or 2.x only? Which PHP versions?
  2. What is the exact dispatch contract — PSR-14, Symfony EventDispatcher, or a bespoke interface? Can it be swapped for Laravel's dispatcher?
  3. Are events dispatched during flush or after commit, and is deferral to after-commit configurable? For any listener with external side effects (mail, HTTP, queue), only after-commit is correct.
  4. How does it behave under nested transactions / wrapInTransaction() / savepoints, and what happens if a listener throws mid-flush?
  5. Is there CI, a test suite covering recursion and rollback, and a release cadence?
  6. Is there any outbox or at-least-once delivery story, or is dispatch purely in-process and best-effort?

Integration Approach

Stack fit. There are two viable profiles and one non-viable one:

  • Viable: greenfield service explicitly designed around Doctrine ORM + DDD, where domain events are a first-class pattern. Here the package addresses a real gap and the Doctrine choice is already made.
  • Viable with cost: existing Laravel app with a Doctrine island (e.g., a bounded context already on Doctrine via a bridge). Here adoption is scoped and defensible.
  • Not viable: a conventional Eloquent Laravel app. Replacing Eloquent to gain domain events is a category error; the migration cost dwarfs the benefit and orphans you from the Laravel ecosystem (Scout, Nova, Cashier, most packages assume Eloquent).

Migration path. If you proceed, prefer the narrowest path: introduce Doctrine and this package inside one bounded context rather than app-wide, and keep the domain-event contract in your own codebase (a thin interface + adapter) so the third-party API does not leak into entities. If what you actually want is reliable domain events rather than Doctrine integration, the cheaper alternatives are Eloquent observers with queued listeners, DB::afterCommit, a transactional outbox table with a relay worker, or an eventing framework such as Ecotone or a Laravel event-sourcing package. Compare those on cost before committing to a persistence-layer swap.

Compatibility. Verify against a pinned, locked matrix: PHP version, doctrine/orm major/minor, and the Laravel bridge version for your Laravel major. Check whether Doctrine's own evolving postFlush/transaction APIs have already subsumed part of this package's reason to exist — if upstream Doctrine now tolerates re-entrant flush, the package's core differentiator narrows and its obsolescence risk rises. Also confirm the bridge is maintained for your Laravel release; an unmaintained bridge is a larger risk than this package.

Sequencing.

  1. Spike (timeboxed, one engineer). Stand up Doctrine in a branch, install the package, and write integration tests specifically for the re-entrant flush case.
  2. Prove the failure modes before proving the happy path. Exception thrown inside a nested listener → what commits? Listener persisting an entity that re-triggers itself → does it terminate? Listener with an external side effect → does it fire before rollback? These tests are the deliverable, not the demo.
  3. Decide fork-or-consume. Given MIT and a small surface, assume you will vendor (copy into app/ or a packages/ path) or maintain a fork. Decide this before adoption, not after upstream goes quiet.
  4. Pilot in one context, with the event contract owned locally.
  5. Gate wider adoption on the pilot surviving a production rollback incident.

Operational Impact

Maintenance. Treat this as code you own from day one. With 6 stars, 0 dependents, and a single publishing org, there is no realistic expectation of timely upstream fixes for your Doctrine or PHP version. Pin the version in composer.json, do not allow auto-updates, and budget an owner. The upside is that the surface is small enough that a senior engineer can fully audit it in under a day — the maintenance burden is bounded, which is the only thing that makes this defensible.

Support. There is no community to lean on and no meaningful dependent corpus to consult when something breaks. Your internal escalation path is the entire SLA. That is acceptable for a low-blast-radius internal tool and unacceptable for a critical path handling payments or compliance-relevant state.

Scaling. The performance cost is negligible in throughput terms — it is per-flush bookkeeping, not per-row. The scaling concern is transaction duration and lock hold time: re-entrant flush means additional SQL round trips and additional rows/locks inside what is already an open transaction, and heavy listeners compound it. Keep listeners thin, push I/O to async workers or an outbox relay, and instrument flush duration. Recursion depth is the real ceiling, not QPS.

Failure modes. Enumerate these explicitly in your runbook:

  • Unbounded recursion — a listener persists an entity whose own listener re-triggers the same handler; typically surfaces as a stack overflow or a hung worker under load, not at development time.
  • Dirty-read within the transaction — inner flush depends on uncommitted outer state; correct in the happy path, fragile when an outer rollback occurs.
  • Lost or duplicated events — dispatch during flush plus a later rollback means side effects fired for state that never persisted; conversely, retries can double-dispatch.
  • Unit-of-work corruption — an exception escaping a listener mid-flush can leave the UnitOfWork in an inconsistent state, producing confusing downstream errors rather than the original cause.
  • No built-in observability — you will need to add logging/metrics around listener execution and flush duration yourself.

Ramp-up. The API surface is small, so learning the package is a day. Learning Doctrine's UnitOfWork and transaction semantics well enough to debug it is a sprint for an Eloquent-native team, and it is a niche skill in the Laravel hiring market. That is the hidden cost and the reason I would not recommend this as a default dependency: the package is cheap, the surrounding competency is not.

Recommendation. Do not adopt for a standard Laravel/Eloquent application — use native events plus after-commit dispatch or an outbox. Consider adoption only for a Doctrine-based DDD service, and only with an explicit decision to vendor/fork, a pinned dependency matrix, and integration tests covering recursion and rollback written before the pilot goes live.

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.
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
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle