HandleMessageMiddleware.php 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Messenger\Middleware;
  11. use Psr\Log\LoggerAwareTrait;
  12. use Psr\Log\NullLogger;
  13. use Symfony\Component\Messenger\Envelope;
  14. use Symfony\Component\Messenger\Exception\HandlerFailedException;
  15. use Symfony\Component\Messenger\Exception\NoHandlerForMessageException;
  16. use Symfony\Component\Messenger\Handler\HandlerDescriptor;
  17. use Symfony\Component\Messenger\Handler\HandlersLocatorInterface;
  18. use Symfony\Component\Messenger\Stamp\HandledStamp;
  19. /**
  20. * @author Samuel Roze <samuel.roze@gmail.com>
  21. */
  22. class HandleMessageMiddleware implements MiddlewareInterface
  23. {
  24. use LoggerAwareTrait;
  25. private $handlersLocator;
  26. private $allowNoHandlers;
  27. public function __construct(HandlersLocatorInterface $handlersLocator, bool $allowNoHandlers = false)
  28. {
  29. $this->handlersLocator = $handlersLocator;
  30. $this->allowNoHandlers = $allowNoHandlers;
  31. $this->logger = new NullLogger();
  32. }
  33. /**
  34. * {@inheritdoc}
  35. *
  36. * @throws NoHandlerForMessageException When no handler is found and $allowNoHandlers is false
  37. */
  38. public function handle(Envelope $envelope, StackInterface $stack): Envelope
  39. {
  40. $handler = null;
  41. $message = $envelope->getMessage();
  42. $context = [
  43. 'message' => $message,
  44. 'class' => \get_class($message),
  45. ];
  46. $exceptions = [];
  47. foreach ($this->handlersLocator->getHandlers($envelope) as $handlerDescriptor) {
  48. if ($this->messageHasAlreadyBeenHandled($envelope, $handlerDescriptor)) {
  49. continue;
  50. }
  51. try {
  52. $handler = $handlerDescriptor->getHandler();
  53. $handledStamp = HandledStamp::fromDescriptor($handlerDescriptor, $handler($message));
  54. $envelope = $envelope->with($handledStamp);
  55. $this->logger->info('Message {class} handled by {handler}', $context + ['handler' => $handledStamp->getHandlerName()]);
  56. } catch (\Throwable $e) {
  57. $exceptions[] = $e;
  58. }
  59. }
  60. if (null === $handler) {
  61. if (!$this->allowNoHandlers) {
  62. throw new NoHandlerForMessageException(sprintf('No handler for message "%s".', $context['class']));
  63. }
  64. $this->logger->info('No handler for message {class}', $context);
  65. }
  66. if (\count($exceptions)) {
  67. throw new HandlerFailedException($envelope, $exceptions);
  68. }
  69. return $stack->next()->handle($envelope, $stack);
  70. }
  71. private function messageHasAlreadyBeenHandled(Envelope $envelope, HandlerDescriptor $handlerDescriptor): bool
  72. {
  73. $some = array_filter($envelope
  74. ->all(HandledStamp::class), function (HandledStamp $stamp) use ($handlerDescriptor) {
  75. return $stamp->getHandlerName() === $handlerDescriptor->getName();
  76. });
  77. return \count($some) > 0;
  78. }
  79. }