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

Event Dispatcher Laravel Package

symfony/event-dispatcher

The EventDispatcher component lets application components communicate by dispatching events and listening to them. Register listeners on named events, control priority, and decouple your PHP code with a simple, standalone Symfony library.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Recommendation up front: adopt symfony/event-dispatcher as a transitive/shared-contract dependency and a package-authoring primitive — not as a replacement for illuminate/events. The package is excellent, mature, MIT-licensed, and battle-tested, but in a Laravel codebase its primary value is already captured by Laravel's own dispatcher, and the highest-risk outcome of this evaluation is a two-dispatcher architecture nobody owns.

Architecture fit

  • The component is a PSR-14 implementation with listeners, subscribers, priorities, stoppable propagation, and a small surface area. It is infrastructure, not a feature; it makes money only indirectly (decoupling, extensibility, fewer bespoke hooks).
  • Laravel already ships Illuminate\Events\Dispatcher with the same conceptual model plus Laravel-specific capability the Symfony component does not have: queued listeners, ShouldQueue/ShouldQueueAfterCommit, wildcard listeners, model events, broadcasting integration, and Event::fake() test helpers. Any story that positions this package as "a drop-in replacement for Laravel's events" is wrong and should be struck from stakeholder material.
  • Where it genuinely fits: (a) internal Composer packages/libraries that must run outside Laravel or across Laravel and non-Laravel services; (b) interop where a third-party Symfony-based library needs a dispatcher; (c) as the PSR-14 contract so our domain code depends on an interface rather than on Laravel's facade.
  • Where it does not fit: replacing Eloquent model events, replacing queue-backed side effects, or introducing a second in-process bus inside a request lifecycle.

Integration feasibility

  • Composer-wise it is trivially installable, but it is almost certainly already present transitively through Symfony components in laravel/framework's dependency graph. Adding a direct requirement mainly changes version pinning risk, not capability. Step one of implementation is composer why symfony/event-dispatcher, not composer require.
  • PHP gate is the real constraint: Symfony 8.x requires PHP >= 8.4. Symfony 8.0 also enforces return types across components (a breaking change for anyone extending/overriding). Most Laravel estates are on PHP 8.2–8.3 today, so the realistic target line is 6.4 LTS or 7.4 LTS, not the 8.1 GA headline. The supplied product narrative leads with v8.1.0 GA; that is a future default for us, not a current one.
  • #[AsEventListener] attribute discovery is wired by FrameworkBundle's DI pass, not by the component in isolation. In a Laravel app the attribute is inert unless we write our own registration pass. Budget for that explicitly or drop the attribute from the value case.
  • The component is synchronous only. Anything promising throughput gains, async fan-out, or backpressure must route through Laravel queues or an external broker; the package contributes none of that.

Technical risk

  • Dual-bus ambiguity (high). Two dispatchers in one container means engineers must know which one to dispatch() on, which one Octane/queue workers reset, and which one Event::fake() intercepts. Tests silently passing because a listener was registered on the other dispatcher is the classic failure.
  • Inaccurate capability claims (high, reputational). The draft stakeholder pitch states TraceableEventDispatcher provides "immutable event logs for GDPR/HIPAA compliance." It does not — it is a debug/profiling wrapper that records which listeners ran and their timing inside the Symfony profiler, is not persisted, and is not tamper-evident. Do not put that sentence in front of auditors or Legal. If audit trails are a requirement, that is a separate design (append-only store + domain events), and this package is at most a hook point.
  • Version-pin conflict (medium). Hard-requiring ^8.1 while other Symfony packages in the tree resolve ^6.4|^7.x produces solver deadlock and forces an unplanned fleet-wide PHP 8.4 upgrade.
  • Metric anomaly (low, but note it). "Dependents: 0" is a data-source artifact of the split-repo/monorepo layout; this component is depended on by essentially every Symfony package. Do not let a procurement scorecard read that number as an adoption signal either way.
  • Long-running-process memory (medium, and evidence-based). Recurrent fixes in 7.4.8 / 8.0.8 / 6.4.36 for TraceableEventDispatcher leaks, plus an 8.0.9 fix for reset-during-dispatch, confirm the component behaves differently under Octane/queue workers than under FPM. Any adoption plan must state the worker-reset story.

Key questions to answer before committing

  1. Which concrete problem does this solve that illuminate/events + PSR-14 typing does not? Name the module and the coupling it removes.
  2. Is symfony/event-dispatcher already resolved in our lockfile, and at which version? What breaks if we pin it?
  3. What is our PHP floor per service, and does any service need 8.4 within the planning horizon?
  4. If we introduce a second dispatcher, who owns the convention, the lint rule, and the observability story for it?
  5. Do we need queued/async listeners? If yes, the Symfony component cannot be the primary bus.
  6. Are any compliance/audit requirements being attached to this package? If so, they are misattributed and must be re-scoped.
  7. Is the real requirement library portability (packages that must work in and out of Laravel)? That is a yes to PSR-14 contracts, and a maybe to this concrete implementation.
  8. What is the rollback? (Answer should be "remove the service binding," not "revert 40 call sites.")

Integration Approach

