This is a guest post from Mark Headd, a voice application developer who was one of the first 10,000 users of our platform, and was originally published on his Vox Populi blog on May 6, 2008.
A few weeks ago, I posted about accessing web services from CCXML using PHP. This post will demonstrate how to do the same thing, only from VoiceXML. We’ll be using Voxeo Prophecy and PHP for this example. We’ll also be referring to the GreenPhone project — available free for download — for the sample code.
Using the greenSoapClient Class
In the last post on this topic, I demonstrated how to use a simple PHP class as a way to access multiple SOAP-based web services from CCXML. This class forms the basis of our method for accessing web services from VoiceXML as well. However, in this instance, instead of using the CCXML <send/> element, we’ll use a VoiceXML subdialog.
Subdialogs in VoiceXML are typically used to create reusable dialog components for capturing common types of input, like a series of digits (e.g., credit card numbers, account numbers, etc). They can also be used to compartmentalize complex interactions with a caller and provide a simple interface for accessing results. By way of example, this is how the OSDMs from Nuance work, as well as the Targus service from Voxeo. We’ll borrow this approach to access a web service from StrikeIron that will send the details of an E85 or bio-diesel station to a cell phone via SMS.
Setting up our Subdialog
In order to send an SMS message with details on an E85 or bio-diesel station, we’ll need 2 things; the station details, and a cell phone number to send it to.
In order to send the details on a station from VoiceXML to PHP, we’ll pack it up in a pipe-delimited string called “detailsToSend” (I won’t go into too much detail about how this is done in this post — to learn more, refer to the GreenPhone Project code). The cell phone number we are sending to is obtained from the caller ID of the calling party, stored in a variable named “ani”. Details on how to access caller ID are given in a previous post.
Our subdialog call will look like this:
<form id="sendDetails"> <catch event="error.badfetch"> <prompt> There was a problem sending the station details to your phone. <break strength="weak"/> </prompt> <goto next="#goodbye"/> </catch> <subdialog name="sendSMS" src="../php/sendStationDetails.php" namelist="ani detailsToSend"> <prompt> Sending the station details to <say-as interpret-as="telephone"><value expr="ani"/></say-as> </prompt> <filled> <if cond="sendSMS.result==0"> <prompt>Your message has been sent.<break strength="weak"/></prompt> <else/> <prompt> There was a problem sending the station details to your phone. <break strength="weak"/> </prompt> </if> <goto next="#goodbye"/> </filled> </subdialog> </form>
We use the attributes on the <subdialog> element to give our subdialog a name (which we’ll use to access the results sent back from PHP), to specify where to POST our variables to and also to specify which variables to POST.
You’ll also notice that we have set up a handler here for an “error.badfetch” event. This is a good habit to get into whenever you set up a request to an external resource (like a PHP script). If the script isn’t there or has problems, an “error.badfetch” event will get returned and unless you specified a handler for this event, your day will not end well.
<if cond=”sendSMS.result==0″> … code logic goes here … </if>
With this in mind, our PHP script needs to send back a variable called “result”. How do we do this? Lets take a look at the PHP script:
A Simple Subdialog using PHP
The subdialog that we want to render is extremely simple — we only need to render enough VoiceXML to declare a variable called “result” and return it to the parent dialog. We’ll do this after we make our web service call to send the SMS message.
There are two pieces of information returned from the StrikeIron web service that we are interested in; a string that holds the response message from the service (i.e., “success”, “failure”, etc.) and a number indicating the outcome of the web service call.
We’ll take these two bits if information and assign them to PHP variables:
$result = $xml->soapHeader->ResponseInfo->ResponseCode; $message = $xml->soapHeader->ResponseInfo->Response;
Now, we want to write out these variables in a simple VoiceXML subdialog:
<?xml version="1.0" encoding="utf-8"?> <vxml version="2.1" xmlns="http://www.w3.org/2001/vxml"> <form id="F_1"> <log>*** SMS response message was: <?php echo $message; ?>. ***</log> <block> <var name="result" expr="<?php echo $result ?>"/> <return namelist="result"/> </block> </form> </vxml>
As discussed above, this creates just enough VoiceXML to instantiate a variable and return it to the parent dialog. For good measure, we’ll write out the web service string (contained in the PHP variable $message) as a log statement, in case it contains information we want to look at later.
Why This Approach?
Using this technique for accessing web services from VoiceXML provides a couple of advantages. First, it allows us to completely separate the presentation layer (the VoiceXML) from the logic used to invoke the web service. This is a fairly standard design practice that makes creating the dialog much easier for a developer that does not necessarily know a whole lot about web services. With this approach, they don’t really need to — they only need to know that the subdialog call will return a variable called “result” whose value can be inspected to determine what to do next.
Additionally, because the parent dialog is just static VoiceXML it may be possible to cache it. Since the parent dialog isn’t dynamic, it can be cached for fast access, while the subdialog — which must be dynamic — is the only component sent from the web server to the VoiceXML platform each time a caller accesses the application. Careful design can yield additional caching opportunities that can make your applications more efficient and less bandwidth intensive.
In the next post, we’ll explore one additional method for accessing web service from VoiceXML. Stay tuned…