Laravel でSMSに通知する
こんにちはみなさん。
プロダクト触っている身としては、ユーザにどうやって通知して、プロダクトをより使ってもらうかって、結構重要です。通知の手段としてはメールとかSlackとかあるわけですが、よりカジュアルで通じやすい手段として、SMSを使うのもあります。
でも、使ったことないものを使うのはハードルが高く、プロダクトに入れるにも勇気がいるものです。
このハードルを下げるのが、素振り、ということで素振りしていきましょう。
今回はPHPerらしく、ちゃんとPHP, Laravelの話です。
マニュアルにあるじゃん!て思った人はそっち見てもいいよ。
環境
ここは動作環境の用意をしている箇所なので、もうあるよって人はNEXMOの項目まで飛ばしてください。
動作環境はこんな感じでいつものようにコンテナ用意します。
FROM php:8
RUN apt-get update && apt-get install -y git unzip libonig-dev libzip-dev && \
docker-php-ext-install mbstring pdo pdo_mysql zip
COPY /usr/bin/composer /usr/bin/composer
ちょっとDB使うのでdocker-compose.yml は以下のように定義します
version: "3"
services:
workspace:
build: workspace
command: sleep infinity
volumes:
- ../:/var/www/
environment:
- LANGUAGE=en_US.UTF-8
- LC_ALL=en_US.UTF-8
ports:
- 8888:8888
db:
image: mysql
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_USER=niisan
- MYSQL_DATABASE=niisan
- MYSQL_PASSWORD=secret
以降はコンテナ内部で実行していきます。
今回の主題はLaravelですので、さっそく適当にプロジェクト作ります。
composer create-project --prefer-dist laravel/laravel sample-sms
Vonage Communications APIsを使った通知
SMSの通知方法はマニュアルの以下の項目を見れば、大体 書いてあります。
微妙に変なところではまりやすいので注意してください。で、マニュアルサイトによると、NEXMOを使ってくれとありますが、現在は名前が変わってVonage Communications APIsになっています。
とりあえず、こいつを使えばSMS投げられるということです。
アカウントゲット
今回はフリーのアカウントをゲットしましょう。
のtry it free でアカウントを作成します。アカウントをゲットしたら以下のページにアクセスします。
ここでPHPのコードをコピーすると、IDとシークレットIDがクリップボードにコピーされます。$basic = new \Nexmo\Client\Credentials\Basic('*******', '*****************');
$client = new \Nexmo\Client($basic);
$message = $client->message()->send([
'to' => '111111111111111',
'from' => 'Vonage APIs',
'text' => 'Hello from Vonage SMS API'
]);
Basic
のコンストラクタの引数の一つめがIDで、二つめがシークレットIDですね。
とりあえず、.env
に突っ込みます。
NEXMO_KEY=********
NEXMO_SECRET=**************
通知作る
通知するためのパッケージ突っ込んでおきます。
composer require laravel/nexmo-notification-channel
データベースのユーザーのmigrationを更新して、電話番号入れておきます。
$table->string('email')->unique();
+ $table->string('phone_number')->nullable();
$table->timestamp('email_verified_at')->nullable();
データベースに適当に自分の電話番号突っ込んでおきます。
次に通知作ります。artisan make:notification
使ってもいいんですが、結構書き換え発生します。
Notifications/SmsNotification.php
<?php
namespace App\Notifications;
use Illuminate\Notifications\Messages\NexmoMessage;
use Illuminate\Notifications\Notification;
class SmsNotification extends Notification
{
/**
* 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 ['nexmo'];
}
/**
* Get the Nexmo / SMS representation of the notification.
*
* @param mixed $notifiable
* @return NexmoMessage
*/
public function toNexmo($notifiable)
{
return (new NexmoMessage)
->content('hello world!こんにちは!' . $notifiable->name);
}
}
こんな感じ。
最後にUser
モデルにどのフィールドでSMS送るか指定します。
Models/User.php
/**
* Route notifications for the Nexmo channel.
*
* @param \Illuminate\Notifications\Notification $notification
* @return string
*/
public function routeNotificationForNexmo($notification)
{
return $this->phone_number;
}
これがないと、一切送られません。
通知する
適当なコマンドで通知してみます。
Console/Commands/SmsNotify.php
<?php
namespace App\Console\Commands;
use App\Models\User;
use App\Notifications\SmsNotification;
use Illuminate\Console\Command;
class SmsNotify extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'notify:sms';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send SMS notification!';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$user = User::find(1);
$user->notify(new SmsNotification);
}
}
これでコマンドができたので、メッセージを送ります。
なお、フリープランだと送信元の番号はある程度ランダムになるっぽいです。
かけても意味ないとは思いますが、いたずらせんようにね。
php artisan notify:sms
さあこい!
送れた!!送れたけど...!
化けとるやないかーい!
というわけで、unicode文字列が化けます。
文字化けしない方法
unicode文字列を使用するためにはunicode
メソッドを使います。
Notifications/SmsNotification.php
/**
* Get the Nexmo / SMS representation of the notification.
*
* @param mixed $notifiable
* @return NexmoMessage
*/
public function toNexmo($notifiable)
{
return (new NexmoMessage)
->unicode()
->content('hello world!こんにちは!' . $notifiable->name);
}
あとは修正してみましょう。
php artisan notify:sms
今度こそ!
送れました!やったね!
注意事項
今回の記事の注意事項です。
日本からのSMSはお高い
VonageのAPIは従量課金制で、価格は
一見、SMSの料金は0.0062ユーロって書いてありますが、国際電話になるせいか、日本からの送信は0.07ユーロと、10倍以上になります。
気をつけましょう。
フリーアカウントの制限
フリーアカウントは以下の制限があります。
- APIの使用は利用価格にして2ユーロ分です。
- 送信元の電話番号は不定っぽい
- SMSのメッセージにわざわざ「テストだよ!」って入っている
というわけで、プロダクションでは有料アカウント使いましょうね。
まとめ
というわけで、SMSを使った通知をLaravelからやる方法を素振りしました。
いや、まあ、なんというか、何が微妙って、nexmo
って固定のサービス名入れている挙句、そのサービス名は別の新しいサービス名に移行した挙句、でも通知のチャンネル(via)に残っちゃっているというさま。
また、日本というお国の事情もあるのだろうけど、SESのメール一通の値段の700倍強のお値段と、ちょっと気軽に使うにはしり込みする設定にも、ちょっとびっくりです。
ただ、ユーザへのアプローチはメールよりも高いだろうし、使いどころを見極めて使っていきたいですね。
本日はこんなところです。
Discussion