Laravel 5.3+ で実装された Notification を使用して Laravel でいつでもどこでも Slack 通知を発火する。
Notification は RoutesNotifications
トレイトを継承しているすべてのクラスから発火することが可能。必要に応じてユーザーの Slack Webhookに通知を飛ばすことも可能だが、通常はアプリケーション運営側の同一チームに送信することが主であろう。そのため、通知を飛ばすクラス (notifiable) に以下のようなトレイトを継承させておくと使いやすい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?php namespace App\Traits\Notification; use Illuminate\Notifications\RoutesNotifications; trait SlackNotifiable { use RoutesNotifications; public function routeNotificationForSlack(): string { return config('services.slack.hook'); // 適当な Webhook URLを返す } } |
なお、このトレイトを Notifiable
と同時に継承してしまうと同レベルで同じトレイト(RoutesNotifications
)を継承しているため同時重複宣言エラーとなってしまうので注意されたい。
もくじ
設置準備
Slack Webhook URL の取得
当たり前だが、Slackに通知するにはSlack側にアプリを登録しておく必要がある。Laravelの Slack Webhook channel では Incoming Webhooks を利用するのでここから登録し、Webhook の URLを取得しておく。
なお、発行されるURLは https://hooks.slack.com/services/{{チームID}}/B4X8MFMK8/{{キー}}
の形となる。
また、このページから自動投稿に使用するデフォルトのchや表示名、アイコンを設定できる。これら (Label以外) は投稿時に個別に設定することも可能。
(~5.7) Guzzle HTTP Client のインストール
新規に作成したLaravel アプリには guzzle がインストールされていない。Slack Webhook Channel はこれを利用しているので入っていなければインストールする。
1 |
composer require guzzlehttp/guzzle |
(5.8+) Slack Channel のインストール
Laravel 5.8 でこの Slack チャンネルは外部パッケージに分離されたので、これをインストールする必要がある。なおこのパッケージの依存関係としてguzzleはついてくるので上記の操作は飛ばせる。
1 |
composer require laravel/slack-notification-channel |
Notifiable を継承
通知を呼びすクラス (notifiable) で Notifiable
、または上記の SlackNotifiable
を継承 (use
) する。notifiableに使用するクラスは何でもいいが、一般に Model (Entity) なクラスに持たせるのが使いやすい。
SlackNotifiable
を使用しなかったのならば、上で取得したURLを返す routeNotificationForSlack
メソッドをそのクラスに用意しておこう。
デフォルトの User モデルだとこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?php namespace App; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { use Notifiable; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; protected function routeNotificationForSlack() { return 'https://hooks.slack.com/services/...'; } } |
公開するアプリとかだったらカスタマイズ性を高められる方がいいが、テストに使う分には十分だろう。
コラム: ユーザーが指定したWebhookに投げる
Laravel アプリからユーザーの Slack への投稿権を得る方法はいくつかあるだろう。例えば、上記の方法で取得した URL をユーザー設定で登録してもらう。あるいは、Slack apps の OAuth 2 で incoming-webhook
を 付与してやればWebhook用のURLを得ることが出来る。(前者の場合はバリでとか考えるのが面倒そう:: esa.io とかは前者。)
例えばこのURLをそのユーザーの routeNotificationForSlack
で返してやり、そのモデルに対して notify
メソッドで SlackNotification を投げてやればユーザーのSlackに通知を飛ばすことが可能だろう。(このメソッドでfalsyな値を返せば通知の送信はスキップされる)
この場合、ユーザーの指定したchにきちんと通知の飛ぶよう、SlackMessage (後述) にchを設定すべきでない。
Notification の作成と送信
Notification の扱い方はメール通知のときと大してかわらない。また、1つのNotificationからメール、Slack……のように複数に同時送信することも可能だが、今回は省略する。
Notification
通知のクラスを作成してやる。例えば以下の例ではSlackに次のような通知が送信される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
<?php namespace App\Notifications; use App\User; use Carbon\Carbon; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Messages\SlackAttachment; use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; use Illuminate\Contracts\Queue\ShouldQueue; class NewUserSlackNotification extends Notification { use Queueable; /** * @var User */ private $user; /** * Create a new notification instance. * * @return void */ public function __construct(User $user) { $this->user = $user; } /** * Get the notification's delivery channels. * * @param mixed $notifiable * @return array */ public function via($notifiable) { return ['slack']; } public function toSlack($notifiable) { return (new SlackMessage()) ->from('Larapet') ->image('https://larapet.hinaloe.net/wp-content/uploads/sites/15/2017/03/cropped-86f8cf99663ac01836df2fa9c56890ff-1.png') ->content('新規ユーザー登録') ->attachment(function (SlackAttachment $attachment) { $attachment ->title('ユーザー', route('user-profile', ['user' => $this->user->getKey()])) ->field('名前', $this->user->name) ->field('メールアドレス', $this->user->email) ->timestamp(Carbon::parse($this->user->{$this->user->getCreatedAtColumn()})); }) ->attachment(function (SlackAttachment $attachment) { $attachment->title('2つ目のattachment')->color('#ffa'); }); } } |
(通知の送信にQueueを使用する場合はShouldQueueも継承する)
このほか、$message->to('#hoge')
で送信先CHを指定したりも出来るので、SlackMessage や SlackAttachment の APIドキュメントも参考に。
送信
通知を送りたいタイミングで notifiableのnotifyメソッドを呼んでやるのみ。
上記 Notification の場合、コンストラクタで対象を渡しているのでこんな感じ。
1 |
$user->notify(new NewUserSlackNotification($user)); |
(メール通知と組み合わせてみる: https://gist.github.com/hinaloe/042fdb4d5e03965fb2557f283cfcf9d1 )
作成時のテストには routes/console.php
でコマンドを設定してやり、artisanから呼ぶと捗る。
1 2 3 4 |
Artisan::command('slack', function () { $user = \App\User::first(); $user->notify(new \App\Notifications\NewUserSlackNotification($user)); }); |
また、Notification の toSlack
や via
にはnotifiable (ここでは $user
)が渡されるので、これを利用するのも捗るかもしれない。
最近はシステムの通知をすべてSlackに一元化してポジションにかかわらずサービスを管理、見渡しやすくなった。(もちろん同ポジションのものは他にもあったわけだが)
通知チャンネルとしては欠かせないものなので、それが標準機能で簡単に使えるのは嬉しい。うまく活用できるといいだろう。