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

Command Bus Laravel Package

innmind/command-bus

A lightweight command bus for PHP that maps commands to handlers and dispatches them through a middleware pipeline, making it easy to add concerns like transactions, logging, and validation around command execution.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

innmind/command-bus is a minimal command-bus abstraction from the Innmind ecosystem — a strict-typed, functionally-oriented family of PHP packages (immutable collections, Maybe/Either monads, value-object typing) authored as a coherent DDD toolkit rather than a Laravel add-on. The package itself is almost certainly small: a Command marker, a CommandBus interface, and one or two concrete handlers with a heavy dependence on sibling Innmind packages for type safety. That is the central finding of this evaluation: we would be adopting an ecosystem and a programming idiom to obtain roughly one interface and one dispatcher, not adopting a feature.

Architecture fit. Poor for a Laravel codebase by default. Laravel already ships a first-class bus (Illuminate\Contracts\Bus\Dispatcher), the dispatch() helper, the Dispatchable trait, ShouldQueue, and a middleware pipeline that ties into the container, queues, events, validation, and database transactions. Innmind's bus is a parallel, incompatible mechanism with its own type contracts. Bringing it in produces a two-bus application: engineers must know which bus a given command belongs to, container auto-resolution does not apply, and framework features (queue retries, Bus::fake() in tests, Horizon visibility) do not reach the Innmind path. The architecture only fits if we are deliberately building a framework-agnostic domain layer with Laravel as an outer adapter — a legitimate architecture, but one where the interface is what we want, not the dependency.

Integration feasibility. A spike is cheap and should be the first task. The package has zero dependents and zero stars, which means no field reports on compatibility with current PHP versions (8.2/8.3/8.4), no Laravel service provider, no published test matrix, and no evidence anyone has wired it into a Symfony or Laravel container. Because it is archived, there will also be no compatibility release when PHP 8.5 lands or when a transitive Innmind dependency shifts its API. The realistic integration effort is not "install and register" but "read the source, verify it against our PHP baseline, and decide whether to fork." For a package this small, forking or reimplementing is usually a day of work; adopting it as a live dependency is an indefinite maintenance commitment. The MIT license makes the fork option clean.

Technical risk. High, concentrated in three places. Supply chain and governance: archived, single-author, no dependents — if a defect surfaces we are the maintainers, whether or not we planned to be. Coupling: the package's value is inseparable from Innmind's type system; pulling in the bus pulls in the immutable/monad stack, which becomes a transitive dependency of our domain layer and is very hard to unwind later. Semantic risk: a command bus implies guarantees (synchronous vs. queued execution, transactional boundaries, handler-not-found behaviour, idempotency, retry semantics, observability hooks). A minimal library typically specifies none of these, so the guarantees we actually depend on would be ones we build ourselves on top. Counterweights: the license is permissive, the code volume is small enough to audit in an afternoon, and nothing here is a security surface.

Key questions.

  1. What is the actual public API surface — is this an interface plus a dispatcher, or does it carry substantive behaviour we would have to reimplement?
  2. What PHP version range and Innmind dependency versions does it pin, and do those resolve against our current composer.json without conflict?
  3. Does it support asynchronous execution at all, or is it synchronous-only? If synchronous-only, what does it give us beyond a match statement and the container?
  4. Are transaction boundaries, handler-not-found errors, and middleware/interception part of the contract or left to the caller?
  5. Which bounded context is driving this request, and has it been compared against simply using Laravel's bus with a Command/Handler convention?
  6. Is the organisation prepared to own a fork with a named maintainer and a PHP-version upgrade runbook?

Integration Approach

Stack fit. The pattern fits; the package does not, for a standard Laravel stack. Laravel's bus already satisfies the command/handler separation, middleware, and async dispatch that a CQRS-lite introduction needs, and it does so with queue integration, test fakes, and framework-wide familiarity. The defensible reasons to reach outside the framework are (a) a hard requirement that the domain layer be framework-independent for a future migration, or (b) an existing Innmind-based service we must interoperate with. Absent one of those, the correct move is to codify the pattern internally and treat innmind/command-bus as a design reference, not a dependency.

