LaravelとTwilioでSMSポータルを作る方法

March 22, 2019
執筆者
Brian Iyoha
寄稿者
Twilio の寄稿者によって表明された意見は彼ら自身のものです
レビュー担当者

LaravelとTwilioでSMSポータルを作る方法

この記事はBrian Iyohaこちらで公開した記事(英語)を日本語化したものです。

アプリケーションのワークフローにおいて、重要な情報をユーザーに渡すことが必要になる場合があります。Webテクノロジーが進歩したおかげで、この処理はプッシュ通知で簡単にできます。ただし、このようなサービスの多くは、ユーザーがインターネットに接続していることが必要です。残念なことに、実際にはすべてのユーザーが常にインターネットに接続できるわけではありません。

この問題は、インターネットに依存しない通知システムを使用することにより解決できます。

このチュートリアルでは、TwilioのProgrammable SMSとLaravelを使用してSMS通知ポータル(管理画面)を作成する方法をご紹介します。

目標

このチュートリアルを最後まで進めると、LaravelとTwilioを使って以下のようなSMSポータルの作成方法を学べます。

ポータル完成

このポータルでは、ダッシュボードを介してSMSでユーザーに通知ができます。

必要条件

このチュートリアルを進めるには、以下の項目が必要です。

  • Laravelの基礎知識。
  • ローカルマシンにインストールされたLaravel
  • グローバルにインストールされたComposer
  • ローカルマシンに設定されたMySQL
  • Twilioのアカウント。Twilioホームページをブラウザで開き、[今すぐ無料サインアップ]ボタンをクリックするか、Twilioアカウントの作成リンクからサインアップします。このリンクを使用するとアカウントのアップグレード時に$10(米国ドル)相当分のクレジットが追加で付与されます。

プロジェクトを設定する

まず、LaravelインストーラーかComposerを使用し、新しいLaravelプロジェクトを作成します。このチュートリアルでは、Laravelインストーラーを利用します。Laravelがインストールされていない場合は、Laravel公式ドキュメントでインストール方法を確認してください。

新規にLaravelプロジェクトを生成するには、以下のコマンドをターミナルで実行します。

$ laravel new sms-portal

sms-portalに移動し、Composerを介してTwilio SDKをインストールします。

$ cd sms-portal
$ composer require twilio/sdk

ComposerがPCにインストールされていない場合は、こちらの手順に従い、インストールしてください。

Twilio PHP SDKをインストールします。

次に、Twilio認証情報をTwilioダッシュボードから取得します。ダッシュボードに移動し、Account SIDとAuth Tokenを確認します。

アカウント情報

SMSの送信に使用する電話番号を購入します。

TwilioコンソールのBuy a Numberにアクセスします。

Countryで、電話番号が属する国を選択します。現在、TwilioではSMS送信機能付きの日本の電話番号は販売しておりませんので、米国等を選択してください。

電話番号設定画面

各国の電話番号で使用できる機能について詳しくは、TwilioヘルプセンターのTwilioの国際電話番号の利用と機能(英語)を参照してください。

CapabilitiesSMSがチェックされていることを確認してください。

購入した電話番号を記録しておきます。

次に、Twilio認証情報を使用し、.envファイルを更新します。プロジェクトのルートディレクトリにある.envを開き、次の値を追加します。

TWILIO_SID={あなたのAccount SID}
TWILIO_AUTH_TOKEN={あなたのAuth Token}
TWILIO_NUMBER={E.164*形式のTwilioの電話番号}

*E.164形式について詳しくは、Twilioヘルプセンターの「Twilioがサポートする国際電話番号のフォーマット(E164) とは?」を参照してください。

データベースを設定する

Twilio SDKがインストールされた基本的なLaravelプロジェクトが生成されました。次に、データベースを作成します。phpMyAdminなどのGUIアプリケーションを使用してデータベースを管理している場合は、それを使用してsms_portalという名前のデータベースを作成し、このセクションをスキップしてください。

同等のアプリケーションやツールがなく、MySQLがインストールされていない場合は、プラットフォームの公式サイトからMySQLをインストールします。

