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 Contracts Laravel Package

symfony/event-dispatcher-contracts

A small set of PHP interfaces that abstract Symfony's event dispatcher, letting you build on proven event semantics and swap implementations without locking your code to a specific package.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit symfony/event-dispatcher-contracts is an interfaces-and-traits-only package: it ships EventDispatcherInterface, Event, StoppableEventInterface, and ListenerProviderInterface (PSR-14 semantics) with no dispatching implementation. That makes it a contract layer, not a feature. For Laravel, the fit is asymmetric:

  • Event definitions: strong fit. Domain events become framework-agnostic value objects that can travel between Laravel, Symfony workers, and CLI tools.
  • Dispatching: weak fit today. Laravel's Illuminate\Contracts\Events\Dispatcher is not PSR-14 compliant (different dispatch() signature/return, EventServiceProvider registration instead of a ListenerProvider, no StoppableEventInterface handling). Adopting this package does not, by itself, get us interoperability — it only gets us a shared vocabulary.
  • Where it genuinely pays off: shared libraries (e.g., a payment or billing module consumed by a Laravel app and a Symfony service), DDD-style modular monoliths, and SDKs published to multiple frameworks. It is over-abstraction for a single-framework CRUD app.

The "Dependents: 0" figure should be treated as unreliable metadata, not a signal of low adoption — this package is overwhelmingly consumed transitively and rarely declared directly. Conversely, the future-dated "last release: 2026-06-27" needs verification against Packagist before we pin anything in a lockfile.

Integration feasibility

  • Low effort (days): define new events against Symfony\Contracts\EventDispatcher\Event. Laravel can dispatch these objects unchanged, so the change is effectively type-hint migration with no runtime delta.
  • Medium effort (1–2 sprints): introduce an adapter that maps PSR-14 dispatch() onto Laravel's dispatcher (or the reverse via spatie/laravel-psr-event-dispatcher) so external consumers can dispatch into our app.
  • High effort (multi-sprint): replace Laravel's dispatcher as the primary transport. This is where queued listeners, broadcasting, wildcard listeners, and Event::fake() behavior start to erode.

Technical risk

  • Feature loss on dispatcher swap: Laravel's ShouldQueue, ShouldBroadcast, wildcard listeners, and Event::fake() assertions are not part of the PSR-14 contract. Swapping the dispatcher silently removes capabilities teams depend on.
  • Signature drift: listeners written for Laravel (handle($event)) vs PSR-14 callables (__invoke($event)) create a dual-registration surface that drifts over time.
  • Bridge as a single point of failure: the adapter becomes our code to own; there is no Laravel-core commitment to PSR-14 dispatching.
  • Testing gap: the most likely production failure is "green tests, silent listeners" because Event::fake() does not observe a PSR-14 dispatcher.
  • PHP 8.1+ floor is fine for Laravel 10/11/12 but forecloses backporting to legacy services.

Key questions

  1. What is the actual driver — a real cross-framework consumer, or architectural preference? If no consumer exists outside Laravel, defer.
  2. Which Laravel event features (queues, broadcasting, wildcards, model events) must remain? Model events are not covered by this contract at all.
  3. Will we own a custom adapter or depend on a third-party bridge, and who maintains it?
  4. Do we have a concrete second consumer (Symfony service, CLI, message broker) to validate interoperability against in the pilot, or are we building for a hypothetical?
  5. Is the release/version metadata (2026-06-27, dependents 0) verifiable, and what version do we pin?

Integration Approach

Stack fit Partial and deliberate: the package slots in cleanly as the event-definition contract for Laravel 10+ on PHP 8.1+, while Laravel's dispatcher remains the runtime transport. Full PSR-14 dispatching is a separate, optional decision. Recommended posture: adopt contracts now, defer dispatcher replacement until a second framework consumer exists.

Migration path

  1. Phase 1 — Contracts in new code (low risk). New events extend Symfony\Contracts\EventDispatcher\Event; existing events untouched. Add a custom make:event stub and a static-analysis rule so the convention sticks without code review policing.
  2. Phase 2 — Boundary library (medium risk). Extract domain events into a shared package that depends on this contract and nothing Laravel-specific. Laravel dispatches them natively; a Symfony consumer can too. This is the phase that delivers the business value.
  3. Phase 3 — Adapter, only if pulled (higher risk). If an external system must dispatch into Laravel, add a PSR-14 adapter in front of the Laravel dispatcher rather than replacing it. Keep the Laravel dispatcher as the engine; expose PSR-14 at the edge.
  4. Phase 4 — Optional dispatcher swap. Only on evidence (measured need, e.g., a Symfony service bus becoming the canonical dispatcher). Treat as a separate roadmap item with its own risk review.

Compatibility

  • Laravel 10/11/12 and PHP 8.1+: compatible.
  • Third-party packages that assume Illuminate\Events APIs: at risk only in Phase 3/4, not Phase 1/2.
  • Queued/broadcast events: keep them on Laravel's dispatcher; do not route them through a PSR-14 adapter.
  • Eloquent model events: explicitly out of scope.

Sequencing Pilot in one shared module with a real or realistic second consumer, gated by an ADR. Success criteria: same event class dispatching and being consumed in both a Laravel process and a non-Laravel process, with no change to queued/broadcast behavior in the host app. Expand only after that pilot clears. Budget: ~1 sprint for the pilot including adapter spike and test-double work.

Operational Impact

Maintenance Near-zero for the package itself — interfaces only, MIT, Symfony's backward-compatibility promise, and upgrades are typically handled transitively. The real maintenance surface is our adapter and event-convention tooling, which is small but permanent. Pin the version explicitly and let Dependabot/Renovate handle bumps; interface changes are rare and major-version gated.

Support Community-supported with a predictable Symfony release cadence; no vendor SLA. Support risk is not the package — it's the absence of an internal owner for the bridge. Assign ownership to the platform team and document the contract convention in the engineering handbook, otherwise the pattern decays within two quarters as new engineers revert to Illuminate\Events.

Scaling Runtime cost is negligible — it's an autoloaded interface set plus one indirection per dispatch through any adapter. At high event volumes (thousands of dispatches per request or per job batch), benchmark the adapter path specifically; the honest expectation is single-digit microseconds, so this is a footnote, not a blocker.

Failure modes

  • Silent non-delivery: dual-registration drift where a PSR-14 listener is never wired to the Laravel dispatcher. Detect with an integration test asserting dispatch-to-listener end-to-end, not Event::fake().
  • Test/production divergence: suites pass against fakes that don't exist in production.
  • Capability regression: queued or broadcast listeners stop firing after a dispatcher swap. Guard with a feature-parity checklist in the ADR.
  • Signature mismatches during listener migration causing runtime TypeError in async workers — a class of failure that surfaces in queue workers, not the web path, so it's slow to detect.
  • Dependency conflicts on a major contract bump across a polyglot repo.

Ramp-up 1–2 days for a mid-level engineer to understand the contract and the Laravel gap; the ADR and lint rule are the durable artifacts. Team-level rollout is a single knowledge-share plus a code template. The genuine ramp-up cost is organizational: convincing teams not to swap the dispatcher for its own sake.

Recommendation Adopt in Phase 1–2 form (contracts + shared event library) for modules with a credible cross-framework consumer; explicitly decline dispatcher replacement until a second framework consumer is funded. Cheapest reversible step with the highest option value, and it defers the only genuinely risky decision.

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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels