Eine Einführung in die Messenger-Komponente

Eine Einführung in die Messenger-Komponente

Vortrag auf der Symfony User Group Hamburg.

Themen sind die Konzepte rund um die Messenger-Komponente (Message Bus, Message, Handler, Middleware, Envelopes und Stamps), ein Vergleich mit dem EventDispatcher sowie Beispiele für Konfiguration & Verwendung anhand einer Demoanwendung.

Der Code für die gezeigte Demo befindet sich auf GitHub: https://github.com/dbrumann/messenger-screenshot-demo

6a1345d8e6dd15b2c78eff0c331963b1?s=128

Denis Brumann

March 05, 2019
Tweet

Transcript

  1. 4.

    …helps applications send and receive messages to/ from other applications

    [...]. It provides a message bus and some routing capabilities to send messages in any service where you need it https://symfony.com/blog/new-in-symfony-4-1-messenger-component
  2. 9.
  3. 10.

    <?php declare(strict_types = 1); namespace App\Domain\Screenshot; class TakeScreenshotCommand { private

    $url; public function __construct(string $url) { $this->url = $url; } public function getUrl(): string { return $this->url; } }
  4. 12.

    <?php declare(strict_types = 1); namespace App\Domain\Screenshot; use Symfony\Component\EventDispatcher\Event; class TakeScreenshotEvent

    extends Event { private $url; public function __construct(string $url) { $this->url = $url; } public function getUrl(): string { return $this->url; } }
  5. 14.
  6. 16.

    <?php declare(strict_types = 1); namespace App\Domain\Screenshot; use Symfony\Component\Messenger\Handler\MessageHandlerInterface; use Symfony\Component\Messenger\MessageBusInterface;

    class TakeScreenshotHandler implements MessageHandlerInterface { ... public function __invoke(TakeScreenshotCommand $takeScreenshot) { $screenshot = $this->client->takeScreenshot($takeScreenshot->getUrl()); $this->messageBus->dispatch(new ScreenshotTakenEvent($screenshot)); } }
  7. 18.

    namespace App\Domain\Screenshot; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class TakeScreenshotEventSubscriber implements EventSubscriberInterface

    { ... public static function getSubscribedEvents() { return ['app.take_screenshot' => ['takeScreenshot']]; } public function takeScreenshot(TakeScreenshotEvent $event) { $screenshot = $this->client->takeScreenshot($event->getUrl()); $this->eventDispatcher->dispatch(
 'app.save_screenshot', new SaveScreenshotEvent($screenshot) ); } }
  8. 20.

    <?php /* * This file is part of the Symfony

    package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Messenger\Handler; /** * Marker interface for message handlers. * * @author Samuel Roze <samuel.roze@gmail.com> * * @experimental in 4.2 */ interface MessageHandlerInterface { }
  9. 26.

    public static function getHandledMessages(): iterable { yield [TakeScreenshotCommand::class => ['takeDesktopScreenshot',

    0]]; yield [TakeScreenshotCommand::class => ['takeMobileScreenshot', 0]]; } public function takeDesktopScreenshot(
 TakeScreenshotCommand $takeScreenshot ) { ... } public function takeMobileScreenshot( TakeScreenshotCommand $takeScreenshot ) { ... }
  10. 34.

    # config/packages/messenger.yaml framework: messenger: buses: default: default_middleware: true # alternatives:

    false; "allow_no_handlers" middleware: - 'messenger.middleware.validation'
  11. 36.

    $defaultMiddleware = [ 'before' => [['id' => 'logging']], 'after' =>

    [ ['id' => 'send_message'], ['id' => 'handle_message'] ], ];
  12. 38.
  13. 39.
  14. 41.

    public function handle(Envelope $envelope, StackInterface $stack): Envelope { ... if

    (null === $sender || $handle) { return $stack->next()->handle($envelope, $stack); } // message should only be sent and not be handled by the next middleware return $envelope; }
  15. 43.

    if ($envelope->all(ReceivedStamp::class)) { // it's a received message, do not

    send it back return $stack->next()->handle($envelope, $stack); }
  16. 48.

    final class ValidationStamp implements StampInterface { private $groups; /** *

    @param string[]|GroupSequence $groups */ public function __construct($groups) { $this->groups = $groups; } public function getGroups() { return $this->groups; } }
  17. 50.

    public function handle(Envelope $envelope, StackInterface $stack): Envelope { $message =

    $envelope->getMessage(); $groups = null; /** @var ValidationStamp|null $validationStamp */ if ($validationStamp = $envelope->last(ValidationStamp::class)) { $groups = $validationStamp->getGroups(); } $violations = $this->validator->validate($message, null, $groups); if (\count($violations)) { throw new ValidationFailedException($message, $violations); } return $stack->next()->handle($envelope, $stack); }
  18. 51.

    /** @var ValidationStamp|null $validationStamp */ if ($validationStamp = $envelope->last(ValidationStamp::class)) {

    $groups = $validationStamp->getGroups(); } $violations = $this->validator->validate($message, null, $groups);
  19. 52.
  20. 63.
  21. 64.
  22. 65.
  23. 66.