ターミナルを起動し、以下のコマンドを実行し、MySQLにログインします。

$ mysql -u {あなたのユーザー名}

MySQLインスタンスのパスワードがある場合は、-pフラグを追加します。

ログイン後、次のコマンドを実行し、新しいデータベースを作成します。

mysql> create database sms_portal;
mysql> exit;

プロジェクトフォルダのルートにある.envファイルのデータベース設定を適宜変更します。

DB_DATABASE=sms_portal
DB_USERNAME=root
DB_PASSWORD=

移行を作成する

データベースが作成されたため、次はデータベース移行を作成します。データベース移行は、以下のコマンドをターミナルで実行するだけで作成できます。

$ php artisan make:migration create_users_phone_number_table

コマンドを実行すると、{現在のタイムスタンプ}_create_users_phone_number_table移行ファイルが/database/migrationsディレクトリに生成されます。

プロジェクトフォルダをIDEまたはテキストエディタで開くと、必要に応じて変更できるようになります。作成した移行ファイルを開きます。内容は次のようになります。

エディタ画面

phone_number列をテーブルに追加する必要があります。これを行うには、up()メソッドを次のように編集します。

public function up() {
    Schema::create('users_phone_number', function (Blueprint $table) {
        $table->increments('id');
        $table->string('phone_number'); 
        $table->timestamps();
    });
}

ファイルを移行できるようになりました。次のコマンドをターミナルで実行するだけで移行できます。

$ php artisan migrate

出力結果は次のようになります。

出力結果

ユーザーインターフェイスを作成する

この時点において、プロジェクトのセットアップが完了しています。次に、データをデータベースに追加し、SMS通知を送信するためのシンプルなユーザーインターフェースを構築します。

/resources/views/welcome.blade.phpを開き、<head>ブロックを次のように変更します。

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>SMS Portal With Twilio</title>
    <!-- Bootstrap styles CDN -->
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
</head>

ページの初期スタイルを削除し、簡単にスタイル設定できるようBootstrapCDNを使用し、Bootstrapを追加しました。次に、2つのフォームをページに作成します。フォームのうち、1つはユーザーの電話番号を登録するため、もう1つは特定のユーザーにカスタム通知メッセージを送信するためのものです。bodyブロックを次のように変更します。

<body>
    <div class="container">
        <div class="jumbotron">
            <div class="row">
                <div class="col">
                    <div class="card">
                        <div class="card-header">
                            Add Phone Number
                        </div>
                        <div class="card-body">
                            <form>
                                <div class="form-group">
                                    <label>Enter Phone Number</label>
            <input type="tel" class="form-control" placeholder="Enter Phone Number">
                                </div>
                <button type="submit" class="btn btn-primary">Register User</button>
                            </form>
                        </div>
                    </div>
                </div>
                <div class="col">
                    <div class="card">
                        <div class="card-header">
                            Send SMS message
                        </div>
                        <div class="card-body">
                            <form>
                                <div class="form-group">
                                    <label>Select users to notify</label>
                                    <select multiple class="form-control">
                                        @foreach ($users as $user)
                                        <option>{{$user->phone_number}}</option>
                                        @endforeach
                                    </select>
                                </div>
                                <div class="form-group">
                                    <label>Notification Message</label>
                                <textarea class="form-control" rows="3"></textarea>
                                </div>
            <button type="submit" class="btn btn-primary">Send Notification</button>
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>

上記のコードのうち、次の部分に注目します。

      <select multiple class="form-control">
            @foreach ($users as $user)
              <option>{{$user->phone_number}}</option>
           @endforeach
      </select>

このスニペットは、このビューで返される利用可能なユーザーの電話番号を保存する任意フィールドを生成します。この機能は後ほど実装します。

ユーザーの電話番号を保存する

まず、クエリを実行し、データベースへのレコードの追加に使用するモデルを作成します。プロジェクトディレクトリでターミナルを起動し、次のコマンドを実行します。

$ php artisan make:model UsersPhoneNumber

app/UsersPhoneNumber.phpにある作成したファイルを開き、次のコードを追加します。

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;

