Laravel Advent Calendar 2019 - Qiita の 9 日目 の記事です。
Laravelの通知ライブラリを使ってボタン付きのslack通知を実装した記事を
下書きのままにしていたので書き上げることにしました..!
Laravelの通知ライブラリ
laravel5.8以降のslack通知機能に変化
通知クラスが外部ライブラリに変わりました!
5.8以降のslack通知(公式)
composerを使って入れないと使えなくなりました。
composer require laravel/slack-notification-channel
ちなみにv5.8
以前はguzzle
を入れれば使える形でした..。
5.8以前のslack通知(公式)
(実はv5.7.16
以降から通知クラスは外部ライブラリ化されてますが、ドキュメントは5.8以降しか)
Nexmoの通知クラスと一緒にframwork内から削除されています。
slack通知のボタンアクション機能とは?
公式のgifだと以下のような表示。
ボタンが付いていて押された後、元のメッセージを変えて1人しか押せなかったり、誰が押したか表示したり色んな機能が考えられそうです..!
今までのslack通知クラスでボタン機能使えなかったの?
そうなんです!
当然、slack側のAPIには用意されていたのでguzzle
で直接叩いたり、Custom Channels
を使って実装することは出来ましたが、Laravelが用意してくれている通知クラスでは使えませんでした。
環境
Laravelの開発環境をdockerで作るなら、@ucan-labさんのLaravelの開発環境をDockerを使って構築するがおすすめです。常に更新されてる!
slack側の設定は以下を参考に
・Slack APIを使用してメッセージを送信する
slackのボタンアクション通知の仕組みはこちらを参考にしました!
・slackで単純なボタン付きメッセージを送る
通信ライブラリを使って実装
さて、通信ライブラリを使って実装してみましょう。
slack-notification-channel
通知したいチャンネルにIncoming Webhooksの設定をしてwebhookを取得します
Incoming Webhooksについてはこの記事を参考にしました。
SlackのIncoming Webhooksを使い倒す
slack通知機能をまず作ります。この時、.env
に設定したwebhookをconfig
に書いておき、routeNotificationForSlack
メソッドで指定します。
<?phpnamespaceApp\Services;useApp\Notifications\SlackButtonMessage;useApp\Notifications\SlackSend;useApp\Notifications\SlackSendQuestion;useIlluminate\Notifications\Notifiable;classSlackNotificationService{useNotifiable;/**
* SlackチャンネルのWebhookURLを返す
*
* @return string
*/publicfunctionrouteNotificationForSlack(){returnconfig('services.slack.button');}/**
* 送信メソッド
* @param $message
*/publicfunctionsend(){// 通知$this->notify(newSlackButtonMessage());}}
上記の送信メソッドで呼ばれるslackボタン通知用のNotificationクラスを作成
<?phpnamespaceApp\Notifications;useIlluminate\Bus\Queueable;useIlluminate\Notifications\Messages\SlackMessage;useIlluminate\Notifications\Notification;/**
* Slack通知クラス
*/classSlackButtonMessageextendsNotification{useQueueable;private$sendMessage;private$title;/**
* Create a new notification instance.
*
* @return void
*/publicfunction__construct(){}/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/publicfunctionvia($notifiable){return['slack'];}/**
* Slack通知処理
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\SlackMessage
*/publicfunctiontoSlack($notifiable){return(newSlackMessage)->from('Test通知',':face_vomiting:')->content('これはテストです :face_vomiting:')->attachment(function($attachment){$attachment->action('googleリンク','https://www.google.com/','primary');});}}
そして積みました...。slack-notification-channel
はボタン通知に対応していますが、ボタン押した際のアクションは単純なURLリンクしか設定できないようです!SlackAttachment.php
の所定の位置を見ると確かにそうなってます。
/**
* Add an action (button) under the attachment.
*
* @param string $title
* @param string $url
* @param string $style
* @return $this
*/publicfunctionaction($title,$url,$style=''){$this->actions[]=['type'=>'button','text'=>$title,'url'=>$url,'style'=>$style,];return$this;}
gifのようにボタン押下後に、元のメッセージに色々アクションを実装したい場合は、無理ですね。
あくまでも通知クラスのライブラリということですね。
GuzzleでAPI実装
書いていきます!
<?phpnamespaceApp\Services;useGuzzleHttp\Client;classSlackButtonService{publicfunctionpostMessage($message){$client=newClient(['headers'=>['Content-Type'=>'application/json']]);$response=$client->post(config('services.slack.button'),['body'=>$message]);logger($response->getBody());$data=json_decode($response->getBody()->getContents());return$data;}}
送信メッセージ出す所
private$slack;/**
* Create a new controller instance.
*
* @return void
*/publicfunction__construct(SlackButtonService$service){$this->slack=$service;}publicfunctionsend(){$message="こんにちは!";$data=array("text"=>$message);$actions=["id"=>"1","name"=>"test",'type'=>"button",'text'=>"こんにちは!","value"=>"button_1",];$data+=["attachments"=>[["callback_id"=>"test","fallback"=>"More details...",'actions'=>[$actions],]]];$payload=json_encode($data);$res=$this->slack->postMessage($payload);}
slackからのレスポンス処理を設定(Interactive MessagesでここのURLを設定しておくことでPOSTされます)
Route::group(['prefix'=>'slack'],function(){Route::post('/api/response','ApiController@getSlackResponse');});
slackからのPOSTに対してcsrfトークンチェックを外す
<?phpnamespaceApp\Http\Middleware;useIlluminate\Foundation\Http\Middleware\VerifyCsrfTokenasMiddleware;classVerifyCsrfTokenextendsMiddleware{/**
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
*
* @var bool
*/protected$addHttpCookie=true;/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/protected$except=[//'/slack/api/*',];}
レスポンス処理
publicfunctiongetSlackResponse(Request$request){$temp=json_decode($request['payload'],true);$temp['original_message']['text']=$temp['user']['name'].'が押しました!';returnresponse($temp['original_message']);}
こんな感じで通知が来た後に...
みたいに元のメッセージを変更したり出来ます!
slackを使っている会社では、slack連携による業務改善やエンゲージメントを高めるような施策が今後も増えてくると思います!
この記事が少しでも実装の助けになればと思います。