# Laravel RabbitMQ Events A package for working with RabbitMQ messages as Laravel events. Automatically serialize and publish events to RabbitMQ, and consume messages from queues by converting them back into events. ## Features **Automatic event serialization** — Events implementing the `Broadcast` interface are automatically serialized and sent to RabbitMQ **Message consumption** — Command to consume messages from RabbitMQ with automatic deserialization and event dispatching **Default bindings** — The `BroadcastEvent` trait sets standard connection parameters for an event **Flexible configuration** — Support for multiple connections and parameterization for each event **Microservices architecture** — Ideal for data exchange between services ## Requirements - PHP 8.1+ - Laravel 10, 11 or 12 - RabbitMQ server ## Installation Install via Composer: ```bash composer require diffhead/laravel-rabbitmq ``` The package will be automatically registered thanks to Laravel Service Provider Discovery. ## Configuration Publish the configuration file: ```bash php artisan vendor:publish --provider="Diffhead\PHP\LaravelRabbitMQ\ServiceProvider" ``` ThisEnvironment Variables ```env # RabbitMQ Connection RABBITMQ_HOST=localhost RABBITMQ_PORT=5672 RABBITMQ_USER=guest RABBITMQ_PASSWORD=guest RABBITMQ_VHOST=/ # Default event parameters RABBITMQ_EVENT_CONNECTION=default RABBITMQ_EVENT_QUEUE=default RABBITMQ_EVENT_EXCHANGE=amq.direct RABBITMQ_EVENT_EXCHANGE_TYPE=direct RABBITMQ_EVENT_EXCHANGE_IS_DEFAULT=true RABBITMQ_EVENT_ROUTING_KEY= ``` ### Configuration Example ```php return [ 'connections' => [ 'default' => [ 'host' => env('RABBITMQ_HOST', 'localhost'), 'port' => env('RABBITMQ_PORT', 5672), 'user' => env('RABBITMQ_USER', 'guest'), 'password' => env('RABBITMQ_PASSWORD', 'guest'), 'vhost' => env('RABBITMQ_VHOST', '/'), ], 'secondary' => [ 'host' => env('RABBITMQ_SECONDARY_HOST', 'localhost'), 'port' => env('RABBITMQ_SECONDARY_PORT', 5672), 'user' => env('RABBITMQ_SECONDARY_USER', 'guest'), 'password' => env('RABBITMQ_SECONDARY_PASSWORD', 'guest'), 'vhost' => env('RABBITMQ_SECONDARY_VHOST', '/'), ] ], 'message' => [ 'serializer' => \Diffhead\PHP\LaravelRabbitMQ\Service\Serializer::class, 'unserializer' => \Diffhead\PHP\LaravelRabbitMQ\Service\Unserializer::class, ], 'event' => [ 'defaults' => [ 'connection' => env('RABBITMQ_EVENT_CONNECTION', 'default'), 'queue' => env('RABBITMQ_EVENT_QUEUE', 'default'), 'exchange' => env('RABBITMQ_EVENT_EXCHANGE', 'amq.direct'), 'exchange_type' => env('RABBITMQ_EVENT_EXCHANGE_TYPE', 'direct'), 'exchange_is_default' => (bool) env('RABBITMQ_EVENT_EXCHANGE_IS_DEFAULT', true), 'routing_key' => env('RABBITMQ_EVENT_ROUTING_KEY', ''), ], 'mapper' => \Diffhead\PHP\LaravelRabbitMQ\Service\EventMapper::class, 'map' => [ /** * Map events to queues and routing keys */ \App\Events\User\UserCreated::class => [ 'queues' => ['portal.users'], 'routing_keys' => ['user.created'], ], \App\Events\Meeting\MeetingCreated::class => [ 'queues' => ['portal.meetings'], 'routing_keys' => ['meeting.created'], ], ], ] ]; ``` ## Usage ### 1. Creating an Event for Publishing to RabbitMQ Create an event that implements the `Broadcast` interface: ```php namespace App\Events; use Diffhead\PHP\LaravelRabbitMQ\Event\Broadcast; use Diffhead\PHP\LaravelRabbitMQ\Trait\BroadcastEvent; use Illuminate\Foundation\Events\Dispatchable; class UserCreated implements Broadcast { use Dispatchable, BroadcastEvent; public function __construct( public int $userId, public string $email, public string $name, ) {} public function jsonSerialize(): array { return [ 'userId' => $this->userId, 'email' => $this->email, 'name' => $this->name, ]; } } ``` #### Event Parameters When implementing the `Broadcast` interface, you must define the following methods: - `getConnection(): string` — RabbitMQ connection name - `getQueue(): string` — Queue name - `getExchange(): string` — Exchange name - `getExchangeType(): string` — Exchange type (direct, topic, fanout, headers) - `getExchangeIsDefault(): bool` — Whether to use the default exchange - `getRoutingKey(): string` — Routing key for the message #### Using the BroadcastEvent Trait The `BroadcastEvent` trait provides implementations of all methods using default parameters from configuration: ```php namespace App\Events; use Diffhead\PHP\LaravelRabbitMQ\Event\Broadcast; use Diffhead\PHP\LaravelRabbitMQ\Trait\BroadcastEvent; class UserCreated implements Broadcast { use BroadcastEvent; public function __construct( public int $userId, public string $email, ) {} public function jsonSerialize(): array { return [ 'userId' => $this->userId, 'email' => $this->email, ]; } } ``` If you need special parameters for a specific event, override the necessary methods: ```php namespace App\Events; use Diffhead\PHP\LaravelRabbitMQ\Event\Broadcast; use Diffhead\PHP\LaravelRabbitMQ\Trait\BroadcastEvent; class CriticalAlert implements Broadcast { use BroadcastEvent; public function __construct( public string $message, ) {} public function getRoutingKey(): string { return 'alert.critical'; } public function getExchange(): string { return 'alerts.topic'; } public function getExchangeType(): string { return 'topic'; } public function jsonSerialize(): array { return [ 'message' => $this->message, ]; } } ``` ### 2. Publishing Events Events are automatically published when dispatched: ```php use App\Events\UserCreated; /** * Events implementing Broadcast are automatically sent to RabbitMQ */ UserCreated::dispatch(userId: 1, email: 'user@example.com', name: 'John Doe'); ``` ### 3. Consuming Messages from RabbitMQ Use the `rabbitmq:consume` command to listen for messages: ```bash ##################################################################################### # # Has following options: # # --connection=default - Connection name from config # --queue=default - Queue # --exchange=amq.direct - Exchange name # --exchange-type=direct - Exchange type # --exchange-is-default - Exchange is default, required for default exchanges # --routing-key=user.* - Listen routing keys, required for topic exchanges # --tag=myconsumer - Consumer tag for rabbitmq # ##################################################################################### php artisan rabbitmq:consume ``` #### Full Consumer Startup Example ```bash php artisan rabbitmq:consume \ --connection=default \ --queue=service.users \ --exchange=amq.direct \ --exchange-type=direct \ --routing-key=user.* \ --tag=service-users-consumer ``` ### 4. Handling Received Events When a message is received from RabbitMQ, it is automatically deserialized and dispatched as a Laravel event. You can listen to these events normally: ```php namespace App\Listeners; use App\Events\UserCreated; use Illuminate\Support\Log; class SendWelcomeEmail { public function handle(UserCreated $event): void { Log::info("User created: {$event->email}"); } } ``` Register the listener in `app/Providers/EventServiceProvider.php`: ```php protected $listen = [ \App\Events\UserCreated::class => [ \App\Listeners\SendWelcomeEmail::class, ], ]; ``` ## Architecture ### Event Publishing Flow ``` Laravel Event (Broadcast) ↓ PublishEvent (Listener) ↓ Serializer (JSON) ↓ RabbitMQ Exchange ↓ Queue ``` ### Message Consumption Flow ``` RabbitMQ Queue ↓ Message Consumer ↓ Unserializer (JSON) ↓ EventMapper (Event) ↓ EventEmitter (Service) ↓ Event Listeners ``` ## Microservices Architecture Example ### Service 1: Publishes event ```php namespace App\Events; use Diffhead\PHP\LaravelRabbitMQ\Event\Broadcast; use Diffhead\PHP\LaravelRabbitMQ\Trait\BroadcastEvent; class UserCreated implements Broadcast { use BroadcastEvent; public function __construct( public int $id, public string $email, public string $name, ) {} public function getRoutingKey(): string { return 'user.created'; } public function jsonSerialize(): array { return [ 'id' => $this->id, 'email' => $this->email, 'name' => $this->name, ]; } } ``` ```php use App\Events\UserCreated; /** * Controller method */ public function store(Request $request) { $user = User::create($request->validated()); UserCreated::dispatch($user->id, $user->email, $user->name); return response()->json($user, 201); } ``` ### Service 2: Receives event Map event using configuration: ```php 'map' => [ \App\Events\UserCreated::class => [ 'queues' => ['service2.users'], 'routing_keys' => ['user.created'] ] ] ``` Then implement and register event listener: ```php namespace App\Listeners; use App\Events\UserCreated; class SyncUserToCalendar { public function handle(UserCreated $event): void { CalendarUser::create([ 'external_id' => $event->id, 'email' => $event->email, 'name' => $event->name, ]); } } ``` Start consumer ```bash php artisan rabbitmq:consume --queue=service2.users --routing-key=user.* --exchange=amq.topic --exchange-type=topic --exchange-is-default ``` ## Serialization The package uses JSON for serialization/deserialization of data via `Serializer` and `Unserializer` interfaces. ### Custom Serialization You can use your own serialization classes by implementing interfaces and overriding following configuration entities: ```php 'message' => [ 'serializer' => \App\Services\CustomSerializer::class, 'unserializer' => \App\Services\CustomUnserializer::class, ], ``` ## Mapping The package maps rabbitmq message to application events ### Custom mapping You can use your own mapping logic by implementing EventMapper interface and overriding the following configuration entity: ```php 'event' => [ 'mapper' => \App\Services\CustomEventMapper::class, ] ```