class UsersPhoneNumber extends Model
{
    protected $table= "users_phone_number";
    protected $fillable = [
        'phone_number'
    ];
}

ここでは、次の点に注意してください。

  • protected $table= “users_phone_number”;を追加するということは、Eloquentにテーブル名の使用を指示するということです。テーブル名の使用を指定しない場合は、クラス名の複数形がテーブル名として使用されます。
  • protected $fillableを追加すると、Eloquentにフィールドの一括割り当てを可能にするよう指示します。詳しくは、Laravel公式ドキュメントを参照してください。

次に、各リクエストルートに必要なロジックを実装するコントローラーを作成します。再度、ターミナルを起動し、次のコマンドを実行します。

$ php artisan make:controller HomeController

その結果、次のような内容のコントローラーファイルがapp/Http/Controllers/HomeController.phpに生成されます。

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HomeController extends Controller
{
    //
}

電話番号の保存メソッドを作成する

リクエスト本文から渡されたデータを使い、新しいUsersPhoneNumberモデルをインスタンス化する関数を作成します。

<?php
  
/**
* Store a new user phone number.
*
* @param  Request  $request
* @return Response
*/
public function storePhoneNumber(Request $request)
{
    //run validation on data sent in
    $validatedData = $request->validate([
        'phone_number' => 'required|unique:users_phone_number|numeric'
    ]);
    $user_phone_number_model = new UsersPhoneNumber($request->all());
    $user_phone_number_model->save();
    return back()->with(['success'=>"{$request->phone_number} registered"]);
}

上記のコードでは、$request本文から渡されたデータで検証を実行してから、UsersPhoneNumberの新しいインスタンスを作成しています。ユーザーの電話番号を保存後、ウェルカムページに戻り、成功メッセージがセッションにフラッシュされます。

ユーザーの電話番号をビューに返す

次に、登録された電話番号のデータをビューに返す必要があります。HomeControllerにて、users_phone_numberテーブルのクエリを実行し、クエリ結果をビューに表示するシンプルな関数を記述します。

<?php

/**
* Show the forms with the user's phone number details.
*
* @return Response
*/
public function show()
{
    $users = UsersPhoneNumber::all(); //query db with model
    return view('welcome', compact("users")); //return view with data
}

compact()は、変数名と値の配列を作成できるPHP関数です。

Twilio Programmable SMSによるメッセージの送信

次のステップでは、TwilioのProgrammable SMSライブラリを使用したSMSの送信を実装します。HomeControllerにて、メッセージ送信のhelper関数として機能するprivate関数を作成します。

<?php
  
/**
* Sends sms to user using Twilio's programmable sms client
* @param String $message Body of sms
* @param Number $recipients string or array of phone number of recepient
*/
private function sendMessage($message, $recipients)
{
    $account_sid = getenv("TWILIO_SID");
    $auth_token = getenv("TWILIO_AUTH_TOKEN");
    $twilio_number = getenv("TWILIO_NUMBER");
    $client = new Client($account_sid, $auth_token);
    $client->messages->create($recipients, 
            ['from' => $twilio_number, 'body' => $message] );
}

この関数は、$message$recipientsの2つのパラメーターを受け取ります。次に、ビルトインのPHP getenv()関数を使用し、保存されているTwilio認証情報を環境変数から取得します。その後、新しいTwilioクライアントを、認証情報を使いインスタンス化します。以下の呼び出しにより、SMSを送信できるようになります。

$client->messages->create($recipients, [
    'from' => $twilio_number, 
    'body' => $message
]);

Twilioのmessages->create()関数は、2つのパラメーターを受け取ります。1つはメッセージの受信者、もう1つはfrombodyのプロパティによる配列です。from有効なTwilio電話番号です。

登録時にユーザー通知を送信する

sendMessage()関数が完成しました。この関数を使用し、メッセージをユーザーに送信します。次に、ユーザー登録が成功したことをユーザーに通知するためにstorePhoneNumber()関数を更新します。

storePhoneNumber()関数を次のように変更します。

<?php
  
