Added PublishEvent listener connection and queue configuration feature
This commit is contained in:
437
README.md
437
README.md
@@ -2,14 +2,6 @@
|
|||||||
|
|
||||||
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.
|
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
|
## Requirements
|
||||||
|
|
||||||
- PHP 8.1+
|
- PHP 8.1+
|
||||||
@@ -26,89 +18,12 @@ composer require diffhead/laravel-rabbitmq
|
|||||||
|
|
||||||
The package will be automatically registered thanks to Laravel Service Provider Discovery.
|
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
|
## Usage
|
||||||
|
|
||||||
### 1. Creating an Event for Publishing to RabbitMQ
|
### 1. Creating regular events for publishing to a RabbitMQ
|
||||||
|
|
||||||
Create an event that implements the `Broadcast` interface:
|
Create an event that implements the `Broadcast` interface. `Broadcast` interface
|
||||||
|
extends `JsonSerializable` then your event should implement `jsonSerialize` method.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
namespace App\Events;
|
namespace App\Events;
|
||||||
@@ -140,18 +55,28 @@ class UserCreated implements Broadcast
|
|||||||
|
|
||||||
#### Event Parameters
|
#### Event Parameters
|
||||||
|
|
||||||
When implementing the `Broadcast` interface, you must define the following methods:
|
When implementing the `Broadcast` interface, you must define the following methods
|
||||||
|
for targeting RabbitMQ message:
|
||||||
|
|
||||||
- `getConnection(): string` — RabbitMQ connection name
|
- `getConnection(): string` — connection name defined in configuration
|
||||||
- `getQueue(): string` — Queue name
|
- `getQueue(): string` — Queue name
|
||||||
- `getExchange(): string` — Exchange name
|
- `getExchange(): string` — Exchange name
|
||||||
- `getExchangeType(): string` — Exchange type (direct, topic, fanout, headers)
|
- `getExchangeType(): string` — Exchange type (direct, topic, fanout, headers)
|
||||||
- `getExchangeIsDefault(): bool` — Whether to use the default exchange
|
- `getExchangeIsDefault(): bool` — Whether to use the default exchange
|
||||||
- `getRoutingKey(): string` — Routing key for the message
|
- `getRoutingKey(): string` — Routing key for the message
|
||||||
|
|
||||||
#### Using the BroadcastEvent Trait
|
#### Using the BroadcastEvent trait
|
||||||
|
|
||||||
The `BroadcastEvent` trait provides implementations of all methods using default parameters from configuration:
|
The `BroadcastEvent` trait provides implementations of all methods using default parameters from configuration. You can directly override method's return value for
|
||||||
|
customizing concrete event or override this behaviour globally by changing
|
||||||
|
following env variables:
|
||||||
|
|
||||||
|
* `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=`
|
||||||
|
|
||||||
```php
|
```php
|
||||||
namespace App\Events;
|
namespace App\Events;
|
||||||
@@ -162,19 +87,6 @@ use Diffhead\PHP\LaravelRabbitMQ\Trait\BroadcastEvent;
|
|||||||
class UserCreated implements Broadcast
|
class UserCreated implements Broadcast
|
||||||
{
|
{
|
||||||
use BroadcastEvent;
|
use BroadcastEvent;
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
public int $userId,
|
|
||||||
public string $email,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function jsonSerialize(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'userId' => $this->userId,
|
|
||||||
'email' => $this->email,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -190,10 +102,6 @@ class CriticalAlert implements Broadcast
|
|||||||
{
|
{
|
||||||
use BroadcastEvent;
|
use BroadcastEvent;
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
public string $message,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function getRoutingKey(): string
|
public function getRoutingKey(): string
|
||||||
{
|
{
|
||||||
return 'alert.critical';
|
return 'alert.critical';
|
||||||
@@ -208,32 +116,76 @@ class CriticalAlert implements Broadcast
|
|||||||
{
|
{
|
||||||
return 'topic';
|
return 'topic';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function jsonSerialize(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'message' => $this->message,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Publishing Events
|
#### Publishing Events
|
||||||
|
|
||||||
Events are automatically published when dispatched:
|
Events are automatically published when dispatched.
|
||||||
|
|
||||||
|
`\Diffhead\PHP\LaravelRabbitMQ\Listener\PublishEvent`
|
||||||
|
|
||||||
|
This listener implements `ShouldQueue` interface then
|
||||||
|
you can setup his behaviour by chaning following env variables:
|
||||||
|
|
||||||
|
* `RABBITMQ_EVENT_PUBLISHING_CONNECTION=sync`
|
||||||
|
* `RABBITMQ_EVENT_PUBLISHING_QUEUE=default`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
use App\Events\UserCreated;
|
App\Events\UserCreated::dispatch(
|
||||||
|
userId: 1,
|
||||||
/**
|
email: 'user@example.com',
|
||||||
* Events implementing Broadcast are automatically sent to RabbitMQ
|
name: 'John Doe'
|
||||||
*/
|
);
|
||||||
UserCreated::dispatch(userId: 1, email: 'user@example.com', name: 'John Doe');
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Consuming Messages from RabbitMQ
|
### 2. Consuming Messages from RabbitMQ
|
||||||
|
|
||||||
Use the `rabbitmq:consume` command to listen for messages:
|
#### Map events
|
||||||
|
|
||||||
|
Add regular laravel's application event classes mapping to
|
||||||
|
RabbitMQ queues and routing keys using `rabbitmq.event.map` section.
|
||||||
|
|
||||||
|
Event should implement `\Diffhead\PHP\LaravelRabbitMQ\Interface\Event`
|
||||||
|
with no methods if you are using default library mapper.
|
||||||
|
|
||||||
|
```php
|
||||||
|
// config/rabbitmq.php
|
||||||
|
|
||||||
|
'map' => [
|
||||||
|
\App\Events\User\UserCreated::class => [
|
||||||
|
'queues' => ['portal.users'],
|
||||||
|
'routing_keys' => ['user.created'],
|
||||||
|
],
|
||||||
|
\App\Events\Meeting\MeetingCreated::class => [
|
||||||
|
'queues' => ['portal.meetings'],
|
||||||
|
'routing_keys' => ['meeting.created'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
You can set empty array for matching event of all queues or routing keys.
|
||||||
|
|
||||||
|
Follow this example for mapping event with `amq.direct` exchange which not
|
||||||
|
uses routing keys:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// config/rabbitmq.php
|
||||||
|
|
||||||
|
'map' => [
|
||||||
|
\App\Events\User\UserCreated::class => [
|
||||||
|
'queues' => ['portal.users'],
|
||||||
|
'routing_keys' => [],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Consume RabbitMQ queues
|
||||||
|
|
||||||
|
Use the `rabbitmq:consume` command to listen for messages.
|
||||||
|
Consumer will listen rabbitmq bus and emit mapped event from as regular laravel event.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
#####################################################################################
|
#####################################################################################
|
||||||
@@ -252,7 +204,7 @@ Use the `rabbitmq:consume` command to listen for messages:
|
|||||||
|
|
||||||
php artisan rabbitmq:consume
|
php artisan rabbitmq:consume
|
||||||
```
|
```
|
||||||
#### Full Consumer Startup Example
|
##### Full Consumer Startup Example
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
php artisan rabbitmq:consume \
|
php artisan rabbitmq:consume \
|
||||||
@@ -264,7 +216,7 @@ php artisan rabbitmq:consume \
|
|||||||
--tag=service-users-consumer
|
--tag=service-users-consumer
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. Handling Received Events
|
##### 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:
|
When a message is received from RabbitMQ, it is automatically deserialized and dispatched as a Laravel event. You can listen to these events normally:
|
||||||
|
|
||||||
@@ -274,7 +226,7 @@ namespace App\Listeners;
|
|||||||
use App\Events\UserCreated;
|
use App\Events\UserCreated;
|
||||||
use Illuminate\Support\Log;
|
use Illuminate\Support\Log;
|
||||||
|
|
||||||
class SendWelcomeEmail
|
class LogUserCreation
|
||||||
{
|
{
|
||||||
public function handle(UserCreated $event): void
|
public function handle(UserCreated $event): void
|
||||||
{
|
{
|
||||||
@@ -288,139 +240,24 @@ Register the listener in `app/Providers/EventServiceProvider.php`:
|
|||||||
```php
|
```php
|
||||||
protected $listen = [
|
protected $listen = [
|
||||||
\App\Events\UserCreated::class => [
|
\App\Events\UserCreated::class => [
|
||||||
\App\Listeners\SendWelcomeEmail::class,
|
\App\Listeners\LogUserCreation::class,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
|
or using Laravel's `\Illuminate\Support\Facades\Event` facade.
|
||||||
|
|
||||||
## Architecture
|
### 3. Configure and customize logics
|
||||||
|
|
||||||
### Event Publishing Flow
|
#### Serialization
|
||||||
|
|
||||||
```
|
The package does serialization/deserialization of message data via following interfaces:
|
||||||
Laravel Event (Broadcast)
|
|
||||||
↓
|
|
||||||
PublishEvent (Listener)
|
|
||||||
↓
|
|
||||||
Serializer (JSON)
|
|
||||||
↓
|
|
||||||
RabbitMQ Exchange
|
|
||||||
↓
|
|
||||||
Queue
|
|
||||||
```
|
|
||||||
|
|
||||||
### Message Consumption Flow
|
* `\Diffhead\PHP\LaravelRabbitMQ\Interface\Serializer`
|
||||||
|
* `\Diffhead\PHP\LaravelRabbitMQ\Interface\Unserializer`
|
||||||
|
|
||||||
```
|
By default implementations library interacts with JSON data.
|
||||||
RabbitMQ Queue
|
|
||||||
↓
|
|
||||||
Message Consumer
|
|
||||||
↓
|
|
||||||
Unserializer (JSON)
|
|
||||||
↓
|
|
||||||
EventMapper (Event)
|
|
||||||
↓
|
|
||||||
EventEmitter (Service)
|
|
||||||
↓
|
|
||||||
Event Listeners
|
|
||||||
```
|
|
||||||
|
|
||||||
## Microservices Architecture Example
|
##### Custom Serialization
|
||||||
|
|
||||||
### 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
|
You can use your own serialization classes by implementing
|
||||||
interfaces and overriding following configuration entities:
|
interfaces and overriding following configuration entities:
|
||||||
@@ -432,11 +269,7 @@ interfaces and overriding following configuration entities:
|
|||||||
],
|
],
|
||||||
```
|
```
|
||||||
|
|
||||||
## Mapping
|
##### Custom mapping
|
||||||
|
|
||||||
The package maps rabbitmq message to application events
|
|
||||||
|
|
||||||
### Custom mapping
|
|
||||||
|
|
||||||
You can use your own mapping logic by implementing EventMapper
|
You can use your own mapping logic by implementing EventMapper
|
||||||
interface and overriding the following configuration entity:
|
interface and overriding the following configuration entity:
|
||||||
@@ -446,3 +279,91 @@ interface and overriding the following configuration entity:
|
|||||||
'mapper' => \App\Services\CustomEventMapper::class,
|
'mapper' => \App\Services\CustomEventMapper::class,
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Configuration
|
||||||
|
|
||||||
|
Publish the configuration file if it not exists:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php artisan vendor:publish --provider="Diffhead\PHP\LaravelRabbitMQ\ServiceProvider"
|
||||||
|
```
|
||||||
|
|
||||||
|
Used environment variables:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# RabbitMQ Connection
|
||||||
|
RABBITMQ_HOST=localhost
|
||||||
|
RABBITMQ_PORT=5672
|
||||||
|
RABBITMQ_USER=guest
|
||||||
|
RABBITMQ_PASSWORD=guest
|
||||||
|
RABBITMQ_VHOST=/
|
||||||
|
|
||||||
|
# Events publishing listener parameters
|
||||||
|
RABBITMQ_EVENT_PUBLISHING_CONNECTION=sync
|
||||||
|
RABBITMQ_EVENT_PUBLISHING_QUEUE=default
|
||||||
|
|
||||||
|
# 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=
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Example of `config/rabbitmq.php`
|
||||||
|
|
||||||
|
```php
|
||||||
|
// config/rabbitmq.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', ''),
|
||||||
|
],
|
||||||
|
'publishing' => [
|
||||||
|
'connection' => env('RABBITMQ_EVENT_PUBLISHING_CONNECTION', 'sync'),
|
||||||
|
'queue' => env('RABBITMQ_EVENT_PUBLISHING_QUEUE', 'default'),
|
||||||
|
],
|
||||||
|
'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'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
"description": "A laravel package for events emitting between services using RabbitMQ as message broker.",
|
"description": "A laravel package for events emitting between services using RabbitMQ as message broker.",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"laravel", "rabbitmq", "event", "emit", "microservice",
|
"laravel", "rabbitmq", "event", "emit", "microservice",
|
||||||
"pipeline", "data exchanging", "message broker"
|
"pipeline", "data exchanging", "message", "broker", "php8",
|
||||||
|
"php", "amqp"
|
||||||
],
|
],
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
'connections' => [
|
'connections' => [
|
||||||
|
/**
|
||||||
|
* This section helps you to configure
|
||||||
|
* RabbitMQ connections for consumers or events
|
||||||
|
* publishing.
|
||||||
|
*/
|
||||||
'default' => [
|
'default' => [
|
||||||
'host' => env('RABBITMQ_HOST', 'localhost'),
|
'host' => env('RABBITMQ_HOST', 'localhost'),
|
||||||
'port' => env('RABBITMQ_PORT', 5672),
|
'port' => env('RABBITMQ_PORT', 5672),
|
||||||
@@ -11,10 +16,23 @@ return [
|
|||||||
]
|
]
|
||||||
],
|
],
|
||||||
'message' => [
|
'message' => [
|
||||||
|
/**
|
||||||
|
* Serializer converts a PHP object into \PhpAmqpLib\Message\AMQPMessage
|
||||||
|
*/
|
||||||
'serializer' => \Diffhead\PHP\LaravelRabbitMQ\Service\Serializer::class,
|
'serializer' => \Diffhead\PHP\LaravelRabbitMQ\Service\Serializer::class,
|
||||||
|
/**
|
||||||
|
* Unserializer converts \PhpAmqpLib\Message\AMQPMessage into a PHP array
|
||||||
|
*/
|
||||||
'unserializer' => \Diffhead\PHP\LaravelRabbitMQ\Service\Unserializer::class,
|
'unserializer' => \Diffhead\PHP\LaravelRabbitMQ\Service\Unserializer::class,
|
||||||
],
|
],
|
||||||
'event' => [
|
'event' => [
|
||||||
|
/**
|
||||||
|
* \Diffhead\PHP\LaravelRabbitMQ\Trait\BroadcastEvent
|
||||||
|
*
|
||||||
|
* This trait helps you to configure where the event should be broadcasted
|
||||||
|
* by default. You can override these settings directly in the event class
|
||||||
|
* or globally using environment variables.
|
||||||
|
*/
|
||||||
'defaults' => [
|
'defaults' => [
|
||||||
'connection' => env('RABBITMQ_EVENT_CONNECTION', 'default'),
|
'connection' => env('RABBITMQ_EVENT_CONNECTION', 'default'),
|
||||||
'queue' => env('RABBITMQ_EVENT_QUEUE', 'default'),
|
'queue' => env('RABBITMQ_EVENT_QUEUE', 'default'),
|
||||||
@@ -23,11 +41,30 @@ return [
|
|||||||
'exchange_is_default' => (bool) env('RABBITMQ_EVENT_EXCHANGE_IS_DEFAULT', true),
|
'exchange_is_default' => (bool) env('RABBITMQ_EVENT_EXCHANGE_IS_DEFAULT', true),
|
||||||
'routing_key' => (string) env('RABBITMQ_EVENT_ROUTING_KEY', ''),
|
'routing_key' => (string) env('RABBITMQ_EVENT_ROUTING_KEY', ''),
|
||||||
],
|
],
|
||||||
|
/**
|
||||||
|
* \Diffhead\PHP\LaravelRabbitMQ\Listener\PublishEvent
|
||||||
|
*
|
||||||
|
* This listener publishes events to a rabbitmq bus and
|
||||||
|
* does that using laravel queues.
|
||||||
|
*
|
||||||
|
* You can configure which connection and queue to use for.
|
||||||
|
*/
|
||||||
|
'publishing' => [
|
||||||
|
'connection' => env('RABBITMQ_EVENT_PUBLISHING_CONNECTION', 'sync'),
|
||||||
|
'queue' => env('RABBITMQ_EVENT_PUBLISHING_QUEUE', 'default'),
|
||||||
|
],
|
||||||
|
/**
|
||||||
|
* This mapper detects event which should
|
||||||
|
* be emitted when RabbitMQ message received.
|
||||||
|
*/
|
||||||
'mapper' => \Diffhead\PHP\LaravelRabbitMQ\Service\EventMapper::class,
|
'mapper' => \Diffhead\PHP\LaravelRabbitMQ\Service\EventMapper::class,
|
||||||
|
/**
|
||||||
|
* Map events with their queues and routing keys.
|
||||||
|
*/
|
||||||
'map' => [
|
'map' => [
|
||||||
/**
|
/**
|
||||||
* Example:
|
* Example:
|
||||||
*
|
*
|
||||||
* \App\Shared\Event\User\UserCreated::class => [
|
* \App\Shared\Event\User\UserCreated::class => [
|
||||||
* 'queues' => ['portal.calendar.users'],
|
* 'queues' => ['portal.calendar.users'],
|
||||||
* 'routing_keys' => ['user.created'],
|
* 'routing_keys' => ['user.created'],
|
||||||
@@ -38,6 +75,5 @@ return [
|
|||||||
* ],
|
* ],
|
||||||
*/
|
*/
|
||||||
],
|
],
|
||||||
|
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace Diffhead\PHP\LaravelRabbitMQ\Command;
|
namespace Diffhead\PHP\LaravelRabbitMQ\Command;
|
||||||
|
|
||||||
use Diffhead\PHP\LaravelRabbitMQ\Dto\ConsumerParameters;
|
use Diffhead\PHP\LaravelRabbitMQ\Dto\ConsumerParameters;
|
||||||
use Diffhead\PHP\LaravelRabbitMQ\Object\Connection;
|
use Diffhead\PHP\LaravelRabbitMQ\Object\ConnectionWithChannel;
|
||||||
use Diffhead\PHP\LaravelRabbitMQ\Object\Exchange;
|
use Diffhead\PHP\LaravelRabbitMQ\Object\Exchange;
|
||||||
use Diffhead\PHP\LaravelRabbitMQ\Object\ExchangeDeclaration;
|
use Diffhead\PHP\LaravelRabbitMQ\Object\ExchangeDeclaration;
|
||||||
use Diffhead\PHP\LaravelRabbitMQ\Object\Queue;
|
use Diffhead\PHP\LaravelRabbitMQ\Object\Queue;
|
||||||
@@ -31,7 +31,7 @@ class Consume extends Command
|
|||||||
*/
|
*/
|
||||||
protected $description = 'Consume messages from RabbitMQ';
|
protected $description = 'Consume messages from RabbitMQ';
|
||||||
|
|
||||||
private ?Connection $connection = null;
|
private ?ConnectionWithChannel $connection = null;
|
||||||
|
|
||||||
public function handle(
|
public function handle(
|
||||||
Configuration $configuration,
|
Configuration $configuration,
|
||||||
@@ -40,7 +40,10 @@ class Consume extends Command
|
|||||||
LoggerInterface $logger
|
LoggerInterface $logger
|
||||||
): void {
|
): void {
|
||||||
$params = ConsumerParameters::fromArray($this->options());
|
$params = ConsumerParameters::fromArray($this->options());
|
||||||
$config = $configuration->get($params->connection->value() ?? 'default');
|
|
||||||
|
$config = $configuration->getConnection(
|
||||||
|
$params->connection->value() ?? 'default'
|
||||||
|
);
|
||||||
|
|
||||||
$queue = $this->getQueue($params);
|
$queue = $this->getQueue($params);
|
||||||
|
|
||||||
|
|||||||
@@ -13,11 +13,15 @@ use Diffhead\PHP\LaravelRabbitMQ\Object\QueueDeclaration;
|
|||||||
use Diffhead\PHP\LaravelRabbitMQ\Service\Configuration;
|
use Diffhead\PHP\LaravelRabbitMQ\Service\Configuration;
|
||||||
use Diffhead\PHP\LaravelRabbitMQ\Service\Connector;
|
use Diffhead\PHP\LaravelRabbitMQ\Service\Connector;
|
||||||
use Diffhead\PHP\LaravelRabbitMQ\Event\Broadcast;
|
use Diffhead\PHP\LaravelRabbitMQ\Event\Broadcast;
|
||||||
|
use Diffhead\PHP\LaravelRabbitMQ\Object\Publishing;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
|
||||||
class PublishEvent implements ShouldQueue
|
class PublishEvent implements ShouldQueue
|
||||||
{
|
{
|
||||||
|
private Publishing $publishing;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private Configuration $configuration,
|
private Configuration $configuration,
|
||||||
private Connector $connector,
|
private Connector $connector,
|
||||||
@@ -26,7 +30,7 @@ class PublishEvent implements ShouldQueue
|
|||||||
|
|
||||||
public function handle(Broadcast $event): void
|
public function handle(Broadcast $event): void
|
||||||
{
|
{
|
||||||
$config = $this->configuration->get($event->getConnection());
|
$config = $this->configuration->getConnection($event->getConnection());
|
||||||
|
|
||||||
$queue = new Queue(
|
$queue = new Queue(
|
||||||
name: $event->getQueue(),
|
name: $event->getQueue(),
|
||||||
@@ -59,4 +63,24 @@ class PublishEvent implements ShouldQueue
|
|||||||
$connection->connection()->close();
|
$connection->connection()->close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function viaConnection(): string
|
||||||
|
{
|
||||||
|
return $this->getOrCreatePublishing()->connection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function viaQueue(): string
|
||||||
|
{
|
||||||
|
return $this->getOrCreatePublishing()->queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getOrCreatePublishing(): Publishing
|
||||||
|
{
|
||||||
|
if (! isset($this->publishing)) {
|
||||||
|
$configuration = App::make(Configuration::class);
|
||||||
|
$this->publishing = $configuration->getPublishing();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->publishing;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Diffhead\PHP\LaravelRabbitMQ\Object;
|
|
||||||
|
|
||||||
class Configuration
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private string $host,
|
|
||||||
private int $port,
|
|
||||||
private string $user,
|
|
||||||
private string $password,
|
|
||||||
private string $vhost,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function host(): string
|
|
||||||
{
|
|
||||||
return $this->host;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function port(): int
|
|
||||||
{
|
|
||||||
return $this->port;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function user(): string
|
|
||||||
{
|
|
||||||
return $this->user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function password(): string
|
|
||||||
{
|
|
||||||
return $this->password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function vhost(): string
|
|
||||||
{
|
|
||||||
return $this->vhost;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,23 +4,38 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Diffhead\PHP\LaravelRabbitMQ\Object;
|
namespace Diffhead\PHP\LaravelRabbitMQ\Object;
|
||||||
|
|
||||||
use PhpAmqpLib\Channel\AMQPChannel;
|
|
||||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
|
||||||
|
|
||||||
class Connection
|
class Connection
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private AMQPStreamConnection $connection,
|
private string $host,
|
||||||
private AMQPChannel $channel
|
private int $port,
|
||||||
|
private string $user,
|
||||||
|
private string $password,
|
||||||
|
private string $vhost,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function connection(): AMQPStreamConnection
|
public function host(): string
|
||||||
{
|
{
|
||||||
return $this->connection;
|
return $this->host;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function channel(): AMQPChannel
|
public function port(): int
|
||||||
{
|
{
|
||||||
return $this->channel;
|
return $this->port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user(): string
|
||||||
|
{
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function password(): string
|
||||||
|
{
|
||||||
|
return $this->password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function vhost(): string
|
||||||
|
{
|
||||||
|
return $this->vhost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/Object/ConnectionWithChannel.php
Normal file
26
src/Object/ConnectionWithChannel.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Diffhead\PHP\LaravelRabbitMQ\Object;
|
||||||
|
|
||||||
|
use PhpAmqpLib\Channel\AMQPChannel;
|
||||||
|
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||||
|
|
||||||
|
class ConnectionWithChannel
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private AMQPStreamConnection $connection,
|
||||||
|
private AMQPChannel $channel
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function connection(): AMQPStreamConnection
|
||||||
|
{
|
||||||
|
return $this->connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function channel(): AMQPChannel
|
||||||
|
{
|
||||||
|
return $this->channel;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/Object/Publishing.php
Normal file
23
src/Object/Publishing.php
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Diffhead\PHP\LaravelRabbitMQ\Object;
|
||||||
|
|
||||||
|
class Publishing
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private string $connection,
|
||||||
|
private string $queue,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function connection(): string
|
||||||
|
{
|
||||||
|
return $this->connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function queue(): string
|
||||||
|
{
|
||||||
|
return $this->queue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,12 +4,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Diffhead\PHP\LaravelRabbitMQ\Service;
|
namespace Diffhead\PHP\LaravelRabbitMQ\Service;
|
||||||
|
|
||||||
use Diffhead\PHP\LaravelRabbitMQ\Object\Configuration as ConfigurationObject;
|
use Diffhead\PHP\LaravelRabbitMQ\Object\Connection;
|
||||||
|
use Diffhead\PHP\LaravelRabbitMQ\Object\Publishing;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
|
|
||||||
class Configuration
|
class Configuration
|
||||||
{
|
{
|
||||||
public function get(string $connection = 'default'): ConfigurationObject
|
public function getConnection(string $connection = 'default'): Connection
|
||||||
{
|
{
|
||||||
$config = config(sprintf('rabbitmq.connections.%s', $connection));
|
$config = config(sprintf('rabbitmq.connections.%s', $connection));
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ class Configuration
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ConfigurationObject(
|
return new Connection(
|
||||||
$config['host'],
|
$config['host'],
|
||||||
(int) $config['port'],
|
(int) $config['port'],
|
||||||
$config['user'],
|
$config['user'],
|
||||||
@@ -27,4 +28,12 @@ class Configuration
|
|||||||
$config['vhost'],
|
$config['vhost'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPublishing(): Publishing
|
||||||
|
{
|
||||||
|
return new Publishing(
|
||||||
|
config('rabbitmq.event.publishing.connection', 'sync'),
|
||||||
|
config('rabbitmq.event.publishing.queue', 'default'),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Diffhead\PHP\LaravelRabbitMQ\Service;
|
namespace Diffhead\PHP\LaravelRabbitMQ\Service;
|
||||||
|
|
||||||
use Diffhead\PHP\LaravelRabbitMQ\Object\Configuration;
|
|
||||||
use Diffhead\PHP\LaravelRabbitMQ\Object\Connection;
|
use Diffhead\PHP\LaravelRabbitMQ\Object\Connection;
|
||||||
|
use Diffhead\PHP\LaravelRabbitMQ\Object\ConnectionWithChannel;
|
||||||
use Diffhead\PHP\LaravelRabbitMQ\Object\Queue;
|
use Diffhead\PHP\LaravelRabbitMQ\Object\Queue;
|
||||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||||
|
|
||||||
class Connector
|
class Connector
|
||||||
{
|
{
|
||||||
public function connect(Configuration $config, Queue $queue): Connection
|
public function connect(Connection $config, Queue $queue): ConnectionWithChannel
|
||||||
{
|
{
|
||||||
$connection = new AMQPStreamConnection(
|
$connection = new AMQPStreamConnection(
|
||||||
$config->host(),
|
$config->host(),
|
||||||
@@ -57,6 +57,6 @@ class Connector
|
|||||||
$queue->bindings()->ticket()
|
$queue->bindings()->ticket()
|
||||||
);
|
);
|
||||||
|
|
||||||
return new Connection($connection, $channel);
|
return new ConnectionWithChannel($connection, $channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user