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以降しか変更されてないので注意です。(今5.7
をupdateするならメジャーアップデートしましょう。))
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を使い倒す] (https://qiita.com/ik-fib/items/b4a502d173a22b3947a0)
slack通知機能をまず作ります。この時、.env
に設定したwebhookをconfig
に書いておき、routeNotificationForSlack
メソッドで指定します。
<?php
namespace App\Services;
use App\Notifications\SlackButtonMessage;
use App\Notifications\SlackSend;
use App\Notifications\SlackSendQuestion;
use Illuminate\Notifications\Notifiable;
class SlackNotificationService
{
use Notifiable;
/**
* SlackチャンネルのWebhookURLを返す
*
* @return string
*/
public function routeNotificationForSlack()
{
return config('services.slack.button');
}
/**
* 送信メソッド
* @param $message
*/
public function send()
{
// 通知
$this->notify(new SlackButtonMessage());
}
}
上記の送信メソッドで呼ばれるslackボタン通知用のNotificationクラスを作成
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
/**
* Slack通知クラス
*/
class SlackButtonMessage extends Notification
{
use Queueable;
private $sendMessage;
private $title;
/**
* 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'];
}
/**
* Slack通知処理
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\SlackMessage
*/
public function toSlack($notifiable)
{
return (new SlackMessage)
->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
*/
public function action($title, $url, $style = '')
{
$this->actions[] = [
'type' => 'button',
'text' => $title,
'url' => $url,
'style' => $style,
];
return $this;
}
gifのようにボタン押下後に、元のメッセージに色々アクションを実装したい場合は、無理ですね。
あくまでも通知クラスのライブラリということですね。
GuzzleでAPI実装
書いていきます!
<?php
namespace App\Services;
use GuzzleHttp\Client;
class SlackButtonService
{
public function postMessage( $message ) {
$client = new Client([
'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
*/
public function __construct(
SlackButtonService $service)
{
$this->slack = $service;
}
public function send(){
$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トークンチェックを外す
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* 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/*',
];
}
レスポンス処理
public function getSlackResponse(Request $request){
$temp = json_decode($request['payload'],true);
$temp['original_message']['text']=$temp['user']['name'] . 'が押しました!';
return response($temp['original_message']);
}
こんな感じで通知が来た後に...
みたいに元のメッセージを変更したり出来ます!
slackを使っている会社では、slack連携による業務改善やエンゲージメントを高めるような施策が今後も増えてくると思います!
この記事が少しでも実装の助けになればと思います。