/**
* Store a new user phone number.
*
* @param  Request  $request
* @return Response
*/
public function storePhoneNumber(Request $request)
{
    //run validation on data sent in
    $validatedData = $request->validate([
        'phone_number' => 'required|unique:users_phone_number|numeric',
    ]);
    $user_phone_number_model = new UsersPhoneNumber($request->all());
    $user_phone_number_model->save();
    $this->sendMessage('User registration successful!!', $request->phone_number);
    return back()->with(['success' => "{$request->phone_number} registered"]);
}

これで、ユーザーの電話番号がデータベースに追加されるたびに、実行されたアクションについて通知するメッセージをユーザーに送信できるようになりました。

カスタム通知を送信する

次に、特定のユーザーにカスタムメッセージを送信するための関数を記述します。HomeControllerに次のコードを追加します。

<?php 
  
/**
* Send message to a selected users
*/
public function sendCustomMessage(Request $request)
{
    $validatedData = $request->validate([
        'users' => 'required|array',
        'body' => 'required',
    ]);
    $recipients = $validatedData["users"];
    // iterate over the array of recipients and send a twilio request for each
    foreach ($recipients as $recipient) {
        $this->sendMessage($validatedData["body"], $recipient);
    }
    return back()->with(['success' => "Messages on their way!"]);
}

この関数は、検証済みのデータを$request本文から$validatedData変数に渡します。その結果、$validatedData[users]の配列を反復処理し、$validatedData[“body”]から受信したメッセージを各ユーザーに送信できます。その後、ウェルカムページにリダイレクトし、セッションにメッセージがフラッシュされます。

ルートを作成する

コントローラー関数が正常に作成されました。次に、ルートをアプリケーションに追加しましょう。routes/web.phpを開き、次のように変更します。

<?php
Route::get('/', 'HomeController@show');
Route::post('/', 'HomeController@storePhoneNumber');
Route::post('/custom', 'HomeController@sendCustomMessage');

フォームフィールドをルートで更新する

次に、resources/views/welcome.blade.phpに移動し、各フォームフィールドを次のように変更します。

電話番号を登録するフォーム:

// add the method attribute to the Register User form
// also add the name attributes to the input field 
<form method="POST">
    @csrf
    <div class="form-group">
        <label>Enter Phone Number</label>
        <input type="tel" class="form-control" name="phone_number" placeholder="Enter Phone Number">
    </div>
    <button type="submit" class="btn btn-primary">Register User</button>  
</form>

特定のユーザーにカスタム通知メッセージを送信するためのフォーム:

// add the method and action attributes to the Send custom message form
// also add the name attributes to the input fields 
<form method="POST" action="/custom">
    @csrf
    <div class="form-group">
        <label>Select users to notify</label>
        <select name="users[]" multiple class="form-control">
            @foreach ($users as $user)
            <option>{{$user->phone_number}}</option>
            @endforeach
        </select>
    </div>
    <div class="form-group">
        <label>Notification Message</label>
        <textarea name="body" class="form-control" rows="3"></textarea>
    </div>
    <button type="submit" class="btn btn-primary">Send Notification</button>
</form>

コードをテストする

これまでに作成したすべてのコードを1つにまとめましょう。この時点において、HomeController.phpは次のようになります。

<?php
namespace App\Http\Controllers;

use App\UsersPhoneNumber;
use Illuminate\Http\Request;
use Twilio\Rest\Client;

