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

Laravel Command Bus Laravel Package

onliner/laravel-command-bus

A lightweight command bus for Laravel that maps commands to dedicated handlers, supports middleware pipelines, and keeps write operations cleanly separated from controllers and models. Simple to install and integrate into existing applications.

View on GitHub
Deep Wiki
Context7

Getting Started

The package provides a command-bus abstraction for Laravel: you dispatch a command object, the bus routes it to a handler, and (importantly) you can run that pipeline synchronously or over an AMQP transport with RabbitMQ. v1.1.8 is a patch release that adds a debug toggle for AMQP logging — no breaking changes, so upgrading from v1.1.7 is a drop-in composer update.

Minimal steps:

  1. composer require onliner/laravel-command-bus
  2. Publish the config (typically php artisan vendor:publish --tag=command-bus-config) and review the default default/transport settings.
  3. Define a command class (a plain DTO holding the payload) and a handler class with a handle() method that receives the command.
  4. Register the command → handler mapping — either through the package's registration mechanism (service provider / config mapping) or via auto-discovery, depending on how the package version is configured.
  5. Dispatch it from a controller or service: $commandBus->dispatch(new CreateUserCommand(...)).

Where to look first: the published config/command-bus.php (or equivalent) is the source of truth for transports, handler registration, and the new debug flag. Read the vendor README's "Usage" section alongside the src/ contracts — the interfaces (Command, Handler, Bus) define the entire mental model in a few files.

First use case: start synchronous. Wire one command through the bus with the sync transport and confirm the handler fires before introducing AMQP. This isolates bus wiring bugs from broker/connection issues. Once sync works, flip the transport to AMQP and add a worker (php artisan queue:work or a package-provided consumer command) to process asynchronously.

Implementation Patterns

Command/handler symmetry as the default shape. Keep commands immutable DTOs (constructor-promoted readonly properties) with no logic, and put all behavior in the handler. This is what makes the bus valuable: the dispatch call site stays a one-liner while the handler remains independently unit-testable — instantiate the handler, pass a command, assert the result, no Laravel container or broker needed.

Transport split per command, not per app. The strongest pattern is to keep read-heavy/instant command handlers on the sync transport and route only genuinely async work (notifications, third-party calls, long-running jobs) over AMQP. Configure the transport at the command or mapping level rather than globally where possible; otherwise you force everything through the broker and pay serialization latency for no reason.

Middleware for cross-cutting concerns. A command bus pipeline is the natural home for transactions, logging, auth checks, and idempotency guards. Wrap handler execution in a DB::transaction() middleware so a failing handler rolls back cleanly — this is far easier to reason about than sprinkling transactions inside handlers. Order matters: transaction middleware should sit outside business logic but inside any retry middleware.

AMQP debug logging (new in v1.1.8). Enable it via the config debug option (typically backed by an env var like COMMAND_BUS_DEBUG=true). Use this when diagnosing publish/consume issues: missing messages, unroutable commands, or connection drops. Treat it as a diagnostic mode, not a permanent setting — see Gotchas.

Integration tip — dispatching from HTTP and queue contexts. Because the bus is transport-agnostic, you can dispatch the same command from a controller (synchronous request) or from a queued listener (fire-and-forget). Keep the dispatch call identical in both and let config decide execution. This keeps controllers thin and makes it trivial to promote a slow endpoint to async later without changing call sites.

Testing pattern. Prefer asserting on the handler directly for behavior, and use the bus only to assert dispatch occurred (swap the bus for a fake/spy where the package exposes one). For AMQP paths, run an in-memory or sync transport in the test suite — never point tests at a real broker.

Gotchas and Tips

Debug logging is verbose by design. The new AMQP debug option will log publish/consume activity at a low level. Turn it on temporarily via env, reproduce the issue, then turn it off. Leaving it on in production will flood logs, balloon storage, and can measurably slow high-throughput consumers due to synchronous log I/O. If you need it in production for an incident, scope it to a single worker process.

Command serialization is the usual failure point. Anything sent over AMQP is serialized. Keep command payloads to scalars, arrays, and simple DTOs — avoid passing Eloquent models, closures, or objects with resources/connections. Prefer passing IDs and re-fetching in the handler; this also avoids stale-data bugs when a message sits in the queue. If you must pass a model, be explicit about which attributes are serialized.

Handler registration caching. If handlers are resolved via container binding or discovery, remember that config/binding caches (php artisan config:cache, optimize) can leave you with a stale mapping after adding a command. Clear caches when a new command "isn't being found" — this is the most common false alarm.

Retries and idempotency. AMQP redelivery means a handler can run more than once. Design handlers to be idempotent (upsert instead of insert, guard on an idempotency key) before you enable retries. Pair this with the transaction middleware so a partially-completed handler doesn't leave inconsistent state on redelivery.

Worker lifecycle. Long-running consumers accumulate memory and can hold stale DB connections. Use bounded workers (--max-jobs/--max-time equivalents) and a supervisor to restart them. If a handler throws and the worker exits, make sure your process manager restarts it — silent consumer death is a classic AMQP-in-Laravel trap.

Connection/config quirks. Broker credentials, vhost, and queue names are config-driven; a mismatch between the publishing process and the consuming worker's config (different .env, different queue names) results in messages that are published successfully but never consumed. When messages "disappear," check the queue/routing key on both sides first, then enable the new debug logging to confirm the publish actually reached the broker.

Extension points. The bus middleware pipeline and the transport abstraction are the intended seams. Add behavior via middleware rather than editing handlers or subclassing the bus. For custom transports or logging formats, the transport contract is the place to extend — but pin your version when doing so, since patch releases like v1.1.8 can touch the transport's internal logging behavior without a major bump.

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.
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
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle