laravelcollective/bus
A command bus for Laravel that dispatches commands to their handlers, with middleware support and container integration for cleaner, decoupled application logic.
laravelcollective/bus is the Laravel 5.0-era Illuminate\Bus command bus, extracted into the Collective\Bus namespace so it could keep working after the framework replaced it with the pipeline-based dispatch()/Jobs system in 5.1. Practically everything useful lives in the 5.0 bus: a Dispatcher, a CommandBus contract, the SelfHandling/SelfHandlingCommand traits, a ShouldBeQueued marker interface, and the DispatchesCommands trait you mix into controllers. Treat the src/ directory as the documentation — the README is thin and there is no config file, migrations, or published assets.
Minimal setup:
composer require laravelcollective/bus — on a modern Laravel this will almost certainly fail on constraints (last tag is December 2015, pinned to PHP 5.x / Laravel ~5.0–5.1). The realistic path today is dev-master on a legacy app, or vendoring the handful of classes you need.config/app.php providers: Collective\Bus\BusServiceProvider::class. This is what binds the dispatcher into the container (typically aliased onto Illuminate\Contracts\Bus\Dispatcher), so provider order matters if anything resolves the bus in its own register().DispatchesCommands trait to App\Http\Controllers\Controller (or a base service class) to get dispatch() / dispatchFrom().app(Illuminate\Contracts\Bus\Dispatcher::class) should return the collective dispatcher, not the framework one.First use case to try: a single side-effecting action moved out of a controller. Create App\Commands\RegisterUser as a plain DTO with public properties, create App\Commands\RegisterUserHandler with a handle(RegisterUser $command) method, then $this->dispatch(new RegisterUser($input)) from the controller. If that round-trips, the bus is wired correctly; everything else is variants on it.
Command + handler pairs (the default). Keep commands as dumb, serializable value objects — public scalar/array properties, no dependencies injected beyond what dispatchFrom marshals. Put all behaviour and injected services (UserRepository, Mailer, etc.) in the handler. The dispatcher resolves handlers out of the container by convention (CommandClass → CommandClassHandler); if you rename or namespace things asymmetrically, you'll get a container resolution exception rather than a helpful message, so bind handlers explicitly when the convention doesn't hold.
Self-handling commands. For small actions where the split is ceremony, implement the SelfHandling trait on the command and give it its own handle(). Good for one-off actions dispatched in two or three places; bad for anything you want to unit test in isolation or queue, since you end up injecting services into the command itself.
dispatchFrom for HTTP input. $this->dispatchFrom(RegisterUser::class, $request) marshals request input onto the command's public properties. This is the 5.0 idiom that FormRequest + Jobs later replaced. Two consequences: only public properties are populated, and the marshalling is a straight assignment — so validation belongs in the command's rules (if you're using the validating-command pattern) or explicitly at the top of the handler. Don't rely on the request object leaking into the command.
Queueing. Implement ShouldBeQueued on the command and the dispatcher pushes it through the queue resolver instead of calling the handler inline. You need the queue traits the package/framework provides (InteractsWithQueue, SerializesModels, etc.) on the command, and the command's $connection/$queue properties select the destination. This is where the package earns its keep in a legacy app: you can convert a synchronous handler to a queued one by adding an interface and nothing else.
Pipelines and composition. The dispatcher supports a pipeThrough array of middleware classes wrapping handle — useful for cross-cutting concerns (transaction wrapping, logging, authorization) without touching handlers. Reserve it for genuinely universal behaviour; command-specific concerns belong inside the handler.
Controllers stay thin. A controller method should be: build command, dispatch, redirect/respond. Handler = transaction boundary + domain work. Fire domain events from inside the handler after the work commits, not from the controller before dispatch — otherwise a failed handler leaves you with an event that claims success.
Illuminate\Bus\Dispatcher with the dispatch() helper and DispatchesJobs is the replacement; 5.5+ added Bus::fake() and job middleware. Only adopt this for an app already rooted in the 5.0 idiom. Never introduce it into a new codebase.Illuminate\Contracts\Bus\Dispatcher and getting the framework's dispatcher, so queued commands silently execute synchronously or fail to resolve handlers. Confirm which implementation you actually got, and check that your provider is registered after the framework's bus provider.SerializesModels where available and keep commands to scalars/IDs when you can.dispatchFrom is silent about missing input. A property the request never populates stays at its default (often null) and the handler receives it without complaint. Validate in the handler, or at minimum assert command invariants in a constructor/handle guard.Bus::fake() here. Mock or swap the CommandBus/dispatcher binding to assert what was dispatched, and separately instantiate handlers directly with mocked collaborators — the handler is just a class with a handle() method, so most of your test suite shouldn't need the bus at all.pipeThrough middleware array, and container bindings for handlers. Those three cover nearly every customization request.How can I help you explore Laravel packages today?