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

Symfony Notifier Component

Symfony Notifier Component

069a861584701a8b5f72a838bd7e0f2e?s=128

Jan Schädlich

February 04, 2020
Tweet

More Decks by Jan Schädlich

Other Decks in Programming

Transcript

  1. Symfony Notifier Sending messages via a unified API Jan Schädlich

    @jschaedl SensioLabs 2020-02-04 | Symfony User Group Hamburg
  2. “… a notification system is a … software … that

    provides a means of delivering a message to a set of recipients … “ https://en.wikipedia.org/wiki/Notification_system What is a Notification System?
  3. Application Incident Notification System Sms Chat Email Notification

  4. Application Incident Notification System Policy Sms Chat Email Notification

  5. Symfony Notifier Component experimental

  6. ChannelPolicy ChatChannel SmsChannel EmailChannel Notifier Notification ChatMessage SmsMessage EmailMessage Texter

    Transport SmsMessage Transport ChatMessage Chatter Transports Transports Transports
  7. $ composer req symfony/notifier

  8. Transport Install with Slack composer require symfony/slack-notifier Telegram composer require

    symfony/telegram-notifier Twilio composer require symfony/twilio-notifier Nexmo composer require symfony/nexmo-notifier * Using Mailer Transports is also possible.
  9. Notifications

  10. Content Importance Subject

  11. use Symfony\Component\Notifier\Notification\Notification; $notification = (new Notification()) ->subject('A nice subject') ->content(‘An

    even nicer content.') ->importance(Notification::IMPORTANCE_URGENT) ; 1 2 3 4 5 6 7
  12. use Symfony\Component\Notifier\Notification\Notification; $notification = (new Notification()) ->subject('A nice subject') ->content(‘An

    even nicer content.') ->importance(Notification::IMPORTANCE_URGENT) ->emoji('!') # email, chat, sms # chat/slack, chat/telegram, sms/twilio, sms/nexmo # {channel}/{transport} ->channels([‘chat/slack', 'email']) ; 1 2 3 4 5 6 7 8 9 10 11 12
  13. use Symfony\Component\Notifier\Notification\Notification; $errorNotification = Notification::fromThrowable( new \Exception('Oops!') ); 1 2

    3 4 5
  14. use Symfony\Component\Notifier\Notification\Notification; $errorNotification = Notification::fromThrowable( new \Exception(‘Oops!'), # email, chat,

    sms # chat/slack, chat/telegram, sms/twilio, sms/nexmo ['chat/slack', 'email'] ); 1 2 3 4 5 6 7 8
  15. Notifier

  16. use Symfony\Component\Notifier\Notifier; // ??? $notifier = new Notifier($channels, $channelPolicy); $notifier->send(new

    Notification(…)); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
  17. use Symfony\Component\Notifier\Notifier; use Symfony\Component\Notifier\Bridge\Slack\SlackTransportFactory; $transport = (new SlackTransportFactory())->create(‘slack://...’); 1 2

    3 4 5 6 7 8 9 10 11 12 13 14 15 16
  18. use Symfony\Component\Notifier\Notifier; use Symfony\Component\Notifier\Transport; $transport = Transport::fromDsns([ 'slack://...', 'telegram://...' ]);

    // returns a Transports object 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
  19. use Symfony\Component\Notifier\Notifier; use Symfony\Component\Notifier\Bridge\Slack\SlackTransportFactory; use Symfony\Component\Notifier\Channel\ChatChannel; $transport = (new SlackTransportFactory())->create(‘slack://...’);

    $channels = [ 'chat' => new ChatChannel($transport) ]; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
  20. use Symfony\Component\Notifier\Notifier; use Symfony\Component\Notifier\Bridge\Slack\SlackTransportFactory; use Symfony\Component\Notifier\Channel\ChatChannel; use Symfony\Component\Notifier\Channel\ChannelPolicy; $transport =

    (new SlackTransportFactory())->create(‘slack://...’); $channels = ['chat' => new ChatChannel($transport)]; $channelPolicy = new ChannelPolicy([ 'urgent' => [‘chat‘], 'high' => ['chat'], 'medium' => [‘chat/slack‘], 'low' => [‘chat/slack'], ]); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
  21. use Symfony\Component\Notifier\Notifier; use Symfony\Component\Notifier\Bridge\Slack\SlackTransportFactory; use Symfony\Component\Notifier\Channel\ChatChannel; use Symfony\Component\Notifier\Channel\ChannelPolicy; $transport =

    (new SlackTransportFactory())->create(‘slack://...’); $channels = ['chat' => new ChatChannel($transport)]; $channelPolicy = new ChannelPolicy([/* ... */]); $notifier = new Notifier($channels, $channelPolicy); $notifier->send(new Notification(…), new Recipient(…)); 1 2 3 4 5 6 7 8 9 10 … 16 17 18 19 20
  22. Let’s take a closer look

  23. ChannelPolicy Routing to Channels and Transports

  24. $channelPolicy = new ChannelPolicy([ 'urgent' => ['email', 'chat/slack', 'sms'], 'high'

    => ['email', ‘chat/slack'], 'medium' => ['email'], 'low' => ['pidgeon'], ]); • Routing Notifications by importance to channels and transports • Define your own importance
  25. Channels Notifications to Messages

  26. $channels = [ 'email' => new EmailChannel($emailTransports), 'chat' => new

    ChatChannel($chatTransports), 'sms' => new SmsChannel($smsTransports), // ... ]; • Channels are like categories • Channels can hold several Transports • Channels convert Notifications into Messages - EmailNotificationInterface - ChatNotificationInterface - SmsNotificationInterface
  27. $channels = [ 'email' => new EmailChannel($emailTransports), 'chat' => new

    ChatChannel($chatTransports), 'sms' => new SmsChannel($smsTransports), 'browser' => new BrowserChannel($requestStack), ]; • BrowserChannel holds the RequestStack • BrowserChannel writes Notification as flash messages
  28. Transports Sending via third-party Service

  29. $chatTransports = Transport::fromDsns([ 'slack://ACCES_TOKEN@default?channel=CHANNEL', 'telegram://TELEGRAM_TOKEN@default' ]); $smsTransports = Transport::fromDsns([ 'twilio://ACCOUNT_ID:ACCOUNT_TOKEN@default?from=SENDER_NAME',

    'nexmo://API_TOKEN:API_SECRET@default?from=SENDER_NAME' ]); Supports ChatMessage only Supports SmsMessage only
  30. $dsn = 'failover(slack://ACCES_TOKEN@default?channel=CHANNEL telegram://TELEGRAM_TOKEN@default)';

  31. $dsn = 'roundrobin(slack://ACCES_TOKEN@default?channel=CHANNEL telegram://TELEGRAM_TOKEN@default)';

  32. Framework Integration

  33. framework: notifier: enabled: true chatter_transports: slack: '%env(SLACK_DSN)%' telegram: '%env(TELEGRAM_DSN)%' texter_transports:

    twilio: '%env(TWILIO_DSN)%' nexmo: '%env(NEXMO_DSN)%' channel_policy: # use chat/slack, chat/telegram, sms/twilio, sms/nexmo # or email, chat, sms urgent: ['email', 'chat', 'sms'] high: ['email', 'chat'] medium: ['email'] low: ['email'] admin_recipients: - { email: 'admin@example.com', phone: '0815 223445' } notification_on_failed_messages: false
  34. Monolog Handler

  35. # config/packages/prod/monolog.yaml monolog: channels: ['notifier'] handlers: admin_notifications: type: filter handler:

    notifier max_level: info channels: ['notifier'] notifier: type: service id: Symfony\Bridge\Monolog\Handler\NotifierHandler
  36. Messenger Integration

  37. namespace Symfony\Component\Notifier\Channel; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Notifier\Exception\LogicException; use Symfony\Component\Notifier\Transport\TransportInterface; abstract class

    AbstractChannel implements ChannelInterface { protected $transport; protected $bus; public function __construct( TransportInterface $transport = null, MessageBusInterface $bus = null ) { if (null === $transport && null === $bus) { throw new LogicException(...); } $this->transport = $transport; $this->bus = $bus; } }
  38. namespace Symfony\Component\Notifier\Messenger; use Symfony\Component\Notifier\Message\MessageInterface; use Symfony\Component\Notifier\Transport\TransportInterface; final class MessageHandler {

    private $transport; public function __construct(TransportInterface $transport) { $this->transport = $transport; } public function __invoke(MessageInterface $message) { $this->transport->send($message); } }
  39. # FrameworkBundle/Resources/config/notifier.xml <services> <service id="chatter.messenger.chat_handler" class="Symfony\Component\Notifier\Messenger\MessageHandler"> <argument type="service" id="chatter.transports" />

    <tag name="messenger.message_handler" handles="Symfony\Component\Notifier\Message\ChatMessage" /> </service> <service id="texter.messenger.sms_handler" class="Symfony\Component\Notifier\Messenger\MessageHandler"> <argument type="service" id="texter.transports" /> <tag name="messenger.message_handler" handles="Symfony\Component\Notifier\Message\SmsMessage" /> </service> </services>
  40. Disable delivery

  41. # config/packages/dev/notifier.yaml # config/packages/test/notifier.yaml framework: notifier: chatter_transports: slack: 'null://' telegram:

    'null://' texter_transports: twilio: 'null://' nexmo: 'null://'
  42. Feature Recap • Sending chat, sms, email and browser notifications

    • Built-in providers (Slack, Telegram, Nexmo, Twilio) • Monolog Handler • Async notifications via messenger • NULL transport for dev and test environment
  43. What’s missing? • More built-in providers (Microsofft Teams, Mattermost, etc.)

    • Possibility to define a custom transport • (Disable usage of messenger) • WebProfiler and DebugToolBar integration • WebTestCase notifier assertions
  44. Thank you! https://speakerdeck.com/jschaedl