Version 1.0.0
This commit is contained in:
448
README.md
Normal file
448
README.md
Normal file
@@ -0,0 +1,448 @@
|
||||
# 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,
|
||||
]
|
||||
```
|
||||
Reference in New Issue
Block a user