PHPマイクロフレームワークSlimで作るTwilioコールセンターシステム
1.アプリ紹介編
2.環境設定
1.ライブラリインストール編
2.Apache mod_rewrite設定編
3.CSSとJavaScript編
3.“Twilioコールフローフレームワーク”編
の続きです。
コールフローを作ります。
Twilioからリクエストされることで、コールフローが起動します。以下のような流れ。
- お客様が050番号に電話する。
- Twilioによって、050番号の「音声通話」に登録されているRequest URLが、サーバーアプリ(Runa-CCA)にリクエストされる。
- 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の中の、
index.php1 | \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からリクエストされるものになります。
Route.php1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | $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で送られてきたパラメータを全て取得します。
NewService.php1 2 3 | $app = \Slim\Slim::getInstance();
$params = $app ->request->params();
|
続いて、RequestがTwilioから来たものなのかどうかを検証します。
検証処理については、別記事「Twilioにおける認証(TwilioからのRequestデータ検証)について」に記載の通りです。
NewService.php1 | if (( new \Runa_CCA\Model\Twilio())->validateTwilioRequest( $app , $params )){
|
Trueが返ってきたら、Switch文で判定して、Modelクラスを呼びます。ここからがコールフローの本体です。コールフローでの処理が終わって、ModelクラスからTwiMLオブジェクト(\Services_Twilio_Twimlオブジェクト)が返ってきたら、それをTwiMLを作るVewクラスに渡します。
NewService.php1 2 3 4 5 6 | 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でレンダリングさせます。
TwiML.php1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class Twiml {
public function __construct( $app ){
$this ->app = $app ;
}
public function createTwiml( $twilioObj ){
$this ->app->render(
'TwiML/twiml.twig' ,
[
'twiml' => $twilioObj ,
]
);
}
}
|
Twigを使用している場合は、
1 2 3 | {% autoescape true %}
ほげほげ
{% endautoescape %}
|
でエスケープされます。
しかし、TwiMLを出力させるので、オートエスケープをオンにしてしまうと、TwiMLのタグがすべてエスケープされてしまいます。そのため、
1 2 3 | {% autoescape false %}
{{ twiml }}
{% endautoescape %}
|
として、エスケープしないようにしています。
しかし、例えばお客様から電話機で番号入力させて、それをTwilioで読み上げたりするような場合は、エスケープする必要があります。
twilio-phpで自動でエスケープしてくれるのですが、\Services_Twilio_Twimlクラスの__callマジックメソッドのコメントを読むと、「経験ない開発者の中にはアンパサンドをエスケープしない人がいる」といった記載がありました。twilio-phpには頼らずエスケープ処理せい、ということなんでしょう。
Runa-CCAでは、\Base\Conf内にエスケープするメソッドを用意しておりまして、TwiMLを作成するときにはそのメソッドを実行してエスケープするようにしています。
次回はコールフローの中身を見ていく予定です。