From 9973d671bfe44791ef125fb2342a7c1c9e7b9ef1 Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Wed, 4 Jul 2018 16:59:52 +0200 Subject: [PATCH 1/3] Added configuration for multiple buses --- messenger/multiple-buses.rst | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 messenger/multiple-buses.rst diff --git a/messenger/multiple-buses.rst b/messenger/multiple-buses.rst new file mode 100644 index 00000000000..2cf010995c2 --- /dev/null +++ b/messenger/multiple-buses.rst @@ -0,0 +1,41 @@ +.. index:: + single: Messenger; Multiple buses + +Multiple Buses +============== + +A common architecture when building application is to separate commands from +queries. Commands are actions that do something and queries fetches 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. + +A **command bus** is a little different form a **query bus**. As example, +command buses must not return anything and query buses are rarely asynchronous. +You can configure these buses and their rules by using middlewares. + +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. + +.. configuration-block:: + + .. code-block:: yaml + + framework: + messenger: + default_bus: messenger.bus.command + buses: + messenger.bus.command: + middleware: + - messenger.middleware.validation + - messenger.middleware.handles_recorded_messages: ['@messenger.bus.event'] + - doctrine_transaction_middleware: ['default'] + messenger.bus.query: + middleware: + - messenger.middleware.validation + messenger.bus.event: + middleware: + - messenger.middleware.allow_no_handler + - messenger.middleware.validation + +.. _article about CQRS: https://martinfowler.com/bliki/CQRS.html From 4a3f754e43e5f41f3dab74666760a484a9b1f868 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Tue, 20 Nov 2018 14:24:57 +0100 Subject: [PATCH 2/3] [Messenger] Multiples buses, scoping handlers per bus, PSR-4 discovery & debug --- components/messenger.rst | 9 ++ messenger.rst | 114 +------------- messenger/multiple-buses.rst | 41 ----- messenger/multiple_buses.rst | 292 +++++++++++++++++++++++++++++++++++ 4 files changed, 309 insertions(+), 147 deletions(-) delete mode 100644 messenger/multiple-buses.rst create mode 100644 messenger/multiple_buses.rst diff --git a/components/messenger.rst b/components/messenger.rst index 2700e3eec55..06d618190a0 100644 --- a/components/messenger.rst +++ b/components/messenger.rst @@ -291,5 +291,14 @@ loop, the message bus will add a :class:`Symfony\\Component\\Messenger\\Asynchro envelope item to the message envelopes and the :class:`Symfony\\Component\\Messenger\\Asynchronous\\Middleware\\SendMessageMiddleware` middleware will know it should not route these messages again to a transport. +Learn more +---------- +.. toctree:: + :maxdepth: 1 + :glob: + + /messenger + /messenger/* + .. _blog posts about command buses: https://matthiasnoback.nl/tags/command%20bus/ .. _SimpleBus project: http://simplebus.io diff --git a/messenger.rst b/messenger.rst index 14f5f4d906e..70e8926114d 100644 --- a/messenger.rst +++ b/messenger.rst @@ -421,112 +421,6 @@ like this: The first argument is the receiver's service name. It might have been created by your ``transports`` configuration or it can be your own receiver. -Multiple Buses --------------- - -If you are interested in architectures like CQRS, you might want to have multiple -buses within your application. - -You can create multiple buses (in this example, a command bus and an event bus) like -this: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/messenger.yaml - framework: - messenger: - # The bus that is going to be injected when injecting MessageBusInterface: - default_bus: messenger.bus.commands - - # Create buses - buses: - messenger.bus.commands: ~ - messenger.bus.events: ~ - - .. code-block:: xml - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/messenger.php - $container->loadFromExtension('framework', array( - 'messenger' => array( - 'default_bus' => 'messenger.bus.commands', - 'buses' => array( - 'messenger.bus.commands' => null, - 'messenger.bus.events' => null, - ), - ), - )); - -This will generate the ``messenger.bus.commands`` and ``messenger.bus.events`` services -that you can inject in your services. - -.. note:: - - To register a handler only for a specific bus, add a ``bus`` attribute to - the handler's service tag (``messenger.message_handler``) and use the bus - name as its value. - -Type-hints and Auto-wiring -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Auto-wiring is a great feature that allows you to reduce the amount of configuration -required for your service container to be created. When using multiple buses, by default, -the auto-wiring will not work as it won't know which bus to inject in your own services. - -In order to clarify this, you can use the DependencyInjection's binding capabilities -to clarify which bus will be injected based on the argument's name: - -.. configuration-block:: - - .. code-block:: yaml - - # config/services.yaml - services: - _defaults: - # ... - - bind: - $commandBus: '@messenger.bus.commands' - $eventBus: '@messenger.bus.events' - - .. code-block:: xml - - - - - - - - - - - - - Middleware ---------- @@ -961,4 +855,12 @@ will give you access to the following services: #. ``messenger.sender.yours``: the sender; #. ``messenger.receiver.yours``: the receiver. +Learn more +---------- +.. toctree:: + :maxdepth: 1 + :glob: + + /messenger/* + .. _`enqueue's transport`: https://github.com/php-enqueue/messenger-adapter diff --git a/messenger/multiple-buses.rst b/messenger/multiple-buses.rst deleted file mode 100644 index 2cf010995c2..00000000000 --- a/messenger/multiple-buses.rst +++ /dev/null @@ -1,41 +0,0 @@ -.. index:: - single: Messenger; Multiple buses - -Multiple Buses -============== - -A common architecture when building application is to separate commands from -queries. Commands are actions that do something and queries fetches 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. - -A **command bus** is a little different form a **query bus**. As example, -command buses must not return anything and query buses are rarely asynchronous. -You can configure these buses and their rules by using middlewares. - -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. - -.. configuration-block:: - - .. code-block:: yaml - - framework: - messenger: - default_bus: messenger.bus.command - buses: - messenger.bus.command: - middleware: - - messenger.middleware.validation - - messenger.middleware.handles_recorded_messages: ['@messenger.bus.event'] - - doctrine_transaction_middleware: ['default'] - messenger.bus.query: - middleware: - - messenger.middleware.validation - messenger.bus.event: - middleware: - - messenger.middleware.allow_no_handler - - messenger.middleware.validation - -.. _article about CQRS: https://martinfowler.com/bliki/CQRS.html diff --git a/messenger/multiple_buses.rst b/messenger/multiple_buses.rst new file mode 100644 index 00000000000..e3b221450d6 --- /dev/null +++ b/messenger/multiple_buses.rst @@ -0,0 +1,292 @@ +.. index:: + single: Messenger; Multiple buses + +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. + +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. + +.. configuration-block:: + + .. code-block:: yaml + + framework: + messenger: + # The bus that is going to be injected when injecting MessageBusInterface + default_bus: messenger.bus.commands + buses: + messenger.bus.commands: + middleware: + - validation + - doctrine_transaction + messenger.bus.queries: + middleware: + - validation + messenger.bus.events: + middleware: + - allow_no_handler + - validation + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + $container->loadFromExtension('framework', array( + 'messenger' => array( + // The bus that is going to be injected when injecting MessageBusInterface + 'default_bus' => 'messenger.bus.commands', + 'buses' => array( + 'messenger.bus.commands' => array( + 'middleware' => array( + 'validation', + 'doctrine_transaction', + ), + ), + 'messenger.bus.queries' => array( + 'middleware' => array( + 'validation', + ), + ), + 'messenger.bus.events' => array( + 'middleware' => array( + 'validation', + 'allow_no_handler', + ), + ), + ), + ), + )); + +This will generate the ``messenger.bus.commands``, ``messenger.bus.queries`` +and ``messenger.bus.events`` services that you can inject in your services. + +Type-hints and Auto-wiring +-------------------------- + +Auto-wiring is a great feature that allows you to reduce the amount of configuration +required for your service container to be created. By using ``MessageBusInterface`` +as argument typehint in your services, the default configured bus will be injected +(i.e ``messenger.bus.commands`` in above examples). + +When working with multiple buses, you can use the ``DependencyInjection`` component's +binding capabilities to clarify which bus will be injected based on the argument's name: + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + _defaults: + # ... + + bind: + $commandBus: '@messenger.bus.commands' + $queryBus: '@messenger.bus.queries' + $eventBus: '@messenger.bus.events' + + .. code-block:: xml + + + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + + $container->bind('$commandBus', 'messenger.bus.commands'); + $container->bind('$queryBus', 'messenger.bus.queries'); + $container->bind('$eventBus', 'messenger.bus.events'); + +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: + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + App\MessageHandler\SomeCommandHandler: + tags: [{ name: messenger.message_handler, bus: messenger.bus.commands }] + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + + $container->services() + ->set(App\MessageHandler\SomeCommandHandler::class) + ->tag('messenger.message_handler', ['bus' => 'messenger.bus.commands']); + +This way, the ``App\MessageHandler\SomeCommandHandler`` handler will only be +known by the ``messenger.bus.commands`` bus. + +You can also automatically add this tag to a number of classes by following +a naming convention and registering all of the handler services by name with +the correct tag: + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + + # put this after the `App\` line that registers all your services + command_handlers: + namespace: App\MessageHandler\ + resource: '%kernel.project_dir%/src/MessageHandler/*CommandHandler.php' + tags: + - { name: messenger.message_handler, bus: messenger.bus.commands } + + query_handlers: + namespace: App\MessageHandler\ + resource: '%kernel.project_dir%/src/MessageHandler/*QueryHandler.php' + tags: + - { name: messenger.message_handler, bus: messenger.bus.queries } + + .. code-block:: xml + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + + // Command handlers + $container->services() + ->load('App\MessageHandler\\', '%kernel.project_dir%/src/MessageHandler/*CommandHandler.php') + ->tag('messenger.message_handler', ['bus' => 'messenger.bus.commands']); + + // Query handlers + $container->services() + ->load('App\MessageHandler\\', '%kernel.project_dir%/src/MessageHandler/*QueryHandler.php') + ->tag('messenger.message_handler', ['bus' => 'messenger.bus.queries']); + +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 argument. + +.. code-block:: terminal + + $ bin/console debug:messenger + + Messenger + ========= + + messenger.bus.commands + ---------------------- + + The following messages can be dispatched: + + --------------------------------------------------------------------------------------- + App\Message\DummyCommand + handled by App\MessageHandler\DummyCommandHandler + App\Message\MultipleBusesMessage + handled by App\MessageHandler\MultipleBusesMessageHandler + --------------------------------------------------------------------------------------- + + messenger.bus.queries + --------------------- + + The following messages can be dispatched: + + --------------------------------------------------------------------------------------- + App\Message\DummyQuery + handled by App\MessageHandler\DummyQueryHandler + App\Message\MultipleBusesMessage + handled by App\MessageHandler\MultipleBusesMessageHandler + --------------------------------------------------------------------------------------- + +.. _article about CQRS: https://martinfowler.com/bliki/CQRS.html From 65b158d9a26f6b055065ab1dc4a2059507718dad Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 27 Dec 2018 16:48:26 +0100 Subject: [PATCH 3/3] Fixed a minor syntax issue in a link --- console/coloring.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/console/coloring.rst b/console/coloring.rst index 4848c2e7d32..2793a709fd5 100644 --- a/console/coloring.rst +++ b/console/coloring.rst @@ -9,9 +9,9 @@ output (e.g. important messages, titles, comments, etc.). By default, the Windows command console doesn't support output coloring. The Console component disables output coloring for Windows systems, but if your commands invoke other scripts which emit color sequences, they will be - wrongly displayed as raw escape characters. Install the `Cmder`_, `ConEmu`_, `ANSICON`_ - ,`Mintty`_ (used by default in GitBash and Cygwin) or `Hyper`_ free applications - to add coloring support to your Windows command console. + wrongly displayed as raw escape characters. Install the `Cmder`_, `ConEmu`_, + `ANSICON`_, `Mintty`_ (used by default in GitBash and Cygwin) or `Hyper`_ + free applications to add coloring support to your Windows command console. Using Color Styles ------------------