LoginSignup
14
8

More than 3 years have passed since last update.

Laravelの通知ライブラリでslackボタンアクション機能を実装

Last updated at Posted at 2019-12-08

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内から削除されています。

gitの差分

slack通知のボタンアクション機能とは?

公式のgifだと以下のような表示。
ボタンが付いていて押された後、元のメッセージを変えて1人しか押せなかったり、誰が押したか表示したり色んな機能が考えられそうです..!
Example_6.gif

slack公式のボタン機能

今までの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 メソッドで指定します。

SlackNotificationService.php
<?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クラスを作成

SlackButtonMessage.php
<?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');
            });
    }
}

出ました!
スクリーンショット 2019-12-09 5.24.12.png

そして積みました...。slack-notification-channelはボタン通知に対応していますが、ボタン押した際のアクションは単純なURLリンクしか設定できないようです!
SlackAttachment.php の所定の位置を見ると確かにそうなってます。

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実装

書いていきます!

SlackButtonService.php

<?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;
    }
}

送信メッセージ出す所

send.php

    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);
    }

こんな感じで出ますね!
スクリーンショット 2019-12-09 7.37.30.png

slackからのレスポンス処理を設定(Interactive MessagesでここのURLを設定しておくことでPOSTされます)

web.php
Route::group(['prefix' => 'slack'], function()
{
    Route::post('/api/response', 'ApiController@getSlackResponse');
});

slackからのPOSTに対してcsrfトークンチェックを外す

VerifyCsrfToken.php
<?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/*',
    ];
}

レスポンス処理

ApiController.php
    public function getSlackResponse(Request $request){

        $temp = json_decode($request['payload'],true);
        $temp['original_message']['text']=$temp['user']['name'] . 'が押しました!';
        return response($temp['original_message']);
    }

こんな感じで通知が来た後に...

スクリーンショット 2019-12-09 7.37.30.png

ボタンを押すと...
スクリーンショット 2019-12-09 7.37.49.png

みたいに元のメッセージを変更したり出来ます!

slackを使っている会社では、slack連携による業務改善やエンゲージメントを高めるような施策が今後も増えてくると思います!
この記事が少しでも実装の助けになればと思います。

14
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
8