Skip to content

Getting Started

A lightweight, extensible message bus implementation for Laravel supporting both Command and Query patterns with middleware pipeline architecture.

  • PHP 8.5+
  • Laravel 12.28+
Terminal window
composer require cline/message-bus

The service provider is auto-discovered. Handler discovery works automatically in local development.

Dispatch commands for write operations:

use Cline\MessageBus\Facades\CommandBus;
$result = CommandBus::dispatch(new CreateUserCommand(
email: 'user@example.com',
name: 'John Doe',
));

Execute queries for read operations:

use Cline\MessageBus\Facades\QueryBus;
$user = QueryBus::ask(new GetUserByEmailQuery(
email: 'user@example.com',
));

This package implements Command Query Responsibility Segregation (CQRS):

  • Commands - Write operations that modify state
  • Queries - Read operations that return data

Separating reads and writes allows you to optimize each path independently.

Both buses use Laravel’s Pipeline to process messages through middleware:

Command → Middleware 1 → Middleware 2 → Handler → Result

Configure middleware globally via config or per-dispatch with withMiddleware().

In local development, handlers are discovered automatically via PHP attributes:

use Cline\MessageBus\Commands\Attributes\AsCommandHandler;
#[AsCommandHandler(CreateUserCommand::class)]
final readonly class CreateUserHandler
{
public function handle(CreateUserCommand $command): User
{
// Handle the command
}
}

For production, cache the handler map for performance.

Publish the config file:

Terminal window
php artisan vendor:publish --tag=message-bus-config

Config options:

return [
'paths' => [
'command_handlers' => base_path('bootstrap/cache/command-handlers.php'),
'query_handlers' => base_path('bootstrap/cache/query-handlers.php'),
],
];

The discovery system scans these directory patterns:

  • Legacy: Application/CommandHandler/ and Application/QueryHandler/
  • Modern: Application/Command/Handlers/ and Application/Query/Handlers/

All handler classes must be within the Monolith\ namespace.