【Laravel】Notificationを使って、一番シンプルなSlack通知機能を実装する

##作成物
ユーザーが以下のようなフォームを送信した際に、管理者へSlack通知を送信する機能を実装します。

![スクリーンショット 2021-09-19 7.08.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1208065/12e5f4dd-3cdc-7194-aad6-814605abf384.png)

####ちなみに...
Laravelでメールを送信する方法は、MailableとNotificationの2つあります。

メールを送信するのみならばMailableの方が使いやすいという意見が多いようですが、Mailableはメールしか使えない一方で、NotificationはSMSやSlackなど色々なチャンネルで通知を送信することができます。

今回はSlack通知を実装するため、Notificationを使います。


 

#手順
1. Webhook URLの取得
2. slack-notification-channelパッケージのインストール
3. Notificationクラスの作成
4. 通知送信処理を記述する（Notifiable）


##1.　Webhook URLの取得
###Webhook URLとは　~APIとの違い~
Webhookとは、サーバー上である特定のイベントが発生した時に、サーバー側からクライアント側に通知するシステムのことです。例えば、お気に入りに登録した商品が割引になった際にSNSで通知する、など多くの使い方があります。

APIはリクエストに対してレスポンスしてくれるのに対して、Webhookはリクエストしなくても予め設定した条件によってレスポンスしてくれます。この点がAPIとの違いです。

Webhookに対応しているサービスは、Slack以外にも、ChatWork・Twitter・GitHubなど数多く存在します。

###SlackのWebhook

Slack通知のルートに使用するためのURLとして、予めSlack側でWebhook URLを取得する必要があります。
取得方法は下記の記事を参考にさせていただきました。

https://www.yukibnb.com/entry/slack_incoming_webhook_url

URLを取得したら、.envに記述しておきます。

```env:.env
SLACK_CHANNEL=laravel_notification    //任意で設定したチャンネル
SLACK_URL=https://hooks.slack.com/services/・・・    //取得したURL
```

##2. slack-notification-channelパッケージのインストール
LaravelでSlack Notificationを利用するためには、slack-notification-channelパッケージをインストールする必要があります。

```
$ composer require laravel/slack-notification-channel
``` 

##3. Notificationクラスの作成
Notificationクラスを作成します。
このクラスの役割は以下の２つです。

* メッセージ内容の生成
* 通知方法の指定

Notificationクラスはコマンドで作成できます。

```
$ php artisan make:notification SendSlack    //クラス名は任意で設定
```

実行すると`app/Notifications`の下に`SendSlack.php`ファイルが作成されます。
このファイルを下記のように編集します。



```SendSlack.php
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\SlackMessage;    //追記

class SendSlack extends Notification
{
    use Queueable;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct()
    {
       //
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['slack'];    //編集
    }

    public function toSlack($notifiable)    //編集
    {
        return (new SlackMessage)
            ->content("新規ユーザーが登録されました。");
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            //
        ];
    }
}

```

###コードの解説
* viaメソッド
・通知方法を指定します。
・デフォルトでは`mail`になっているので、`slack`に変更します。

* toSlackメソッド
・Slackメッセージを送信する場合は、NotificationクラスにtoSlackメソッドを定義すると決められています。([ReDouble](https://readouble.com/laravel/8.x/ja/notifications.html))
・このメソッドは$notifiableエンティティを受け取り、Illuminate\Notifications\Messages\SlackMessageインスタンスを返す必要があります。
・SlackMessageクラスを利用していますが、これはslack-notification-channelをインストールすることで利用できるクラスです。
・contentメソッドを使って、送信するテキストを指定します。
・他にもfromメソッド・toメソッドを使って送信者・受信者をカスタマイズしたり、imageメソッドで画像を使用することもできます。


###Notificationクラスの使い方
このNotificationクラスをインスタンス化して、notifyメソッド（後述）の引数として渡すことで、通知の送信処理が実行されます。


##4. 通知送信処理を記述する（Notifiable）
記述したいのは以下の2点です。

* 通知送信処理の実行
* 通知送信先の指定

通知を送信する処理の方法は、`Notifiableトレイトのnotifyメソッド`を使用する方法と、`Notificationファサード`を使用する方法の2つあります。今回はNotifiableトレイトを使って記述していきます。

Notifiableトレイトをuseしたクラスであればどこでも、送信処理を書くことができます。（App\Models\User.phpにはデフォルトでNotifiableトレイトがuseされています。）

今回は新しくコントローラーを作成してNotifiableトレイトをuseし、コントローラー内で通知送信処理を記述することにします。

```
$ php artisan make:controller SlackController
```

処理の流れを掴むため、ここでルーティングの設定も済ませておきます。

```web.php
Route::get('/slack', [SlackController::class,'index']);
Route::post('/slack', [SlackController::class,'send']);
```

```SlackController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Notifications\Notifiable;    //追記
use App\Notifications\SendSlack;    //追記
use Illuminate\Notifications\Messages\SlackMessage;    //追記


class SlackController extends Controller
{
    use Notifiable;    //追記

    public function index()
    {
        return view('slack.index');
    }

    public function send()
    {
        $slack = $this->notify(new SendSlack());

        session()->flash('success', '送信しました！');
        return back();
    }

    public function routeNotificationForSlack($notification)
    {
        return config('app.slack_url');
    }
}

```
###コードの解説
* indexメソッド
・フォーム画面にアクセスした際の処理です。
・resources/views/slack/index.blade.phpにて、フォーム画面のビューを作成します（コードは後ほど記載）。

* sendメソッド
・フォームを送信した際の処理です。
・notifyメソッドは、Notificationクラスのインスタンスを引数に受けます。notifyメソッドはNotifiableトレイトのメソッドです。
・送信後、フォーム画面にフラッシュメッセージを表示するため、セッションを使っています。

* routeNotificationForSlackメソッド
・Slack通知を適切なチャンネルにルーティングするために、このメソッドを定義します。
・通知の配信先となるWebhook URLを返します。
・直接URLを記述するのではなく、envに書いたURLをconfigで呼び出し、configの設定をこのメソッドで呼び出しています。
※下記のように、config/app.phpにおいてenv関数を使い、envに設定したURLを読み込んでいます。

```config\app.php
'slack_url' => env('SLACK_URL'),
```

##ビューの作成
フォーム画面のビューを作成します。

```html:index.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Slack Notification</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
</head>

<body>
<form action="{{ url('slack') }}" method='POST'>
    @csrf
    <div class="form-group">
        <p>名前</p>
        <input type="text" name="name" value="{{ old('name') }}" class="form-control">

        <p>メッセージ</p>
        <input type="text" name="message" value="{{ old('message') }}" class="form-control">

        <p><input type="submit" value="送信" class="btn"></p>
    </div>
</form>

@if (Session::has('success'))
<div class="session">
    <p class="bg-warning text-center">{{ Session::get('success')}}</p>
</div>
@endif

</body>
</html>
```

##動作確認
ローカルサーバーを立ち上げ、`localhost:8000/slack`にアクセスすると、フォーム画面が表示されます。
内容を入力して送信ボタンを押せば、登録したSlackのチャンネルに通知が届きます。


##参考記事

https://readouble.com/laravel/8.x/ja/notifications.html

https://qiita.com/ikasama/items/de7c5aa8c6056b79adf3

https://reffect.co.jp/laravel/laravel-event-listener#Slack

https://biz.addisteria.com/mailable_notifications/