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の中の、
\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を作成するときにはそのメソッドを実行してエスケープするようにしています。
次回はコールフローの中身を見ていく予定です。