.. index:: single: Messenger; Getting results / Working with command & query buses
When a message is handled, the :class:`Symfony\\Component\\Messenger\\Middleware\\HandleMessageMiddleware` adds a :class:`Symfony\\Component\\Messenger\\Stamp\\HandledStamp` for each object that handled the message. You can use this to get the value returned by the handler(s):
use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\Stamp\HandledStamp; $envelope = $messageBus->dispatch(new SomeMessage()); // get the value that was returned by the last message handler $handledStamp = $envelope->last(HandledStamp::class); $handledStamp->getResult(); // or get info about all of handlers $handledStamps = $envelope->all(HandledStamp::class);
The Messenger component can be used in CQRS architectures where command & query buses are central pieces of the application. Read Martin Fowler's article about CQRS to learn more and :doc:`how to configure multiple buses </messenger/multiple_buses>`.
As queries are usually synchronous and expected to be handled once, getting the result from the handler is a common need.
A :class:`Symfony\\Component\\Messenger\\HandleTrait` exists to get the result
of the handler when processing synchronously. It also ensures that exactly one
handler is registered. The HandleTrait
can be used in any class that has a
$messageBus
property:
// src/Action/ListItems.php namespace App\Action; use App\Message\ListItemsQuery; use App\MessageHandler\ListItemsQueryResult; use Symfony\Component\Messenger\HandleTrait; use Symfony\Component\Messenger\MessageBusInterface; class ListItems { use HandleTrait; public function __construct(MessageBusInterface $messageBus) { $this->messageBus = $messageBus; } public function __invoke() { $result = $this->query(new ListItemsQuery(/* ... */)); // Do something with the result // ... } // Creating such a method is optional, but allows type-hinting the result private function query(ListItemsQuery $query): ListItemsQueryResult { return $this->handle($query); } }
Hence, you can use the trait to create command & query bus classes.
For example, you could create a special QueryBus
class and inject it
wherever you need a query bus behavior instead of the MessageBusInterface
:
// src/MessageBus/QueryBus.php namespace App\MessageBus; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\HandleTrait; use Symfony\Component\Messenger\MessageBusInterface; class QueryBus { use HandleTrait; public function __construct(MessageBusInterface $messageBus) { $this->messageBus = $messageBus; } /** * @param object|Envelope $query * * @return mixed The handler returned value */ public function query($query) { return $this->handle($query); } }