PHPマイクロフレームワークSlimで作るTwilioコールセンターシステム(4.コールフロー(1.コールフロー起動まで編))

PHPマイクロフレームワークSlimで作るTwilioコールセンターシステム
1.アプリ紹介編
2.環境設定
 1.ライブラリインストール編
 2.Apache mod_rewrite設定編
 3.CSSとJavaScript編
3.“Twilioコールフローフレームワーク”編

の続きです。

コールフローを作ります。
Twilioからリクエストされることで、コールフローが起動します。以下のような流れ。

  1. お客様が050番号に電話する。
  2. Twilioによって、050番号の「音声通話」に登録されているRequest URLが、サーバーアプリ(Runa-CCA)にリクエストされる。
  3. Runa-CCAでリクエストを処理する。

「050番号の「音声通話」に登録されているRequest URL」ですが、Runa-CCAでは新サービス・製品窓口のコールフロー(NewService)をサンプルとして用意していて、「http://ドメイン名/runa-cca/twilio/callflow/newservice/main」になります。このURLは、Apache mod_rewrite設定の通り、index.phpで処理されることになります。

“Twilioコールフローフレームワーク”編」に書いた通り、index.phpは、Slimのオブジェクトを作って、ルータ(\Runa_CCA\Route.php)に処理を渡す役割を負います。具体的にはindex.phpの中の、

\Runa_CCA\Route::registration($app);

によって、ルータに処理が渡されます。
なお、index.phpでsession_start()とかしているのはWebアプリケーション機能用でして、コールフローのみであれば不要になります。

ルータ(\Runa_CCA\Route.php)のregistrationメソッドには以下のように書いてあります。
Request URLに従って、コントローラ(\Runa_CCA\Controller\CallFlow\NewService.php)のstart(“main”)メソッドを呼びます。
GETとPOSTの両方に対応するようにしているのはテスト用です。テスト終わったらPOSTで統一するべきだと思います。
main以外は別途Twilioからリクエストされるものになります。

        // CallFlow
        // "NewService"
        $app->map ('/twilio/callflow/newservice/main', 
                    function () {
                        \Runa_CCA\Controller\CallFlow\NewService::start("main");
                    })->via('GET', 'POST');
        $app->map ('/twilio/callflow/newservice/wait', 
                    function () {
                        \Runa_CCA\Controller\CallFlow\NewService::start("wait");
                    })->via('GET', 'POST');
        $app->map ('/twilio/callflow/newservice/info', 
                    function () {
                        \Runa_CCA\Controller\CallFlow\NewService::start("info");
                    })->via('GET', 'POST');
        $app->map ('/twilio/callflow/newservice/enqueaction', 
                    function () {
                        \Runa_CCA\Controller\CallFlow\NewService::start("enqueaction");
                    })->via('GET', 'POST');
        $app->map ('/twilio/callflow/newservice/guidance', 
                    function () {
                        \Runa_CCA\Controller\CallFlow\NewService::start("guidance");
                    })->via('GET', 'POST');
        $app->map ('/twilio/callflow/newservice/statuscallback', 
                    function () {
                        \Runa_CCA\Controller\CallFlow\NewService::start("statuscallback");
                    })->via('GET', 'POST');

コントローラ(\Runa_CCA\Controller\CallFlow\NewService.php)では、まず、Slimのインスタンスを取得し、Requestで送られてきたパラメータを全て取得します。

        // Get Parameters
        $app = \Slim\Slim::getInstance();
        $params = $app->request->params();

続いて、RequestがTwilioから来たものなのかどうかを検証します。
検証処理については、別記事「Twilioにおける認証(TwilioからのRequestデータ検証)について」に記載の通りです。

if((new \Runa_CCA\Model\Twilio())->validateTwilioRequest($app, $params)){

Trueが返ってきたら、Switch文で判定して、Modelクラスを呼びます。ここからがコールフローの本体です。コールフローでの処理が終わって、ModelクラスからTwiMLオブジェクト(\Services_Twilio_Twimlオブジェクト)が返ってきたら、それをTwiMLを作るVewクラスに渡します。

                    // Go to Main CallFlow
                    case "main" :
                    
                        $response = (new \Runa_CCA\Model\CallFlow\NewService\Main())->main($params);
                        (new \Runa_CCA\View\Twiml($app))->createTwiml($response);
                        break;

実は、ここのエラー処理には問題ありなのです。
Webアプリケーション機能とエラー処理を共有しておりまして、日本語でエラーページを返す仕様にしています。
しかしそうすると、Twilioホームページでログ確認するときに文字化けしてしまうんです。コールフロー用のエラーページを英語で作らないといけません。この点は別記事に書いておきました。
別途修正予定です。

TwiMLを作るTwiMLクラスですが、以下のようにTemplateを呼び出し、Twigでレンダリングさせます。

class Twiml {

    public function __construct($app){
        
        $this->app = $app;
        
    }

    public function createTwiml($twilioObj){
        
        $this->app->render(
            'TwiML/twiml.twig', 
            [
                'twiml'         => $twilioObj,
            ]
        ); 
        
    } 
}

Twigを使用している場合は、

{% autoescape true %}
ほげほげ
{% endautoescape %}

でエスケープされます。
しかし、TwiMLを出力させるので、オートエスケープをオンにしてしまうと、TwiMLのタグがすべてエスケープされてしまいます。そのため、

{% autoescape false %}
{{ twiml }}
{% endautoescape %}

として、エスケープしないようにしています。

しかし、例えばお客様から電話機で番号入力させて、それをTwilioで読み上げたりするような場合は、エスケープする必要があります。
twilio-phpで自動でエスケープしてくれるのですが、\Services_Twilio_Twimlクラスの__callマジックメソッドのコメントを読むと、「経験ない開発者の中にはアンパサンドをエスケープしない人がいる」といった記載がありました。twilio-phpには頼らずエスケープ処理せい、ということなんでしょう。

Runa-CCAでは、\Base\Conf内にエスケープするメソッドを用意しておりまして、TwiMLを作成するときにはそのメソッドを実行してエスケープするようにしています。

次回はコールフローの中身を見ていく予定です。

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.