|
| 1 | +.. index:: |
| 2 | + single: Messenger; Record messages |
| 3 | + |
| 4 | +Record Events Produced by a Handler |
| 5 | +=================================== |
| 6 | + |
| 7 | +In a example application there is a command (a CQRS message) named ``CreateUser``. |
| 8 | +That command is handled by the ``CreateUserHandler``. The command handler creates |
| 9 | +a ``User`` object, stores that object to a database and dispatches an ``UserCreatedEvent``. |
| 10 | +That event is also a normal message but is handled by an *event* bus. |
| 11 | + |
| 12 | +There are many subscribers to the ``UserCreatedEvent``, one subscriber may send |
| 13 | +a welcome email to the new user. Since we are using the ``DoctrineTransactionMiddleware`` |
| 14 | +we wrap all database queries in one database transaction and rollback that transaction |
| 15 | +if an exception is thrown. That would mean that if an exception is thrown when sending |
| 16 | +the welcome email, then the user will not be created. |
| 17 | + |
| 18 | +The solution to this issue is to not dispatch the ``UserCreatedEvent`` in the |
| 19 | +``CreateUserHandler`` but to just "record" the events. The recorded events will |
| 20 | +be dispatched after ``DoctrineTransactionMiddleware`` has committed the transaction. |
| 21 | + |
| 22 | +To enable this, you simply just add the ``messenger.middleware.handles_recorded_messages`` |
| 23 | +middleware. Make sure it is registered before ``DoctrineTransactionMiddleware`` |
| 24 | +in the middleware chain. |
| 25 | + |
| 26 | +.. configuration-block:: |
| 27 | + |
| 28 | + .. code-block:: yaml |
| 29 | +
|
| 30 | + # config/packages/workflow.yaml |
| 31 | + framework: |
| 32 | + messenger: |
| 33 | + default_bus: messenger.bus.command |
| 34 | + buses: |
| 35 | + messenger.bus.command: |
| 36 | + middleware: |
| 37 | + - messenger.middleware.validation |
| 38 | + - messenger.middleware.handles_recorded_messages: ['@messenger.bus.event'] |
| 39 | + # Doctrine transaction must be after handles_recorded_messages middleware |
| 40 | + - app.doctrine_transaction_middleware: ['default'] |
| 41 | + messenger.bus.event: |
| 42 | + middleware: |
| 43 | + - messenger.middleware.allow_no_handler |
| 44 | + - messenger.middleware.validation |
| 45 | +
|
| 46 | +.. code-block:: php |
| 47 | +
|
| 48 | + use Doctrine\ORM\EntityManagerInterface; |
| 49 | + use Symfony\Component\Messenger\MessageRecorderInterface; |
| 50 | +
|
| 51 | + class CreateUserHandler |
| 52 | + { |
| 53 | + private $em; |
| 54 | + private $eventRecorder; |
| 55 | +
|
| 56 | + public function __construct(MessageRecorderInterface $eventRecorder, EntityManagerInterface $em) |
| 57 | + { |
| 58 | + $this->eventRecorder = $eventRecorder; |
| 59 | + $this->em = $em; |
| 60 | + } |
| 61 | +
|
| 62 | + public function __invoke(CreateUser $command) |
| 63 | + { |
| 64 | + $user = new User($command->getUuid(), $command->getName(), $command->getEmail()); |
| 65 | + $this->em->persist($user); |
| 66 | +
|
| 67 | + $this->eventRecorder->record(new UserCreatedEvent($command->getUuid()); |
| 68 | + } |
| 69 | + } |
0 commit comments