Stack fit

  • Primary, keep: illuminate/events remains the application bus — it owns HTTP/request lifecycle, model events, queue integration, and Event::fake().
  • Secondary, add narrowly: symfony/event-dispatcher as an internal library bus for extracted packages and for domain modules we want framework-agnostic. One instance, one clearly documented service id, never autowired by default.
  • Contract layer: type-hint PSR-14 EventDispatcherInterface (via symfony/event-dispatcher-contracts) in reusable code rather than either concrete dispatcher. This is the single highest-value, lowest-risk move in the whole assessment and it does not require replacing anything.
  • Do not use: the attribute-based listener discovery (needs a custom pass), the FrameworkBundle-specific integrations, or the Traceable dispatcher as a production audit mechanism.

Migration path

  1. Inventory — composer why/composer show on the three or four most-coupled services. Confirm resolved version and PHP constraints. Exit: one-page dependency map.
  2. Contract-first refactor — convert high-coupling direct service calls in the pilot module to PSR-14 typed dispatch + explicit listeners, still on Laravel's dispatcher. Exit: measurable reduction in constructor injections; no behaviour change; tests green.
  3. Extraction (only if step 2 proves value) — stand up the Symfony dispatcher as a named service for that module only, with a thin adapter that lets the module dispatch without knowing the host. Exit: module's own test suite runs with no Laravel bootstrap.
  4. Bridge, if and only if cross-boundary events are needed — a single explicit forwarder (Symfony → Laravel), never bidirectional, to avoid loops. Exit: loop-guard test in CI.
  5. Standardize or stop — either publish the convention (naming, priority registry, worker reset) or unwind step 3. Most teams should expect to stop at step 2.

Compatibility

  • Target ^6.4 (LTS) or ^7.4 (LTS) to match the PHP 8.1/8.2+ floors in current services; treat ^8.x as gated on a PHP 8.4 platform decision, and note that 8.0 enforces return types (extenders must be audited).
  • Widen constraints (^6.4|^7.4) rather than pinning, so other Symfony packages in the graph can co-resolve.
  • Verify PSR-14 interface implementation on the installed Illuminate\Events\Dispatcher version before relying on contract-only typing; if absent for our Laravel version, the adapter in step 3 carries it.

Sequencing Run steps 1–2 in a single sprint in one module. Gate steps 3–4 on a written answer to questions 1 and 5 above. Any request to lead with the v8.1 GA narrative is a sequencing error: it inverts the PHP upgrade and the architectural decision.

Operational Impact

Maintenance

  • Low code-maintenance burden: MIT, small API surface, Symfony core team, frequent patch releases across five maintained branches (6.4, 7.3, 7.4, 8.0, 8.1) — the changelogs are mostly "no significant changes," which is a positive signal for a component at this age. Patch cadence is high enough that we should be comfortable with routine composer update churn.
  • The real maintenance cost is our own convention, not the package: a second bus needs an owner, a written rule for which bus to use, a static-analysis or code-review check, and a documented worker-reset step. That is ongoing product-owner attention, not a one-off.

Support

  • Community/OSS support via GitHub and Symfony's security policy; no vendor SLA. That is acceptable for infrastructure this well-trodden, but it means we self-insure on upgrade work. Do not let a vendor-shaped "enterprise-grade support" claim imply a contract that does not exist.
  • Documentation is strong and version-scoped, but it is Symfony documentation — it will not answer "which dispatcher do I use in Laravel." That gap is ours to fill internally.

Scaling

  • In-process dispatch is fast and predictable; the component is not the throughput bottleneck. Real scaling gains come from design (decoupling, fewer synchronous call chains), not from swapping dispatchers.
  • Synchronous-only is the scaling ceiling. Fan-out to email, webhooks, search indexing, or third parties must remain on Laravel queues. If a design proposes "high-throughput pipelines with <5% overhead" as a reason to adopt, that benefit is attributable to the queue/broker tier, not to this package.
  • Watch Octane/queue workers: the 7.4.8/8.0.8/6.4.36 leak fixes and the 8.0.9 reset-during-dispatch fix are the specific behaviours to regression-test if we run long-lived processes.

Failure modes

  • Silent no-op: listener registered on the wrong dispatcher; event dispatched but nothing reacts; tests pass because nothing asserted the listener.
  • Ordering and loops: priority collisions and re-entrant dispatch causing recursion; mitigated by an explicit priority registry and a loop guard, not by discipline alone.
  • Exception blast radius: a listener throwing aborts the remaining listeners and can fail the originating request; needs a stated policy (fail-fast vs. isolate-and-log) per event class.
  • Propagation surprises: stopPropagation() in an early listener silently starving later listeners — a debugging cost that surfaces as "logging stopped working" weeks later.
  • Worker state drift: listeners or closures captured per-request accumulating across jobs in queue/Octane workers.
  • Compliance over-claim: someone points at TraceableEventDispatcher in a design review as the audit log. Kill this early; it is the failure mode with external consequences.

Ramp-up

  • Conceptually near-zero: the mental model is identical to Laravel events, and mid-level engineers will be productive in a day. The cost is organizational, not technical — teaching when to use which bus, and getting reviewers to catch cross-bus mistakes.
  • #[AsEventListener] attributes are the one genuinely unfamiliar element and, since discovery requires a FrameworkBundle-style DI pass we would have to build, I would deprioritize them for the first two quarters and use explicit registration.
  • Budget: ~1 engineer-week for inventory + pilot refactor, plus a recurring small tax on code review. If the ask grows beyond that, the scope has drifted from "decouple a module" to "introduce a second event platform," which needs its own business case — not a package evaluation.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin