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

Symfony Notifier Component

Symfony Notifier Component

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

    View full-size slide

  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?

    View full-size slide

  3. Application
    Incident
    Notification System
    Sms
    Chat
    Email
    Notification

    View full-size slide

  4. Application
    Incident
    Notification System
    Policy
    Sms
    Chat
    Email
    Notification

    View full-size slide

  5. Symfony Notifier
    Component
    experimental

    View full-size slide

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

    View full-size slide

  7. $ composer req symfony/notifier

    View full-size slide

  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.

    View full-size slide

  9. Notifications

    View full-size slide

  10. Content
    Importance
    Subject

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  13. use Symfony\Component\Notifier\Notification\Notification;
    $errorNotification = Notification::fromThrowable(
    new \Exception('Oops!')
    );
    1
    2
    3
    4
    5

    View full-size slide

  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

    View full-size slide

  15. 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

    View full-size slide

  16. 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

    View full-size slide

  17. 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

    View full-size slide

  18. 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

    View full-size slide

  19. 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

    View full-size slide

  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([/* ... */]);
    $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

    View full-size slide

  21. Let’s take a closer look

    View full-size slide

  22. ChannelPolicy
    Routing to Channels and Transports

    View full-size slide

  23. $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

    View full-size slide

  24. Channels
    Notifications to Messages

    View full-size slide

  25. $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

    View full-size slide

  26. $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

    View full-size slide

  27. Transports
    Sending via third-party Service

    View full-size slide

  28. $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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  31. Framework Integration

    View full-size slide

  32. 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: '[email protected]', phone: '0815 223445' }
    notification_on_failed_messages: false

    View full-size slide

  33. Monolog Handler

    View full-size slide

  34. # 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

    View full-size slide

  35. Messenger Integration

    View full-size slide

  36. 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;
    }
    }

    View full-size slide

  37. 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);
    }
    }

    View full-size slide

  38. # FrameworkBundle/Resources/config/notifier.xml

    class="Symfony\Component\Notifier\Messenger\MessageHandler">

    handles="Symfony\Component\Notifier\Message\ChatMessage" />

    class="Symfony\Component\Notifier\Messenger\MessageHandler">

    handles="Symfony\Component\Notifier\Message\SmsMessage" />


    View full-size slide

  39. Disable delivery

    View full-size slide

  40. # config/packages/dev/notifier.yaml
    # config/packages/test/notifier.yaml
    framework:
    notifier:
    chatter_transports:
    slack: 'null://'
    telegram: 'null://'
    texter_transports:
    twilio: 'null://'
    nexmo: 'null://'

    View full-size slide

  41. 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

    View full-size slide

  42. 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

    View full-size slide

  43. Thank you!
    https://speakerdeck.com/jschaedl

    View full-size slide