Skip to content

Commit 36a089a

Browse files
committed
[Messenger] Added a trait for synchronous query & command buses
1 parent bd21549 commit 36a089a

File tree

3 files changed

+144
-0
lines changed

3 files changed

+144
-0
lines changed

components/messenger.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,5 +298,14 @@ loop, the message bus will add a :class:`Symfony\\Component\\Messenger\\Stamp\\R
298298
stamp to the message envelopes and the :class:`Symfony\\Component\\Messenger\\Middleware\\SendMessageMiddleware`
299299
middleware will know it should not route these messages again to a transport.
300300

301+
Learn more
302+
----------
303+
.. toctree::
304+
:maxdepth: 1
305+
:glob:
306+
307+
/messenger
308+
/messenger/*
309+
301310
.. _blog posts about command buses: https://matthiasnoback.nl/tags/command%20bus/
302311
.. _SimpleBus project: http://simplebus.io

messenger.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,4 +928,12 @@ will give you access to the following services:
928928
#. ``messenger.sender.yours``: the sender;
929929
#. ``messenger.receiver.yours``: the receiver.
930930

931+
Learn more
932+
----------
933+
.. toctree::
934+
:maxdepth: 1
935+
:glob:
936+
937+
/messenger/*
938+
931939
.. _`enqueue's transport`: https://github.com/php-enqueue/messenger-adapter

messenger/handler_results.rst

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
.. index::
2+
single: Messenger; Getting results / Working with command & query buses
3+
4+
Getting results
5+
---------------
6+
7+
When a message is handled, the :class:`Symfony\\Component\\Messenger\\Middleware\\HandleMessageMiddleware`
8+
adds a :class:`Symfony\\Component\\Messenger\\Stamp\\HandledStamp` for each responding handler,
9+
which can be used to get their returned value:
10+
11+
.. configuration-block::
12+
13+
.. code-block:: php
14+
15+
use Symfony\Component\Messenger\MessageBusInterface;
16+
use Symfony\Component\Messenger\Stamp\HandledStamp;
17+
18+
$envelope = $messageBus->dispatch(SomeMessage());
19+
20+
// Get the last handled stamp and its returned value:
21+
$handledStamp = $envelope->last(HandledStamp::class);
22+
$handledStamp->getResult();
23+
24+
Using the :method:`Symfony\\Component\\Messenger\\Stamp\\HandledStamp::last` method
25+
assumes there is only one configured handler or that only the last handler
26+
result is relevant. But you can also get the stamps for all handlers:
27+
28+
.. configuration-block::
29+
30+
.. code-block:: php
31+
32+
use Symfony\Component\Messenger\MessageBusInterface;
33+
use Symfony\Component\Messenger\Stamp\HandledStamp;
34+
35+
$envelope = $messageBus->dispatch(SomeMessage());
36+
$handledStamps = $envelope->all(HandledStamp::class);
37+
38+
A :class:`Symfony\\Component\\Messenger\\HandleTrait` also exists in order to ease
39+
leveraging a Messenger bus for synchronous needs.
40+
The :method:`Symfony\\Component\\Messenger\\HandleTrait::handle` method ensures
41+
there is exactly one handler registered and returns its result.
42+
43+
Working with command & query buses
44+
----------------------------------
45+
46+
The Messenger component can be used in CQRS architectures where command & query
47+
buses are central pieces of the application.
48+
See Martin Fowler's `article about CQRS`_ to learn more and :doc:`how to configure multiple buses </messenger/multiple_buses>`.
49+
50+
As queries are usually synchronous and expect to be handled once, getting the
51+
result from the handler is a common need.
52+
53+
You can directly leverage the ``HandleTrait`` trait in a controller (or any caller):
54+
55+
.. configuration-block::
56+
57+
.. code-block:: php
58+
59+
namespace App\Controller;
60+
61+
use App\Message\ListItemsQuery;
62+
use App\MessageHandler\ListItemsQueryResult;
63+
use Symfony\Component\Messenger\HandleTrait;
64+
use Symfony\Component\Messenger\MessageBusInterface;
65+
66+
class ListItemsController
67+
{
68+
use HandleTrait;
69+
70+
public function __construct(MessageBusInterface $messageBus)
71+
{
72+
$this->messageBus = $messageBus;
73+
}
74+
75+
public function __invoke(Request $request)
76+
{
77+
// Extract data from the request
78+
//...
79+
80+
$result = $this->query(new ListItemsQuery(/* ... */));
81+
82+
// Return a response with result
83+
// ...
84+
}
85+
86+
// Creating such a method is optional, but allows type-hinting the result
87+
private function query(ListItemsQuery $query): ListItemsResult
88+
{
89+
return $this->handle($query);
90+
}
91+
}
92+
93+
Or you can use the trait to create command & query buses classes.
94+
Here is how you can create a ``QueryBus`` class to inject in places you need
95+
a query bus behavior instead of the ``MessageBusInterface``:
96+
97+
.. configuration-block::
98+
99+
.. code-block:: php
100+
101+
namespace App\MessageBus;
102+
103+
use Symfony\Component\Messenger\Envelope;
104+
use Symfony\Component\Messenger\HandleTrait;
105+
use Symfony\Component\Messenger\MessageBusInterface;
106+
107+
class QueryBus
108+
{
109+
use HandleTrait;
110+
111+
public function __construct(MessageBusInterface $messageBus)
112+
{
113+
$this->messageBus = $messageBus;
114+
}
115+
116+
/**
117+
* @param object|Envelope $query
118+
*
119+
* @return mixed The handler returned value
120+
*/
121+
public function query($query)
122+
{
123+
return $this->handle($query);
124+
}
125+
}
126+
127+
.. _article about CQRS: https://martinfowler.com/bliki/CQRS.html

0 commit comments

Comments
 (0)