Configuration

The configuration for this bridge is defined under the messageBus namespace for the Laminas\ConfigAggregator. It holds multiple path variables, mapping arrays and a failure transport definition.

Any message that is apssed through a messenger middleware or through a command (working asynchronously) will be logged with the Monolog library. Some of the Symfony commands to handle the worker need a cache. Both of these paths can be defined with following configuration. The default configuration will store files in the data/cache/message-bus and data/logs/message-bus directories.

'messageBus' => [
    'logPath' => dirname(__DIR__, 2).'/data/logs/message-bus',
    'cachePath' => dirname(__DIR__, 2).'/data/cache',

    // ...
],

Transports

A ‘transport’ defines the channels, where asynchronous messages can be send to. This can be a database and delegated via Doctrine, a Redis instance or a RabbitMQ. Maybe more to come. To define multiple channels, simply create multiple DSNs within this configuration.

'messageBus' => [
    'transportDSNs' => [
        // name     => DSN,
        'default'   => 'amqp://guest:password@rabbitmq.tld:5672/%2f/default',
        'failure'   => 'amqp://guest:password@rabbitmq.tld:5672/%2f/failure',
        'doctrine'  => 'doctrine://guest:password@mariadb10:3306/default',
        'redis'     => 'redis://redis5:6379/default',
    ],

    // ...
],

For each configured transport DSN, a service named Transport::$name will be added to the service container, holding an instance of Symfony\Component\Messenger\Transport\TransportInterface with the necessary connection to the broker. To get a transport from the container, you can either pass the string - e.g. Transport::default - or use the helper MessageBus\Factory\Transporthelper::createTransportName($name) for the $container->get(...) instruction.

One of those transports should be defined as the ‘failure transport’. Symfony messenger will put any message that has failed 3 times onto this transport. It also offers commands to display and retry failed messages or remove them savely. This transport does not have to be named ‘failure’.

'messageBus' => [
    'failureTransport' => MessageBus\Factory\TransportHelper::createTransportName('failure'),

    // ...
],

Delegating the messages

Each message needs a ‘Worker’ to handle it. You can find out more in the “How to use the bridge” section or in the Symfony documentation. The bridge handles the associations via array maps, defining message to worker(s) and message to transport(s). You can pass a string or array as value.

'messageBus' => [
    // ...

    'handlersLocatorMap' => [
        App\Worker\ImportantSyncMessage::class => [App\Worker\ImportantWorker::class],
        App\Worker\UnimportantAsyncMessage::class => App\Worker\UnimportantWorker::class,
    ],

    'sendersLocatorMap' => [
        App\Worker\UnimportantAsyncMessage::class => 'Transport::default',
    ],

    // ...
],

A message not listed in the ‘sendersLocatorMap’ will be handle synchronously on request.

Custom middlewares

As described in the official Symfony docs, you can define custom middlewares by adding classes that implement the MiddlewareInterface. To add your custom middlewares in Mezzio, create such a class and use the factory method, to configure this service in Psr\Container.

class MyMiddleware implements MiddlewareInterface
{
    private MyService $service;

    public function __construct(MyService $service)
    {
        $this->service = $service;
    }

    public function handle(Envelope $envelope, StackInterface $stack): Envelope
    {
        // implement you middleware

        return $stack->next()->handle($envelope, $stack);
    }
}
class ConfigProvider
{
    public function __invoke(): array
    {
        return [
            'dependencies' => $this->getDependencies(),
        ];
    }

    public function getDependencies(): array
    {
        return [
            'factories'  => [
                MyMiddleware::class => MyMiddlewareFactory::class,
                //...
            ],
        ];
    }

    //...
}

Then add the middleware class to messenger configuration:

'messageBus' => [
    // ...

    # define custom middlewares
    'customMiddlewares' => [
        MyMiddleware::class,
    ],
],