Migration path. Recommended sequence: run a short spike that reads the source and documents its contract (interface, exceptions, execution model, dependency tree); then decide build-vs-fork-vs-adopt with the spike output in hand. If we adopt or fork, register a container binding behind an internal App\Shared\CommandBus interface so the implementation is swappable from day one — this is the single highest-value decision, because it makes the choice reversible. If we build, define the same internal interface and implement it over Laravel's dispatcher with explicit middleware for transactions, logging, and metrics. If we fork, vendor the package under an organisation namespace (app/Support/CommandBus or a private VCS repository), pin the PHP constraint to our actual floor, add tests, and record it in the internal package registry with an owner.

Compatibility. Two compatibility axes must be cleared before any code is written: PHP runtime version (verify the package resolves and its tests pass on our floor, currently 8.2 or 8.3 for modern Laravel) and type-system containment (ensure Innmind value objects and monads do not leak past the bus boundary into controllers, Eloquent models, or job payloads — queued commands must be plain serialisable objects, which Innmind's immutable types are not guaranteed to be).

Sequencing.

  1. Spike and contract documentation — 1–2 days, one engineer.
  2. Architecture decision record: build vs. fork vs. adopt, with the reversibility requirement stated.
  3. Implement the internal interface and the first adapter; add contract tests that any future adapter must pass.
  4. Pilot in one bounded context (a single module with clear command semantics), not in the shared kernel.
  5. Retrofit the second context only after the pilot survives a release cycle with queue and transaction behaviour observed in production.
  6. Only then consider broad standardisation, and only with a written ownership commitment for any forked code.

Operational Impact

Maintenance. Archived status means zero upstream maintenance: no PHP version bumps, no dependency updates, no bug fixes. Because the package is small, the maintenance cost of a fork is genuinely low — an estimated few hours per year for compatibility work, plus a security review on each PHP minor — but that cost only materialises if we assign an owner. An unowned fork is the worst outcome: a silent liability that decays until an unrelated PHP upgrade breaks it at an inconvenient time. Budget the ownership explicitly in the ADR.

Support. No vendor, no active issue tracker, no CVE feed, no community to consult. Internal engineers become the sole source of answers about behaviour, which is acceptable for a 200-line library and unacceptable for anything with meaningful semantics. Documentation will have to be written, not inherited.

Scaling. A minimal command bus scales in the trivial sense — it is a function call — but scaling a bus in production means asynchronous execution, backpressure, retry policy, dead-letter handling, and per-command observability. None of that is likely present. Laravel's bus inherits all of it from the queue subsystem (Redis/SQS, Horizon, failed_jobs, Bus::fake()), and the delta is substantial. If the roadmap includes offloading commands to workers, adopting Innmind's bus means rebuilding a queue integration that the framework already provides, with less maturity and no ecosystem tooling.

Failure modes. Watch for: two-bus ambiguity causing commands to be dispatched on the wrong path and silently not execute; handler-not-found surfacing as an unhandled exception rather than a structured error; absence of transactional wrapping leaving partial writes on handler failure; non-serialisable command payloads failing only when the queue is enabled in staging; Innmind type errors surfacing as TypeError deep in the call stack with poor stack traces; and the slow-rot failure of an unowned fork that passes CI until a PHP upgrade. Each is mitigable, but each requires deliberate work that a framework-native bus provides for free.

Ramp-up. Non-trivial and under-estimated. The Innmind idiom — declare(strict_types=1) everywhere, immutable collections, Maybe/Either instead of null and exceptions — is a genuinely different mental model from idiomatic Laravel. Engineers onboarded to this codebase would need to learn both the framework and a functional PHP dialect, for the benefit of a dispatcher. Estimate two to three days of unfamiliarity per engineer and a persistent tax on code review, against a Laravel-bus alternative that requires roughly an hour of explanation. For a small, framework-fluent team, that trade is difficult to justify on technical merit alone; it is only justified by a strategic framework-independence requirement, which should be stated explicitly rather than assumed.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager