いろいろなサービスで通知する、"Notifier"

[Symfony Component Advent Calendar 2022](https://qiita.com/advent-calendar/2022/symfony-component)の12日目の記事です。

## 最初に
[Symfony](https://symfony.com)はPHPのフレームワークのひとつです。しかし、公式サイトの説明文には

> Symfony is a set of PHP Components, a Web Application framework, a Philosophy, and a Community — all working together in harmony.
  （SymfonyはPHPコンポーネントのセットで、Webアプリケーションフレームワークで、哲学、そしてコミュニティです。それらがハーモニーを奏でながら動作しています。）

と書かれている通り、PHPコンポーネントのセットで、たくさんのコンポーネントを提供しており、それらを組み合わせてひとつのフレームワークとして動作しています。Symfonyのコンポーネントは、Symfony上だけで動作するのではなく、他のPHPフレームワークやアプリケーションでも動作している強力なものが揃っています。

今回はそれらの中から、役立ちそうなもの・お薦めしたいものを紹介していきたいと思います。

※記事内ではautoloadのインポートは省略します。


## いろいろなサービスで通知する、"Notifier"

[Notifier](https://symfony.com/doc/current/notifier.html)は、**メールも含めて**いろいろなサービスを使って通知を行うコンポーネントです。前述のとおりメールも対象なので[Mailer](https://qiita.com/ippey_s/private/f082a0d676220e261204)に依存しています。

### インストール

```shell
composer require symfony/notifier
```

### 通知は5種類

通知は大まかに分けて5種類の通知を用意してあり、各種さまざまなプロバイダをサポートしています。

| 種類 | 概要 |
|---|---|
| SMS | SMSメッセージで通知 |
| Chat | テキストチャットサービスで通知 |
| Email | メールで通知 |
| ブラウザ | 画面上にフラッシュメッセージで通知 |
| Push | Push通知 |



[Mailer](https://qiita.com/ippey_s/private/f082a0d676220e261204)と同じく、[それぞれの種類ごとに複数のプロバイダ](https://symfony.com/doc/current/notifier.html#sms-channel)をサポートしていて、利用するためにはコンポーネントを追加でインストールします。また、DSNの設定も同じく`.env`に設定します。

```:.env
CHATWORK_DSN=chatwork://{APIトークン}@default?room_id={ルームID}
```

```yaml:config/packages/notifier.yaml
framework:
    notifier:
        chatter_transports:
            slack: '%env(CHATWORK_DSN)%'
```

### 通知を送る

通知を送る場合、`Notification`オブジェクトを作成し、`NotifierInterface`を使って通知を送信します。


```php:ItemController.php

use Symfony\Component\Notifier\Notification\Notification;
use Symfony\Component\Notifier\NotifierInterface;
use Symfony\Component\Notifier\Recipient\Recipient;

class ItemController extends AbstractController
{
    public function publish(NotifierInterface $notifier): Response
    {
        $notification = new Notification('メッセージ', ['email', 'sms']);
        $recipient = new Recipient('{メールアドレス}', '{電話番号}'); // どちらかが必要

        $notifier->send($notification, $recipient);
    }
}
```

Chatサービスなどの通知先を指定する必要がなかったりメールアドレス・電話番号ではない場合は、`ChatterInterface`, `TexerInterface`などのクラスを使い、送信処理を行います。
利用する場合は、それぞれ専用の通知クラスを使います。

```php

public function publish(ChatterInterface $chatter, TexterInterface $texer): Response
{
    $chatMessage = new ChatMessage('メッセージ'); // Chatの場合
    $chatter->send($chatMessage);

    $pushMessage = new PushMessage('メッセージ'); // Push通知の場合
    $texter->send($pushMessage);
}
```

### 通知を設定する

通知によって、送り先を変えたり設定を変更したい場合もあります。そのような場合は、それぞれのプロバイダで専用の設定クラスが用意されています。例えば`Chatwork`の場合、

```php:ItemController.php
class ItemController extends AbstractController
{
    public function publish(ChatterInterface $chatter): Response
    {
        // メッセージ
        $chatMessage = new ChatMessage('メッセージ');

        // オプション設定
        $chatworkOptions = new ChatworkOptions([]);
        $chatworkOptions
            ->to(['{ルームID}']) // ルームIDの指定
            ->selfUnread(false)
        ;
        $chatMessage->options($chatworkOption);
        
        $chatter->send($chatMessage); // 送信
    }
}
```

`ChatworkOptions`オブジェクトを作成し、そこに設定を行います。そのオブジェクトを`ChatMessage`オブジェクトに渡すことで、指定のルームにメッセージを送ることができます。

### フェイルオーバー、ラウンドロビン

コンポーネントの設定により、フェイルオーバー、ラウンドロビンに対応できます。


```yaml:config/packages/notifier.yaml
framework:
    notifier:
        chatter_transports:
            # Slackで送信エラーの場合はChatworkで送る
            main: '%env(SLACK_DSN)% || %env(CHATWORK_DSN)%'

            # Slackで送った後の次の通知はChatworkで送る
            roundrobin: '%env(SLACK_DSN)% && %env(CHATWORK_DSN)%'
```

## まとめ

今回は`Notifier`を紹介しました。`Mailer`と似たようなコンポーネントですが、システム管理者に対しての通知だったり、SMS, チャットサービスを利用した通知だったりを行うことができ、とても便利なコンポーネントです。


### 補足

::: note info
Symfony 6.2から[Chatworkが利用できるようになりました](https://github.com/symfony/chatwork-notifier)。
**私が作成しました**。ぜひご活用ください。

:::