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 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 Slide

  3. Application
    Incident
    Notification System
    Sms
    Chat
    Email
    Notification

    View Slide

  4. Application
    Incident
    Notification System
    Policy
    Sms
    Chat
    Email
    Notification

    View Slide

  5. Symfony Notifier
    Component
    experimental

    View Slide

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

    View Slide

  7. $ composer req symfony/notifier

    View 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 Slide

  9. Notifications

    View Slide

  10. Content
    Importance
    Subject

    View 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 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 Slide

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

    View 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 Slide

  15. Notifier

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View 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([
    '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 Slide

  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

    View Slide

  22. Let’s take a closer look

    View Slide

  23. ChannelPolicy
    Routing to Channels and Transports

    View Slide

  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

    View Slide

  25. Channels
    Notifications to Messages

    View Slide

  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

    View Slide

  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

    View Slide

  28. Transports
    Sending via third-party Service

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  32. Framework Integration

    View Slide

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

    View Slide

  34. Monolog Handler

    View Slide

  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

    View Slide

  36. Messenger Integration

    View Slide

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

    View Slide

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

    View Slide

  39. # 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 Slide

  40. Disable delivery

    View Slide

  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://'

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide