Multiple Buses

A common architecture when building applications is to separate commands from queries. Commands are actions that do something and queries fetch data. This is called CQRS (Command Query Responsibility Segregation). See Martin Fowler's article about CQRS to learn more. This architecture could be used together with the Messenger component by defining multiple buses.

アプリケーションを構築する際の一般的なアーキテクチャは、コマンドをクエリから分離することです。コマンドは何かを実行するアクションであり、クエリはデータをフェッチします。これは CQRS (Command Query Responsibility Segregation) と呼ばれます。詳細については、CQRS に関する Martin Fowler の記事を参照してください。このアーキテクチャは、複数のバスを定義することにより、Messenger コンポーネントと一緒に使用できます。

A command bus is a little different from a query bus. For example, command buses usually don't provide any results and query buses are rarely asynchronous. You can configure these buses and their rules by using middleware.

コマンド バスは、クエリ バスとは少し異なります。たとえば、通常、コマンドバスは結果を提供せず、クエリ バスはめったに非同期ではありません。これらのバスとそのルールは、ミドルウェアを使用して構成できます。

It might also be a good idea to separate actions from reactions by introducing an event bus. The event bus could have zero or more subscribers.

イベント バスを導入して、アクションとリアクションを分離することも良い考えです。イベント バスには、0 個以上のサブスクライバーを含めることができます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
framework:
    messenger:
        # The bus that is going to be injected when injecting MessageBusInterface
        default_bus: command.bus
        buses:
            command.bus:
                middleware:
                    - validation
                    - doctrine_transaction
            query.bus:
                middleware:
                    - validation
            event.bus:
                default_middleware:
                    enabled: true
                    # set "allow_no_handlers" to true (default is false) to allow having
                    # no handler configured for this bus without throwing an exception
                    allow_no_handlers: false
                    # set "allow_no_senders" to false (default is true) to throw an exception
                    # if no sender is configured for this bus
                    allow_no_senders: true
                middleware:
                    - validation

6.2

6.2

The allow_no_senders option was introduced in Symfony 6.2.

allow_no_senders オプションは Symfony 6.2 で導入されました。

This will create three new services:

これにより、次の 3 つの新しいサービスが作成されます。
  • command.bus: autowireable with the MessageBusInterface type-hint (because this is the default_bus);
    command.bus: MessageBusInterfacetype-hint で autowireable (これは default_bus であるため);
  • query.bus: autowireable with MessageBusInterface $queryBus;
    query.bus: MessageBusInterface $queryBus で自動配線可能。
  • event.bus: autowireable with MessageBusInterface $eventBus.
    event.bus: MessageBusInterface $eventBus で自動配線可能。

Restrict Handlers per Bus

By default, each handler will be available to handle messages on all of your buses. To prevent dispatching a message to the wrong bus without an error, you can restrict each handler to a specific bus using the messenger.message_handler tag:

デフォルトでは、各ハンドラーはすべてのバスでメッセージを処理するために使用できます。エラーなしでメッセージが間違ったバスにディスパッチされるのを防ぐために、messenger.message_handler タグを使用して、各ハンドラーを特定のバスに制限できます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
# config/services.yaml
services:
    App\MessageHandler\SomeCommandHandler:
        tags: [{ name: messenger.message_handler, bus: command.bus }]
        # prevent handlers from being registered twice (or you can remove
        # the MessageHandlerInterface that autoconfigure uses to find handlers)
        autoconfigure: false

This way, the App\MessageHandler\SomeCommandHandler handler will only be known by the command.bus bus.

このように、App\MessageHandler\SomeCommandHandler ハンドラーは、command.bus バスによってのみ認識されます。

You can also automatically add this tag to a number of classes by using the _instanceof service configuration. Using this, you can determine the message bus based on an implemented interface:

_instanceof サービス構成を使用して、このタグを多数のクラスに自動的に追加することもできます。これを使用すると、実装されたインターフェイスに基づいてメッセージ バスを決定できます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# config/services.yaml
services:
    # ...

    _instanceof:
        # all services implementing the CommandHandlerInterface
        # will be registered on the command.bus bus
        App\MessageHandler\CommandHandlerInterface:
            tags:
                - { name: messenger.message_handler, bus: command.bus }

        # while those implementing QueryHandlerInterface will be
        # registered on the query.bus bus
        App\MessageHandler\QueryHandlerInterface:
            tags:
                - { name: messenger.message_handler, bus: query.bus }

Debugging the Buses

The debug:messenger command lists available messages & handlers per bus. You can also restrict the list to a specific bus by providing its name as an argument.

debug:messenger コマンドは、バスごとに使用可能なメッセージとハンドラーを一覧表示します。引数として名前を指定することで、リストを特定のバスに制限することもできます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ php bin/console debug:messenger

  Messenger
  =========

  command.bus
  -----------

   The following messages can be dispatched:

   ---------------------------------------------------------------------------------------
    App\Message\DummyCommand
        handled by App\MessageHandler\DummyCommandHandler
    App\Message\MultipleBusesMessage
        handled by App\MessageHandler\MultipleBusesMessageHandler
   ---------------------------------------------------------------------------------------

  query.bus
  ---------

   The following messages can be dispatched:

   ---------------------------------------------------------------------------------------
    App\Message\DummyQuery
        handled by App\MessageHandler\DummyQueryHandler
    App\Message\MultipleBusesMessage
        handled by App\MessageHandler\MultipleBusesMessageHandler
   ---------------------------------------------------------------------------------------

Tip

ヒント

Since Symfony 5.1, the command will also show the PHPDoc description of the message and handler classes.

Symfony 5.1 以降、このコマンドは、メッセージとハンドラー クラスの PHPDoc の説明も表示します。