将exchange绑定到Symfony messenger组件中的exchange

将exchange绑定到Symfony messenger组件中的exchange,symfony,rabbitmq,symfony-4.4,symfony-messenger,Symfony,Rabbitmq,Symfony 4.4,Symfony Messenger,是否可以在Symfony messenger组件中定义交换机之间的绑定?(此处为4.4版本) 我知道可以将exchange绑定到队列,如下所示: 传输: 进来的: dsn:%env(RABBITMQ\u共享\u URL)% 选项: 队列: app.pl_传入事件: 绑定密钥: -pl.app# 交换: 名称:my_应用程序传入 类型:主题 然后应用程序设置在它们之间进行交换、排队和绑定。我希望基于路由密钥将exchange绑定到另一个exchange也会产生同样的效果 我知道我可以使用rabb

是否可以在Symfony messenger组件中定义交换机之间的绑定?(此处为4.4版本)

我知道可以将exchange绑定到队列,如下所示:

传输:
进来的:
dsn:%env(RABBITMQ\u共享\u URL)%
选项:
队列:
app.pl_传入事件:
绑定密钥:
-pl.app#
交换:
名称:my_应用程序传入
类型:主题
然后应用程序设置在它们之间进行交换、排队和绑定。我希望基于路由密钥将exchange绑定到另一个exchange也会产生同样的效果

我知道我可以使用rabbitmq捆绑包,但IMO是多余的——我希望只使用一个组件来管理rabbitmq


例如,我想将
其他应用程序
交换绑定到
我的应用程序。传入的
交换基于某个路由密钥。

Messenger不是RabbitMQ管理器,您甚至不能在同一传输中声明多个交换。 但由于它具有所有必需的组件,而且在本例中symfony对配置有点宽容,因此您可以滥用系统,自己构建它

因为我不知道你的要求,我会保持基本的,希望它能让你开始

首先创建
AmqpTransportFactory

// src/Amqp/AmqpTransportFactory.php
namespace App\Amqp;

use Symfony\Component\Messenger\Transport\AmqpExt\AmqpFactory;
use Symfony\Component\Messenger\Transport\AmqpExt\AmqpTransport;
use Symfony\Component\Messenger\Transport\AmqpExt\Connection;
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
use Symfony\Component\Messenger\Transport\TransportFactoryInterface;
use Symfony\Component\Messenger\Transport\TransportInterface;

class AmqpTransportFactory implements TransportFactoryInterface
{
    public function createTransport(
        string $dsn, array $options, SerializerInterface $serializer
    ): TransportInterface
    {
        unset($options['transport_name']);
        $exchanges['name'] = $options['exchange']['name'];
        $exchanges['bindings'] = $options['exchange']['bindings'] ?? [];

        // Passing unknown options is deprecated in 5.1
        unset($options['exchange']['bindings']);

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

        // Ensure our exchange is created first
        $connection->exchange()->declareExchange();
        $channel = $connection->channel();
    
        // This is normally done in the Connection, but is harder to override
        $this->createExchanges($channel, $exchanges);

        return new AmqpTransport($connection, $serializer);
    }

    public function supports(string $dsn, array $options): bool
    {
        return 0 === strpos($dsn, 'amqp://');
    }

    private function createExchanges(\AMQPChannel $channel, array $configuration): void
    {
        $factory = new AmqpFactory();

        foreach ($configuration['bindings'] as $exchange_name => $arguments) {
            $exchange = $factory->createExchange($channel);
            $exchange->setName($exchange_name);
            $exchange->setType($arguments['type'] ?? \AMQP_EX_TYPE_FANOUT);
            $exchange->setFlags($arguments['flags'] ?? \AMQP_DURABLE);
            $exchange->declareExchange();

            if (!is_array($arguments['binding_keys'])) {
                $arguments['binding_keys'] = [$arguments['binding_keys']];
            }

            foreach ($arguments['binding_keys'] as $key) {
                $exchange->bind($configuration['name'], $key);
            }
        }
    }
}
注册服务:

# config/services.yaml
services:
  messenger.transport.amqp.factory:
    class: App\Amqp\AmqpTransportFactory
将新配置添加到exchange:

# config/packages/messenger.yaml
exchange:
  name: my_app.incoming
  type: topic
  bindings:
    other_app:
      type: direct
      binding_keys: ['route']
它将导致以下绑定:

+-----------------+------------------------+------------------------+
|     source      |      destination       |      routing_key       |
+-----------------+------------------------+------------------------+
| my_app.incoming | app.pl_incoming_events | pl.app.#               |
| my_app.incoming | other_app              | route                  |
+-----------------+------------------------+------------------------+

谢谢你的广泛回复!但我不确定它是否适合安装—messenger假定连接类负责安装(请参阅
\Symfony\Component\messenger\Transport\amqtext\Connection
中的
setupExchangeAndQueues
)。在其他情况下,它将使用所述类中的
setupExchangeAndQueues
方法(在连接类中的5个位置执行),但仍将存在错误的交换设置。我在问是否可以使用内置功能,但当我查看代码时,这似乎是不可能的(您已经证实了)。是的,我完全清楚,而且该方法是私有的。当我指出代码中有一条注释时,欢迎您直接重写连接,但作为一个答案,这是一般的想法。然而,正如前两句所说,“它不是一个管理者,甚至不能在一个传输中声明多个交换”,所以“使用内置功能”将是一个很难拒绝的问题。但我不明白为什么交换的设置会是错误的。我明确声明“我们的”交换,以确保它已定义。您可以在连接时调用
setup()
,如果这样可以增强信心。