12

We're using Symfony Messenger in a Symfony 5 project to integrate with RabbitMQ. It works fine when sending messages within Symfony, but I need the ability to use the Messenger component to send messages from some legacy PHP applications that are not built with the Symfony framework.

Under Symfony, it handles all the magic by injecting the MessageBusInterface and all I need to do is something like this:

    public function processTestMessage(MessageBusInterface $bus)
    {
        $bus->dispatch(new TestMessage('Hello World!');
    }

I need to somehow instantiate my own version of $bus that will send AMQP messages the same way that Symfony does. I've been trying to recreate everything that Symfony does behind the scenes to accomplish this, but have not been able to put all the details together.

The crux of the problem is to create my own SendMessageMiddleware that does the same thing as Symfony. After that, it's simple:

    $sendersLocator = ???
    $eventDispatcher = ???

    $sendMessageMiddleware = new($sendersLocator, $eventDispatcher);
    $bus = new MessageBus([$sendMessageMiddleware]);

Does anyone have any examples of working code that uses the Messenger component to send AMQP messages outside of Symfony?

6
  • Hello, This article explains how to use the Messenger features as an independent component in any PHP application. ==> symfony.com/doc/current/components/messenger.html it's pretty straightforward Commented Jul 17, 2020 at 21:01
  • I've already been through that, but it's an example for email and I've having trouble adapting it to AMQP. Commented Jul 17, 2020 at 21:30
  • Here is their unhelpful advice from the article... ------ When using the message bus with Symfony’s FrameworkBundle, the following middleware are configured for you: SendMessageMiddleware (enables asynchronous processing, logs the processing of your messages if you pass a logger) --- Commented Jul 17, 2020 at 21:45
  • 1
    Since I'm NOT using it with the Symfony FrameworkBundle, what I need to know is how to configure the SendMessageMiddleware myself. Commented Jul 17, 2020 at 21:47
  • I have used Messenger in a project that wasn't a full Symfony application, and I used messenger adapter because, if I remember correctly, it was easier to more explicitly control since I didn't have the Symfony "magic". That said, you might want to look at the Symfony test suite for SendMessageMiddlewareTest which shows how you can stub in some of the magic Commented Jul 20, 2020 at 13:32

2 Answers 2

16
+50

This can be improved but it works for me:

use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpSender;
use Symfony\Component\Messenger\Bridge\Amqp\Transport\Connection;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBus;
use Symfony\Component\Messenger\Middleware\SendMessageMiddleware;
use Symfony\Component\Messenger\Transport\Sender\SendersLocatorInterface;

$sendersLocator = new class implements SendersLocatorInterface {
    public function getSenders(Envelope $envelope): iterable
    {
        $connection = new Connection(
            [
                'hosts' => 'localhost',
                'port' => 5672,
                'vhosts' => '/',
                'login' => 'guest',
                'password' => 'guest'
            ],
            [
                'name' => 'messages'
            ],
            [
                'messages' => []
            ]
        );
        return [
            'async' => new AmqpSender($connection)
        ];
    }
};

$middleware = new SendMessageMiddleware($sendersLocator);

$bus = new MessageBus([$middleware]);

$bus->dispatch(new MyMessage());
Sign up to request clarification or add additional context in comments.

6 Comments

btw, this uses php serializer, if you need to serialize to json or xml, just pass a serializer to the AmqpSender.
I thought I did. I awarded the 50 point bounty to you.
@dRamentol How can I consume the messages out of a Symfony project?
@FatemehGharri That's completely out of the scope of this question. You may want to ask a new question on that topic.
@dRamentol You're completely right, and I've done, but I've received nothing special! That is here: stackoverflow.com/questions/65005804/…
|
7

I modified the above answer to let me pass the RabbitMQ credentials as an environment variable. This is what I needed for my application. I was trying to write my own DSN parser and discovered that Symfony already does it, so I basically lifted the code from there.

If the environment variable is not set, it defaults to use the same settings shown in the example above.

use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpSender;
use Symfony\Component\Messenger\Bridge\Amqp\Transport\Connection;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBus;
use Symfony\Component\Messenger\Middleware\SendMessageMiddleware;
use Symfony\Component\Messenger\Transport\Sender\SendersLocatorInterface;

$sendersLocator = new class implements SendersLocatorInterface {
    public function getSenders(Envelope $envelope): iterable
    {
        $dsn = getenv('MESSENGER_TRANSPORT_DSN') ?: $_ENV['MESSENGER_TRANSPORT_DSN'];

        $connection = Connection::fromDsn($dsn); 

        return [
            'async' => new AmqpSender($connection)
        ];
    }
};

$middleware = new SendMessageMiddleware($sendersLocator);

$bus = new MessageBus([$middleware]);

$bus->dispatch(new MyMessage());

1 Comment

remove "new" in $connection = new Connection::fromDsn($dsn);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.