Help us understand the problem. What is going on with this article?

LaravelでFacadeを作ってSlackに通知してみた

お知らせ

改善を加えた新記事はこちらになります。

概要

既存のシステムをメンテナンスする上でエラーが発生したときにSlackに通知させるようにしたかったので、そのときの実装内容をメモとして残しておきます。

参考にさせていただいたサンプルではモデルを通知可能(Notifiable)にして通知処理を記述してありましたが、どこからでも呼び出せるように
Facadeを作成して通知する形にしました。

環境

Laravel:5.8
PHP:7.2

SlackのWebhook URLを取得

こちらからSlackと連携するためのWebhook URLを取得します。

https://[通知したいワークスペース名].slack.com/apps/A0F7XDUAZ--incoming-webhook-?next_id=0

取得したURLは.envファイルに記載しておきます。
通知先のチャネルや投稿されるときの名前等は上記の設定画面で設定しておくこともできますが、通知するときに指定することもできるので合わせて.envファイルに記載しておきます。

.env
SLACK_USERNAME=エラー通知
SLACK_ICON=:fire:
SLACK_CHANNEL=notice-error
SLACK_URL=https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/xxxxxXXxxXxXXxxXXXXXxx

Slack通知チャンネルを追加する

Laravel5.7以前はGuzzle HTTPクライアントがあればよかったのですが、5.8以降はSlack通知チャンネルのインストールが必要になります。

> composer require laravel/slack-notification-channel

Notificationクラスを作成する

以下のコマンドでNotificationクラスを作成します。

> php artisan make:notification SlackNotification

app/Notifications/SlackNotification.phpというファイルが作成されますので、Slack通知用に変更していきます。

app/Notifications/SlackNotification.php
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Messages\SlackAttachment;

class SlackNotification extends Notification
{
    use Queueable;

    protected $message;
    protected $attachment;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct($message = null, $attachment = null)
    {
        $this->message = $message;
        $this->attachment = $attachment;
    }

    /**
     * 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)
    {
        $message = (new SlackMessage)
            ->from(env('SLACK_USERNAME'), env('SLACK_ICON'))
            ->to(env('SLACK_CHANNEL'))
            ->content($this->message);

        if (!is_null($this->attachment) && is_array($this->attachment)) {
            $message->attachment(function (SlackAttachment $attachment) {
                if (isset($this->attachment['title'])) {
                    $attachment->title($this->attachment['title']);
                }
                if (isset($this->attachment['content'])) {
                    $attachment->content($this->attachment['content']);
                }
                if (isset($this->attachment['field']) && is_array($this->attachment['field'])) {
                    foreach($this->attachment['field'] as $k => $v) {
                        $attachment->field($k, $v);
                    }
                }
            });
        }
        return $message;
    }

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

Slack通知ファサードを作成する

Slack通知処理本体の作成

  • Notifiableトレイトを追加する
  • 通知先のURLを返すrouteNotificationForSlackメソッドを追加する
  • 通知処理の中で$this->notify()を呼び出す
app/Services/Slack/SlackService.php
<?php
namespace App\Services\Slack;

use Illuminate\Notifications\Notifiable;
use App\Notifications\SlackNotification;

class SlackService
{
    use Notifiable;

    public function send($message = null, $attachment = null)
    {
        $this->notify(new SlackNotification($message, $attachment));
    }

    protected function routeNotificationForSlack()
    {
        return env('SLACK_URL');
    }
}

ファサードクラスを作成

app/Services/Slack/SlackFacade.php
<?php
namespace App\Services\Slack;

use Illuminate\Support\Facades\Facade;

class SlackFacade extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'slack';
    }
}

サービスプロバイダの作成

以下のコマンドでサービスプロバイダを作成します。

> php artisan make:provider SlackServiceProvider

app/Providers/Slack/SlackServiceProvider.phpというファイルが作成されますので、registerの中にキーとサービスをバインドするための記述を追加します。

app/Providers/Slack/SlackServiceProvider.php
<?php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class SlackServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind(
            'slack',
            'App\Services\Slack\SlackService'
        );
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}

サービスプロバイダとエイリアスを追記する

app/config/app.php
    'providers' => [
        (省略)
        App\Providers\SlackServiceProvider::class,
        (省略)
    ],
    'aliases' => [
        (省略)
        'Slack' => App\Services\Slack\SlackFacade::class,
        (省略)
    ],

通知処理

以下のように記述すればどこででもSlackへの通知が可能です。

\Slack::send('Hello World!');

参考にさせていただいたサイト

https://readouble.com/laravel/5.8/ja/notifications.html
https://www.ritolab.com/entry/110
https://larapet.hinaloe.net/2017/04/09/slack-notification/
https://qiita.com/nekyo/items/95ede7f8d5c5bd3357fb

freeneer
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away