class HomeController extends Controller
{
    /**
    * Show the forms with users phone number details.
    *
    * @return Response
    */
    public function show()
    {
        $users = UsersPhoneNumber::all();
        return view('welcome', compact("users"));
    }
    /**
    * Store a new user phone number.
    *
    * @param  Request  $request
    * @return Response
    */
    public function storePhoneNumber(Request $request)
    {
        //run validation on data sent in
        $validatedData = $request->validate([
            'phone_number' => 'required|unique:users_phone_number|numeric',
        ]);
        $user_phone_number_model = new UsersPhoneNumber($request->all());
        $user_phone_number_model->save();
        $this->sendMessage('User registration successful!!', $request->phone_number);
        return back()->with(['success' => "{$request->phone_number} registered"]);
    }
    /**
    * Send message to a selected users
    */
    public function sendCustomMessage(Request $request)
    {
        $validatedData = $request->validate([
            'users' => 'required|array',
            'body' => 'required',
        ]);
        $recipients = $validatedData["users"];
        // iterate over the array of recipients and send a twilio request for each
        foreach ($recipients as $recipient) {
            $this->sendMessage($validatedData["body"], $recipient);
        }
        return back()->with(['success' => "Messages on their way!"]);
    }
    /**
    * Sends sms to user using Twilio's programmable sms client
    * @param String $message Body of sms
    * @param Number $recipients Number of recipient
    */
    private function sendMessage($message, $recipients)
    {
        $account_sid = getenv("TWILIO_SID");
        $auth_token = getenv("TWILIO_AUTH_TOKEN");
        $twilio_number = getenv("TWILIO_NUMBER");
        $client = new Client($account_sid, $auth_token);
        $client->messages->create($recipients, ['from' => $twilio_number, 'body' => $message]);
    }
}

welcome.blade.phpは、次のようになります。

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>SMS Portal With Twilio</title>
    <!-- Styles -->
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS"
        crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <div class="jumbotron">
            @if (session('success'))
            <div class="alert alert-success">
                {{ session('success') }}
            </div>
            @endif
            @if ($errors->any())
            <div class="alert alert-danger">
                <ul>
                    @foreach ($errors->all() as $error)
                    <li>{{ $error }}</li>
                    @endforeach
                </ul>
            </div>
            @endif
            <div class="row">
                <div class="col">
                    <div class="card">
                        <div class="card-header">
                            Add Phone Number
                        </div>
                        <div class="card-body">
                            <form method="POST">
                                @csrf
                                <div class="form-group">
                                    <label>Enter Phone Number</label>
                                    <input type="tel" class="form-control" name="phone_number" placeholder="Enter Phone Number">
                                </div>
                                <button type="submit" class="btn btn-primary">Register User</button>
                            </form>
                        </div>
                    </div>
                </div>
                <div class="col">
                    <div class="card">
                        <div class="card-header">
                            Send SMS message
                        </div>
                        <div class="card-body">
                            <form method="POST" action="/custom">
                                @csrf
                                <div class="form-group">
                                    <label>Select users to notify</label>
                                    <select name="users[]" multiple class="form-control">
                                        @foreach ($users as $user)
                                        <option>{{$user->phone_number}}</option>
                                        @endforeach
                                    </select>
                                </div>
                                <div class="form-group">
                                    <label>Notification Message</label>
                                    <textarea name="body" class="form-control" rows="3"></textarea>
                                </div>
                                <button type="submit" class="btn btn-primary">Send Notification</button>
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

コードに差異がなければ、次に進みます。

コードに差異がある場合は、適宜修正してください。

アプリケーションを実行する

ターミナルを開き、プロジェクトディレクトリに移動し、次のコマンドを実行します。

$ php artisan serve

Laravelアプリケーションは、ローカルホストポート(通常は8000)にて実行されます。ブラウザにおいてコマンドの実行後に表示されるローカルホストリンクを開きます。ページは次のように表示されます。

ポータル画面

次に進み、新しい電話番号を登録します。すべての処理が正常に完了すると、まもなく登録について通知するSMSが届きます。

SMSメッセージ

フィールドからユーザーを選択し、選択したユーザーに送信するテキストを入力すると、カスタム通知の送信もテストできます。

完了後、Send Notificationボタンをクリックすると、カスタム通知SMSが届きます。

ポータル完成

まとめ

チュートリアルが完了しました。Twilio Programmable SMSをLaravelアプリケーションに統合し、SMSを介して通知メッセージを送信する方法をご紹介しました。このチュートリアルの全ソースコードは、GitHubにて確認できます。

次のステップとして、ユーザーが受け取ったSMSに対して何らかのアクションをとった場合に、特定の処理を実行してみてはいかがでしょうか?

このチュートリアルに関する質問はお気軽にお寄せください。連絡先は次のとおりです。