Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

Denis Brumann

March 05, 2019
Tweet

More Decks by Denis Brumann

Other Decks in Programming

Transcript

  1. …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. <?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; } }
  3. <?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; } }
  4. <?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)); } }
  5. 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) ); } }
  6. <?php /* * This file is part of the Symfony

    package. * * (c) Fabien Potencier <[email protected]> * * 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 <[email protected]> * * @experimental in 4.2 */ interface MessageHandlerInterface { }
  7. 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 ) { ... }
  8. # config/packages/messenger.yaml framework: messenger: buses: default: default_middleware: true # alternatives:

    false; "allow_no_handlers" middleware: - 'messenger.middleware.validation'
  9. $defaultMiddleware = [ 'before' => [['id' => 'logging']], 'after' =>

    [ ['id' => 'send_message'], ['id' => 'handle_message'] ], ];
  10. 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; }
  11. if ($envelope->all(ReceivedStamp::class)) { // it's a received message, do not

    send it back return $stack->next()->handle($envelope, $stack); }
  12. final class ValidationStamp implements StampInterface { private $groups; /** *

    @param string[]|GroupSequence $groups */ public function __construct($groups) { $this->groups = $groups; } public function getGroups() { return $this->groups; } }
  13. 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); }
  14. /** @var ValidationStamp|null $validationStamp */ if ($validationStamp = $envelope->last(ValidationStamp::class)) {

    $groups = $validationStamp->getGroups(); } $violations = $this->validator->validate($message, null, $groups);