Installation
composer require gdx/p-service-bus
Add the service provider to config/app.php:
'providers' => [
// ...
GDX\PServiceBus\ServiceBusServiceProvider::class,
],
Basic Configuration Publish the config file:
php artisan vendor:publish --provider="GDX\PServiceBus\ServiceBusServiceProvider" --tag="config"
Edit config/pservicebus.php to define your bus (e.g., default):
'default' => [
'driver' => 'sync', // or 'async', 'queue', etc.
'options' => [
// Driver-specific config (e.g., queue connection for 'queue' driver)
],
],
First Use Case: Dispatching a Command Define a command:
namespace App\Commands;
use GDX\PServiceBus\Contracts\Command;
class CreateUser implements Command
{
public function __construct(public string $name, public string $email) {}
}
Dispatch it in a controller or service:
use GDX\PServiceBus\Facades\ServiceBus;
ServiceBus::dispatch(new CreateUser('John Doe', '[email protected]'));
Handling Commands Register a handler in a service provider:
$this->app->bind(
GDX\PServiceBus\Contracts\Handler::class,
App\Handlers\CreateUserHandler::class
);
Implement the handler:
namespace App\Handlers;
use App\Commands\CreateUser;
use GDX\PServiceBus\Contracts\Handler;
class CreateUserHandler implements Handler
{
public function handle(CreateUser $command)
{
// Business logic here
return true;
}
}
Dispatching
Use ServiceBus::dispatch() for synchronous execution or ServiceBus::dispatchAsync() for background processing.
// Sync (blocks until handled)
$result = ServiceBus::dispatch(new Command());
// Async (non-blocking)
ServiceBus::dispatchAsync(new Command());
Middleware Integration Apply middleware to commands globally or per-command:
// Global middleware (in ServiceBusServiceProvider)
$this->app->make('pservicebus')->middleware([
\App\Middleware\LogCommand::class,
\App\Middleware\ValidateCommand::class,
]);
// Per-command middleware
ServiceBus::dispatch(new Command())
->withMiddleware([\App\Middleware\CustomMiddleware::class]);
Event-Driven Extensions
Listen for bus events (e.g., CommandDispatched, CommandHandled):
// In a service provider
event(new \GDX\PServiceBus\Events\CommandDispatched($command));
Testing Mock the bus in tests:
$bus = Mockery::mock('overload', \GDX\PServiceBus\Facades\ServiceBus::class);
$bus->shouldReceive('dispatch')->once()->withArgs([$command]);
pservicebus.php:
'async' => [
'driver' => 'queue',
'options' => [
'connection' => 'redis',
'queue' => 'commands',
],
],
queue driver:
'queue' => [
'options' => [
'retry_after' => 60, // Retry after 60 seconds
],
],
$handler = app()->make(\GDX\PServiceBus\Contracts\Handler::class);
$handler->handle($command);
Handler Registration
AppServiceProvider or a dedicated provider:
$this->app->bind(
\GDX\PServiceBus\Contracts\Handler::class,
App\Handlers\{CommandName}Handler::class
);
interface CreateUserHandlerInterface extends Handler {}
Async Driver Quirks
'queue' => [
'options' => [
'queue' => 'commands',
'fail_queue' => 'commands.failed',
],
],
Middleware Order
->before() and ->after() for explicit ordering:
ServiceBus::dispatch(new Command())
->withMiddleware([
\App\Middleware\First::class,
])
->before(\App\Middleware\PreValidation::class)
->after(\App\Middleware\PostLogging::class);
Circular Dependencies
Bus facade or container to avoid direct instantiation:
// Bad: Direct instantiation
$bus = new \GDX\PServiceBus\Bus();
// Good: Use facade
ServiceBus::dispatch(new NestedCommand());
pservicebus.php:
'debug' => env('PSERVICEBUS_DEBUG', false),
use Illuminate\Support\Facades\Log;
class CreateUserHandler implements Handler
{
public function handle(CreateUser $command)
{
Log::debug('Handling CreateUser', ['command' => $command]);
// ...
}
}
Custom Drivers
Extend the Driver interface to support new transport layers (e.g., gRPC, Kafka):
namespace App\Drivers;
use GDX\PServiceBus\Contracts\Driver;
class GrpcDriver implements Driver
{
public function dispatch($command) { /* ... */ }
public function dispatchAsync($command) { /* ... */ }
}
Register it in pservicebus.php:
'grpc' => [
'driver' => \App\Drivers\GrpcDriver::class,
'options' => [...],
],
Command Validation Use Laravel’s validation pipeline:
namespace App\Middleware;
use Closure;
use Illuminate\Validation\ValidationException;
class ValidateCommand
{
public function handle($command, Closure $next)
{
$validator = validator($command, [
'email' => 'required|email',
]);
if ($validator->fails()) {
throw new ValidationException($validator);
}
return $next($command);
}
}
Performance Optimization
ServiceBus::dispatchBatch() (if supported).$handler = app()->makeWith(\App\Handlers\CreateUserHandler::class);
How can I help you explore Laravel packages today?