Sample Webservice Source Code

© 2013 Plum Group, Inc. All rights reserved.

Description

The SOAP Webservice question type allows you to perform logic on survey responses while the respondent is taking the survey, and possibly integrate surveys with your own business processes or databases.

For a walk-through of how to use this question type, see Section 2.18 of the Survey Design tutorial.

When adding this question, the default value is a WSDL for a sample webservice that is compatible with our SOAP webservice type. This sample webservice only performs a simple logic test on the data receives: it responds with "accepted" if any of the responses provided were "yes"; otherwise it responds with "rejected". If the webservice responds with "accepted", and is called again during the course of a survey with answers that would warrant another "accepted" response, the webservice will instead say "accepted again"—this is to demonstrate that a webservice could possibly retain session state over multiple requests while taking a survey. (See the UPDATE note below for details.) The webservice you build can do possibly much more—store data into a database, retrieve data from a file, or send it via an email; it is completely up to how you build your SOAP service.

You should provide a WSDL for your SOAP service that specifies only one function named plumEval. This function will receive two arrays of strings: one with the text of each question on the current page, and the other with all the answers received on the current page. These arrays will be indexed in the same fashion, where each array's elements will be ordered so that the questions correspond with the answers. This function should return a string, which will be saved as the response for the question calling this webservice.

To ensure compatibility with the survey tool, your webservice function signature should read as follows:

plumEval($question_texts, $answers)

We are providing the code for our sample webservice so that you can have a reference implementation to build your own. If you are using PHP (version >5), the following code could easily serve as a template for your own webservice; just replace the contents of the plumEval() function with your own code. For other languages/architectures, the information on the contents of a compatible SOAP request and reply may be useful.

UPDATE (4/17/09): Our SOAP clients will now accept and store cookies you provide with HTTP Set-Cookie: headers. These cookies will be resent to you as specified by the cookie's domain and path. You can use the cookie capability to implement sessions, for instance if you want to associate data from requests across multiple pages. Cookies will be retained over the course of each individual's survey response session, whether over the phone or the web, and discarded upon completion/hangup. Each individual respondent will have their own cookie jar.

UPDATE (7/01/09): Our SOAP client will by default send along a cookie called either ani or ip with the ANI or IP address of the current respondent, respectively. You are free to override this cookie by sending back HTTP Set-Cookie: headers that overwrite or delete it. Additionally, an advanced question option for Advanced Skip Logic has been added, the details of which can be found in Section 6.4 of the Survey Design Tutorial.

UPDATE (1/25/11): We now have a SOAP Web Service tester that you can use to validate your web service against. For a link to this SOAP web service tester, see here.

UPDATE (11/15/13): Our SOAP client will now send answers for Comments questions in base64 encoded format.

Sample SOAP Request/Response

SOAP Request from a survey to the sample webservice at http://survey.plumvoice.com/ws/sample-webservice.php

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
  xmlns:ns1="urn:http://survey.plumvoice.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:ns2="urn:SampleWebservice" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:plumEval>
      <question_texts SOAP-ENC:arrayType="xsd:string[2]" xsi:type="ns2:ArrayOfstring">
        <item xsi:type="xsd:string">Question 1</item>
        <item xsi:type="xsd:string">Question 2</item>
      </question_texts>
      <answers SOAP-ENC:arrayType="xsd:string[2]" xsi:type="ns2:ArrayOfstring">
        <item xsi:type="xsd:string">Answer 1</item>
        <item xsi:type="xsd:string">Answer 2</item>
      </answers>
    </ns1:plumEval>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

SOAP Response from sample webservice back to the survey

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:ns1="http://survey.plumvoice.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
  SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:plumEvalResponse>
      <return xsi:type="xsd:string">rejected</return>
    </ns1:plumEvalResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Sample Webservice Source Code

sample-webservice.php:

<?php 
/************* 
* PLUM SURVEY SAMPLE WEBSERVICE 
* This webservice demonstrates how to make a SOAP service for use with a 
* 'SOAP webservice' question in a survey. 
* (c) 2008 Plum Voice 
*************/ 
$NAMESPACE = "http://survey.plumvoice.com"; 
$DEBUG = true; 

include_once('../lib/WSDL_Gen.php'); 
$WS_DOC_CSS = "css/ws_doc.css"; 
$DESCRIPTION = "An example of a webservice that could be used by a \"SOAP webservice\" question in a survey."; 

$LOGFILE = @fopen("/var/tmp/surveysamplewebservice.log", "a+"); 
function debuglog($str) { 
  global $LOGFILE, $DEBUG; 
  if ($LOGFILE && $DEBUG) { 
    fwrite($LOGFILE, $str); 
  } 
} 

class SampleWebservice extends Services_Webservice { 

  /**
   * The WSDL that you use should specify only one function named "plumEval".
   * This function will receive two arrays of strings: one with the 
   * text of each question, and the other with all the answers received 
   * on the current page. These arrays will be indexed in the same fashion, 
   * e.g., each array's elements will be ordered so that the questions 
   * correspond with the answers.  This function should return a string, 
   * which will be saved as the response for the question calling this 
   * webservice.  If there is a choice with skip logic that corresponds to 
   * this answer, it will be followed. ...
   * 
   * This sample webservice returns "accepted" if any of the submitted answers 
   * were "yes", and "rejected" otherwise.  To demonstrate that session 
   * cookies can be set and checked, after the webservice has "accepted" once, 
   * it will return "accepted again" for every future call within the same 
   * survey where any of the submitted answers were "yes".
   *
   * @param string[] $question_texts
   * @param string[] $answers
   * @return string
   **/
  function plumEval($question_texts, $answers) {
    foreach ($answers as $answer) {
      if ($answer == 'yes') {
        if ($_SESSION['accepted-once']=='yes') {
          return 'accepted again';
        }
        $_SESSION['accepted-once']='yes';
        return 'accepted';
      }
    }
    return 'rejected';
  }
  
}

$myService = new SampleWebservice($NAMESPACE, $DESCRIPTION, array('uri'=>$NAMESPACE, 'encoding'=>SOAP_ENCODED)); 

session_start();
$myService->handle(); 

if ($LOGFILE) { 
  fclose($LOGFILE); 
}

../lib/WSDL_Gen.php: (from PEAR)

<?php 

/** 
 * Easy Web Service (SOAP) creation 
 * 
 * PHP 5 
 * 
 * LICENSE: This source file is subject to version 3.0 of the PHP license 
 * that is available through the world-wide-web at the following URI: 
 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of 
 * the PHP License and are unable to obtain it through the web, please 
 * send a note to license@php.net so we can mail you a copy immediately. 
 * 
 * @category   Services 
 * @package    Webservice 
 * @author     Manfred Weber <weber@mayflower.de> 
 * @copyright  2005 The PHP Group 
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 
 * @version    CVS: $Id: samplewebservice.htm,v 1.26 2013/11/15 18:15:38 victor Exp $ 
 * @link       http://dschini.org/Services/ 
 */ 

// {{{ abstract class Services_WebService 

/** 
 * PEAR::Services_Webservice 
 * 
 * The PEAR::Services_WebService class creates web services from your classes 
 * 
 * @author  Manfred Weber <weber@mayflower.de> 
 * @package Webservices 
 * @version 
 */ 
abstract class Services_Webservice 
{ 
    /** 
     * Namespace of the webservice 
     * 
     * @var    string 
     * @access public 
     */ 
    public $namespace; 

    /** 
     * Description of the webservice 
     * 
     * @var    string 
     * @access public 
     */ 
    public $description; 

    /** 
     * Protocol of the webservice 
     * 
     * @var    string 
     * @access public 
     */ 
    public $protocol; 


    /** 
     * SOAP-server options of the webservice 
     * 
     * @var    array 
     * @access public 
     */ 
    public $soapServerOptions = array(); 

    /** 
     * SOAP schema related URIs 
     * 
     * @access private 
     */ 
    const SOAP_XML_SCHEMA_VERSION  = 'http://www.w3.org/2001/XMLSchema'; 
    const SOAP_XML_SCHEMA_INSTANCE = 'http://www.w3.org/2001/XMLSchema-instance'; 
    const SOAP_SCHEMA_ENCODING   = 'http://schemas.xmlsoap.org/soap/encoding/'; 
    const SOAP_XML_SCHEMA_MIME   = 'http://schemas.xmlsoap.org/wsdl/mime/'; 
    const SOAP_ENVELOP           = 'http://schemas.xmlsoap.org/soap/envelope/'; 
    const SCHEMA_SOAP_HTTP       = 'http://schemas.xmlsoap.org/soap/http'; 
    const SCHEMA_SOAP            = 'http://schemas.xmlsoap.org/wsdl/soap/'; 
    const SCHEMA_WSDL            = 'http://schemas.xmlsoap.org/wsdl/'; 
    const SCHEMA_WSDL_HTTP       = 'http://schemas.xmlsoap.org/wsdl/http/'; 
    const SCHEMA_DISCO           = 'http://schemas.xmlsoap.org/disco/'; 
    const SCHEMA_DISCO_SCL       = 'http://schemas.xmlsoap.org/disco/scl/'; 
    const SCHEMA_DISCO_SOAP      = 'http://schemas.xmlsoap.org/disco/soap/'; 

    /** 
     * Simple WSDL types 
     * 
     * @var    array 
     * @access private 
     */ 
    private $simpleTypes = array( 
        'string', 'int', 'float', 'bool', 'double', 'integer', 'boolean', 
        'varstring', 'varint', 'varfloat', 'varbool', 'vardouble', 
        'varinteger', 'varboolean'); 

    /** 
     * classes are parsed into struct 
     * 
     * @var    array 
     * @access private 
     */ 
    private $wsdlStruct; 

    /** 
     * disco dom root node 
     * the disco dom object 
     * 
     * @var    object 
     * @access private 
     */ 
    private $disco; 

    /** 
     * wsdl dom root node 
     * the wsdl dom object 
     * 
     * @var    object 
     * @access private 
     */ 
    private $wsdl; 

    /** 
     * wsdl-definitions dom node 
     * 
     * @var    object 
     * @access private 
     */ 
    private $wsdl_definitions; 

    /** 
     * Name of the class from which to create a webservice from 
     * 
     * @var    string 
     * @access private 
     */ 
    private $classname; 

    /** 
     * exclude these methods from webservice 
     * 
     * @var    array 
     * @access private 
     */ 
    private $preventMethods; 

    /** 
     * error namespace 
     * 
     * @var    bool 
     * @access private 
     */ 
    private $warningNamespace; 

    /** 
     * error description 
     * 
     * @var    bool 
     * @access private 
     */ 
    private $errorDescription; 

    /** 
     * constructor 
     * 
     * @var    string 
     * @var    string 
     * @var    array 
     * @access public 
     */ 
    public function __construct($namespace, $description, $options) 
    { 
        if (isset($namespace) && $namespace != '') { 
            $this->warningNamespace   = false; 
            $this->errorDescription = false; 
            //$namespace .= (substr($namespace, -1) == '/') ? '' : '/'; 
        } else { 
            $this->warningNamespace   = true; 
            $this->errorDescription = true; 
            $namespace = 'http://example.org/'; 
        } 
        $this->namespace   = $namespace; 
        $this->description = ($description != '') ? $description : 'my example service description'; 
        $this->soapServerOptions = (isset($options) && count($options) > 0) ? $options : array( 
            'uri' => $this->namespace, 
            'encoding' => SOAP_ENCODED); 
        $this->wsdlStruct = array(); 
        $this->preventMethods = array( 
            '__construct', 
            '__destruct', 
            'handle'); 
        $this->protocol = 'http'; 
    } 

    // }}} 
    // {{{ handle() 
    /** 
     * handle 
     * 
     * @access public 
     */ 
    public function handle() 
    { 
        switch (strtolower($_SERVER['QUERY_STRING'])){ 
            case 'wsdl': 
                $this->intoStruct(); 
                $this->handleWSDL(); 
                break; 
            case 'disco': 
                $this->intoStruct(); 
                $this->handleDISCO(); 
                break; 
            default: 
                $this->intoStruct(); 
                if (isset($_SERVER['HTTP_SOAPACTION'])) { 
                    $this->createServer(); 
                } else { 
                    $this->handleINFO(); 
                } 
                break; 
        } 
    } 

    // }}} 
    // {{{ createServer() 
    /** 
     * create the soap-server 
     * 
     * @access private 
     */ 
    private function createServer() 
    { 
        $server = new SoapServer(null, $this->soapServerOptions); 
        $server->SetClass($this->classname); 
        $server->handle(); 
    } 

    // }}} 
    // {{{ handleWSDL() 
    /** 
     * handle wsdl 
     * 
     * @access private 
     */ 
    private function handleWSDL() 
    { 
        header('Content-Type: text/xml'); 
        $this->wsdl = new DOMDocument('1.0' ,'utf-8'); 
        $this->createWSDL_definitions(); 
        $this->createWSDL_types(); 
        $this->createWSDL_messages(); 
        $this->createWSDL_portType(); 
        $this->createWSDL_binding(); 
        $this->createWSDL_service(); 
        echo $this->wsdl->saveXML(); 
    } 

    // }}} 
    // {{{ createDISCO() 
    /** 
     * handle disco 
     * 
     * @access private 
     */ 
    private function handleDISCO() 
    { 
        header('Content-Type: text/xml'); 
        $this->disco = new DOMDocument('1.0' ,'utf-8'); 
        $disco_discovery = $this->disco->createElement('discovery'); 
        $disco_discovery->setAttribute('xmlns:xsi', self::SOAP_XML_SCHEMA_INSTANCE); 
        $disco_discovery->setAttribute('xmlns:xsd', self::SOAP_XML_SCHEMA_VERSION);
        $disco_discovery->setAttribute('xmlns', self::SCHEMA_DISCO ); 
        $disco_contractref = $this->disco->createElement('contractRef'); 
        $urlBase = $this->protocol . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']; 
        $disco_contractref->setAttribute('ref', $urlBase . '?wsdl'); 
        $disco_contractref->setAttribute('docRef', $urlBase); 
        $disco_contractref->setAttribute('xmlns', self::SCHEMA_DISCO_SCL); 
        $disco_soap = $this->disco->createElement('soap'); 
        $disco_soap->setAttribute('address', $urlBase); 
        $disco_soap->setAttribute('xmlns:q1', $this->namespace); 
        $disco_soap->setAttribute('binding', 'q1:' . $this->classname); 
        $disco_soap->setAttribute('xmlns', self::SCHEMA_DISCO_SCL); 
        $disco_contractref->appendChild($disco_soap); 
        $disco_discovery->appendChild($disco_contractref); 
        $this->disco->appendChild($disco_discovery); 
        echo $this->disco->saveXML(); 
    } 

    // }}} 
    // {{{ handleINFO() 
    /** 
     * handle info-site 
     * 
     * @access private 
     */ 
    private function handleINFO() 
    { 
        global $WS_DOC_CSS; 
        header('Content-Type: text/html'); 

        echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html> 
<head> 
<title>' . $this->classname . ' WebService</title> 
<meta name="generator" content="PEAR::Services_Webservice" /> 
<style type="text/css">' 
. file_get_contents($WS_DOC_CSS) . 
'</style> 
</head> 
<body> 
<div id="header"> 
<h1>' . $this->classname . '</h1> 
<p>' . htmlspecialchars($this->description) . '</p> 
</div> 
<p>The following operations are supported. For a formal definition, please review the <a href="' . htmlentities($_SERVER['PHP_SELF']) . '?WSDL">Web Services 
Description Language</a>.</p> 
<ul>'; 

        foreach ($this->wsdlStruct[$this->classname]['method'] as $methodName => $method) { 
            $paramValue = array(); 
            foreach ($method['var'] AS $methodVars) { 
                if (isset($methodVars['param'])) { 
                    $paramValue[] = "<var class=\"parameter\">" . $methodVars['type'] 
                                     . str_repeat('[]', $methodVars['length']) . "</var> " . $methodVars['name']; 
                } 
            } 
            $returnValue = array(); 
            foreach ($method['var'] AS $methodVars) { 
                if (isset($methodVars['return'])) { 
                    $returnValue[] = $methodVars['type'] 
                                     . str_repeat('[]', $methodVars['length']); 
                } 
            } 
            echo sprintf('<li><samp><var class="returnedValue">%s</var> <b class="functionName">%s</b>( %s )</samp>%s</li>' 
                    , implode(',', $returnValue) 
                    , $methodName 
                    , implode(', ', $paramValue) 
                    , ((empty($method['description'])) ? '' : ('<br /><span class="description">' . htmlspecialchars($method['description']) . '</span>'))); 
        } 
/* 
        echo '</ul> 
<p><a href="' . htmlentities($_SERVER['PHP_SELF']) . '?DISCO">DISCO</a> makes it possible for clients to reflect against endpoints to discover services and their 
associated <acronym title="Web Service Description Language">WSDL</acronym> documents.</p>'; 
*/ 
        if ($this->warningNamespace == true 
            || $this->namespace == 'http://example.org/') { 
            echo ' 
<p class="warning"><strong>This web service is using http://example.org/ as its default namespace.<br /> 
Recommendation: Change the default namespace before the <acronym title="eXtensible Markup Language">XML</acronym> Web service is made public.</strong></p> 

<p>Each XML Web service needs a unique namespace in order for client applications to distinguish it from other services on the Web. http://example.org/ is available
for XML Web services that are under development, but published XML Web services should use a more permanent namespace.<br /> 
Your XML Web service should be identified by a namespace that you control. For example, you can use your company`s Internet domain name as part of the namespace.
Although many XML Web service namespaces look like <acronym title="Uniform Resource Locators">URLs</acronym>, they need not point to actual resources on the Web. 
(XML Web service namespaces are <acronym title="Uniform Resouce Identifiers">URIs</acronym>.)</p> 

<p>For more details on XML namespaces, see the <acronym title="World Wide Web Consortium">W3C</acronym> recommendation on
<a href="http://www.w3.org/TR/REC-xml-names/">Namespaces in XML</a>.<br /> 
For more details on <acronym title="Web Service Description Language">WSDL</acronym>, see the <a href="http://www.w3.org/TR/wsdl">WSDL Specification</a>.<br /> 
For more details on URIs, see <a href="http://www.ietf.org/rfc/rfc2396.txt"><acronym title="Request For Comment">RFC</acronym> 2396</a>.</p> 
<p><small>Powered by PEAR <a href="http://pear.php.net/">http://pear.php.net</a></small></p> 
</body> 
</html>'; 

        } 
    } 

    // }}} 
    // {{{ intoStruct() 
    /** 
     * parse classes into struct 
     * 
     * @access private 
     */ 
    protected function intoStruct() 
    { 
        $class = new ReflectionObject($this); 
        $this->classname = $class->getName(); 
        $this->classMethodsIntoStruct(); 
        $this->classStructDispatch(); 
    } 

    // }}} 
    // {{{ classStructDispatch() 
    /** 
     * dispatch types 
     * 
     * @access private 
     */ 
    protected function classStructDispatch() 
    { 
        foreach ($this->wsdlStruct[$this->classname]['method'] as $method) { 
            foreach ($method['var'] as $var){ 
                if (($var['class'] == 1 && $var['length'] == 0) 
                    || ($var['class'] == 1 && $var['length'] > 0)) { 
                    $this->classPropertiesIntoStruct($var['type']); 
                } 
                if (($var['array'] == 1 && $var['length'] > 0) 
                    || ($var['class'] == 1 && $var['length'] > 0)) { 
                    $_typensSource = ''; 
                    for ($i = $var['length']; $i > 0; --$i) { 
                        $_typensSource .= 'ArrayOf'; 
                        $this->wsdlStruct['array'][$_typensSource . $var['type']] = substr($_typensSource, 0, strlen($_typensSource) - 7) . $var['type']; 
                    } 
                } 
            } 
        } 
    } 

    // }}} 
    // {{{ classPropertiesIntoStruct() 
    /** 
     * parse classes properties into struct 
     * 
     * @var    string 
     * @access private 
     */ 
    protected function classPropertiesIntoStruct($className) 
    { 
        if (!isset($this->wsdlStruct[$className])) { 
            $class = new ReflectionClass($className); 
            $properties = $class->getProperties(); 
            $this->wsdlStruct['class'][$className]['property'] = array(); 
            for ($i = 0; $i < count($properties); ++$i) { 
                if ($properties[$i]->isPublic()) { 
                    preg_match_all('~@var\s(\S+)~', $properties[$i]->getDocComment(), $var); 

                    $_cleanType = str_replace('[]', '', $var[1][0], $_length); 
                    $_typens    = str_repeat('ArrayOf', $_length); 

                    $this->wsdlStruct['class'][$className]['property'][$properties[$i]->getName()]['type'] = 
                            $_cleanType; 
                    $this->wsdlStruct['class'][$className]['property'][$properties[$i]->getName()]['wsdltype'] = 
                            $_typens.$_cleanType; 
                    $this->wsdlStruct['class'][$className]['property'][$properties[$i]->getName()]['length'] = 
                            $_length; 
                    $this->wsdlStruct['class'][$className]['property'][$properties[$i]->getName()]['array'] =
                            ($_length > 0 && in_array($_cleanType, $this->simpleTypes)) 
                            ? true : false; 
                    $isObject = (!in_array($_cleanType, $this->simpleTypes) && new ReflectionClass($_cleanType)) 
                            ? true : false; 
                    $this->wsdlStruct['class'][$className]['property'][$properties[$i]->getName()]['class'] =
                            $isObject; 
                    if ($isObject == true) { 
                        $this->classPropertiesIntoStruct($_cleanType); 
                    } 
                    if ($_length > 0) { 
                        $_typensSource = ''; 
                        for ($j = $_length; $j > 0;  --$j) { 
                            $_typensSource .= 'ArrayOf'; 
                            $this->wsdlStruct['array'][$_typensSource.$_cleanType] = 
                                    substr($_typensSource, 0, strlen($_typensSource) - 7) . $_cleanType; 
                        } 
                    } 
                } 
            } 
        } 
    } 

    // }}} 
    // {{{ classMethodsIntoStruct() 
    /** 
     * parse classes methods into struct 
     * 
     * @access private 
     */ 
    protected function classMethodsIntoStruct() 
    { 
        $class = new ReflectionClass($this->classname); 
        $methods = $class->getMethods(); 
        // params 
        foreach ($methods AS $method) { 
            if ($method->isPublic() 
                && !in_array($method->getName(), $this->preventMethods)) { 
                $docComments = $method->getDocComment(); 
                $_docComments_Description = trim(str_replace('/**', '', substr($docComments, 0, strpos($docComments, '@')))); 
                $docComments_Description = preg_replace('/(\\s+|^)\\*\\s*|\\s*\\*(\\s+|$)/', ' ', $_docComments_Description); 
                $this->wsdlStruct[$this->classname]['method'][$method->getName()]['description'] = $docComments_Description; 
                preg_match_all('~@param\s(\S+)~', $docComments, $param); 
                preg_match_all('~@return\s(\S+)~', $method->getDocComment(), $return); 
                $params = $method->getParameters(); 
                for ($i = 0; $i < count($params); ++$i) { 
                    $_class = $params[$i]->getClass(); 
                    $_type  = ($_class) ? $_class->getName() : $param[1][$i]; 

                    $_cleanType = str_replace('[]', '', $_type, $_length); 
                    $_typens    = str_repeat('ArrayOf', $_length); 

                    $this->wsdlStruct[$this->classname]['method'][$method->getName()]['var'][$i]['name'] = 
                            $params[$i]->getName(); 
                    $this->wsdlStruct[$this->classname]['method'][$method->getName()]['var'][$i]['wsdltype'] = 
                            $_typens . $_cleanType; 
                    $this->wsdlStruct[$this->classname]['method'][$method->getName()]['var'][$i]['type'] = 
                            $_cleanType; 
                    $this->wsdlStruct[$this->classname]['method'][$method->getName()]['var'][$i]['length'] = 
                            $_length; 
                    $this->wsdlStruct[$this->classname]['method'][$method->getName()]['var'][$i]['array'] = 
                            ($_length > 0 && in_array($_cleanType, $this->simpleTypes)) 
                            ? true : false; 
                    $this->wsdlStruct[$this->classname]['method'][$method->getName()]['var'][$i]['class'] = 
                            (!in_array($_cleanType, $this->simpleTypes) && new ReflectionClass($_cleanType)) 
                            ? true : false; 
                    $this->wsdlStruct[$this->classname]['method'][$method->getName()]['var'][$i]['param'] = true; 
                } 
                // return 
                if (isset($return[1][0])) { 
                    $_cleanType = str_replace('[]', '', $return[1][0], $_length); 
                } else { 
                    $_cleanType = 'void'; 
                    $_length = 0; 
                } 
                $_typens = str_repeat('ArrayOf', $_length); 

                $this->wsdlStruct[$this->classname]['method'][$method->getName()]['var'][$i]['wsdltype'] = 
                        $_typens.$_cleanType; 
                $this->wsdlStruct[$this->classname]['method'][$method->getName()]['var'][$i]['type'] = $_cleanType; 
                $this->wsdlStruct[$this->classname]['method'][$method->getName()]['var'][$i]['length'] = $_length; 
                $this->wsdlStruct[$this->classname]['method'][$method->getName()]['var'][$i]['array'] = 
                        ($_length > 0 && $_cleanType != 'void' && in_array($_cleanType, $this->simpleTypes)) ? true : false; 
                $this->wsdlStruct[$this->classname]['method'][$method->getName()]['var'][$i]['class'] = 
                        ($_cleanType != 'void' && !in_array($_cleanType, $this->simpleTypes) && new ReflectionClass($_cleanType)) 
                        ? true : false; 
                $this->wsdlStruct[$this->classname]['method'][$method->getName()]['var'][$i]['return'] = true; 
            } 
        } 
    } 

    // }}} 
    // {{{ createWSDL_definitions() 
    /** 
     * Create the definition node 
     * 
     * @return void 
     */ 
    protected function createWSDL_definitions() 
    { 
      /* 
      <definitions name="myService" 
          targetNamespace="urn:myService" 
          xmlns:typens="urn:myService" 
          xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
          xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
          xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
          xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
          xmlns="http://schemas.xmlsoap.org/wsdl/"> 
      */ 

        $this->wsdl_definitions = $this->wsdl->createElement('definitions'); 
        $this->wsdl_definitions->setAttribute('name', $this->classname); 
        $this->wsdl_definitions->setAttribute('targetNamespace', 'urn:'.$this->classname); 
        $this->wsdl_definitions->setAttribute('xmlns:typens', 'urn:'.$this->classname); 
        $this->wsdl_definitions->setAttribute('xmlns:xsd', self::SOAP_XML_SCHEMA_VERSION); 
        $this->wsdl_definitions->setAttribute('xmlns:soap', self::SCHEMA_SOAP); 
        $this->wsdl_definitions->setAttribute('xmlns:soapenc', self::SOAP_SCHEMA_ENCODING); 
        $this->wsdl_definitions->setAttribute('xmlns:wsdl', self::SCHEMA_WSDL); 
        $this->wsdl_definitions->setAttribute('xmlns', self::SCHEMA_WSDL); 

        //$this->wsdl_definitions->setAttribute('xmlns:mime', self::SOAP_XML_SCHEMA_MIME); 
        //$this->wsdl_definitions->setAttribute('xmlns:tns', $this->namespace); 
        //$this->wsdl_definitions->setAttribute('xmlns:http', self::SCHEMA_WSDL_HTTP); 

        $this->wsdl->appendChild($this->wsdl_definitions); 
    } 

    // }}} 
    // {{{ createWSDL_types() 
    /** 
     * Create the types node 
     * 
     * @return void 
     */ 
    protected function createWSDL_types() 
    { 
       /* 
      <types> 
           <xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:myService"/> 
        </types> 
       */ 
        $types  = $this->wsdl->createElement('types'); 
        $schema = $this->wsdl->createElement('xsd:schema'); 
        $schema->setAttribute('xmlns', self::SOAP_XML_SCHEMA_VERSION ); 
        $schema->setAttribute('targetNamespace', 'urn:'.$this->classname); 
        $types->appendChild($schema); 

        // array 
        /* 
        <xsd:complexType name="ArrayOfclassC"> 
            <xsd:complexContent> 
                <xsd:restriction base="soapenc:Array"> 
                    <xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="typens:classC[]"/> 
                </xsd:restriction> 
            </xsd:complexContent> 
        </xsd:complexType> 
        */ 
        if (isset($this->wsdlStruct['array'])) { 

           foreach ($this->wsdlStruct['array'] as $source => $target) { 

              //<s:complexType name="ArrayOfArrayOfInt"> 
            //<s:sequence> 
            //<s:element minOccurs="0" maxOccurs="unbounded" name="ArrayOfInt" nillable="true" type="tns:ArrayOfInt"/> 
            //</s:sequence> 

               $complexType    = $this->wsdl->createElement('xsd:complexType'); 
               $complexContent = $this->wsdl->createElement('xsd:complexContent'); 
               $restriction    = $this->wsdl->createElement('xsd:restriction'); 
               $attribute       = $this->wsdl->createElement('xsd:attribute'); 
               $restriction->appendChild($attribute); 
               $complexContent->appendChild($restriction); 
               $complexType->appendChild($complexContent); 
               $schema->appendChild($complexType); 

               $complexType->setAttribute('name', $source); 
               $restriction->setAttribute('base', 'soapenc:Array'); 
               $attribute->setAttribute('ref', 'soapenc:arrayType'); 

               try { 
                  $class = new ReflectionClass($target); 
               }catch (Exception $e){} 

               if(in_array($target, $this->simpleTypes)){ 
                  $attribute->setAttribute('wsdl:arrayType', 'xsd:'.$target.'[]'); 
               }elseif(isset($class)){ 
                  $attribute->setAttribute('wsdl:arrayType', 'typens:'.$target.'[]'); 
               }else{ 
                  $attribute->setAttribute('wsdl:arrayType', 'typens:'.$target.'[]'); 
               } 
               unset($class); 

           } 
        } 

        // class 
        /* 
        <xsd:complexType name="classB"> 
            <xsd:all> 
                <xsd:element name="classCArray" type="typens:ArrayOfclassC" /> 
            </xsd:all> 
        </xsd:complexType> 
        */ 
        if (isset($this->wsdlStruct['class'])) { 
            foreach ($this->wsdlStruct['class'] as $className=>$classProperty) { 
                $complextype = $this->wsdl->createElement('xsd:complexType'); 
                $complextype->setAttribute('name', $className); 
                $sequence = $this->wsdl->createElement('xsd:all'); 
                $complextype->appendChild($sequence); 
                $schema->appendChild($complextype); 
                foreach ($classProperty['property'] as $classPropertyName => $classPropertyValue) { 
                    $element = $this->wsdl->createElement('xsd:element'); 
                    $element->setAttribute('name', $classPropertyName); 
                    $element->setAttribute('type', ((in_array($classPropertyValue['wsdltype'], $this->simpleTypes)) 
                                                  ? 'xsd:' 
                                                  : 'typens:') . $classPropertyValue['wsdltype']); 
                    $sequence->appendChild($element); 
                } 
            } 
        } 

        $this->wsdl_definitions->appendChild($types); 
    } 

    // }}} 
    // {{{ createWSDL_messages() 
    /** 
     * Create the messages node 
     * 
     * @return void 
     */ 
    protected function createWSDL_messages() 
    { 
       /* 
       <message name="hello"> 
           <part name="i" type="xsd:int"/> 
           <part name="j" type="xsd:string"/> 
       </message> 
       <message name="helloResponse"> 
           <part name="helloResponse" type="xsd:string"/> 
       </message> 
       */ 
        foreach ($this->wsdlStruct[$this->classname]['method'] AS $methodName => $method){ 
            $messageInput = $this->wsdl->createElement('message'); 
            $messageInput->setAttribute('name', $methodName); 
            $messageOutput = $this->wsdl->createElement('message'); 
            $messageOutput->setAttribute('name', $methodName . 'Response'); 
            $this->wsdl_definitions->appendChild($messageInput); 
            $this->wsdl_definitions->appendChild($messageOutput); 

            foreach ($method['var'] as $methodVars) {                
                if (isset($methodVars['param'])) { 
                    $part = $this->wsdl->createElement('part'); 
                    $part->setAttribute('name', $methodVars['name']); 
                    $part->setAttribute('type', (($methodVars['array'] != 1 && $methodVars['class'] != 1) 
                        ? 'xsd:' : 'typens:') . $methodVars['wsdltype']); 
                  $messageInput->appendChild($part); 
                } 
                if (isset($methodVars['return'])) { 
                    $part = $this->wsdl->createElement('part'); 
                    $part->setAttribute('name', $methodName.'Response'); //$methodVars['wsdltype']); 
                    $part->setAttribute('type', (($methodVars['array'] != 1 && $methodVars['class'] != 1) 
                        ? 'xsd:' : 'typens:') . $methodVars['wsdltype']); 
                  $messageOutput->appendChild($part); 
                } 
            } 
        } 
    } 

   // }}} 
    // {{{ createWSDL_binding() 
    /** 
     * Create the binding node 
     * 
     * @return void 
     */ 
    protected function createWSDL_binding() 
    { 
       /* 
       <binding name="myServiceBinding" type="typens:myServicePort">    
           <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> 
               <operation name="hello"> 
                   <soap:operation soapAction="urn:myServiceAction"/> 
               <input> 
                   <soap:body use="encoded" namespace="urn:myService" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> 
                   </input> 
                   <output> 
                       <soap:body use="encoded" namespace="urn:myService" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> 
                   </output> 
           </operation> 
       </binding> 
       */ 
      $binding = $this->wsdl->createElement('binding'); 
        $binding->setAttribute('name', $this->classname . 'Binding'); 
        $binding->setAttribute('type', 'typens:' . $this->classname . 'Port'); 
        $soap_binding = $this->wsdl->createElement('soap:binding'); 
        $soap_binding->setAttribute('style', 'rpc'); 
        $soap_binding->setAttribute('transport', self::SCHEMA_SOAP_HTTP); 
        $binding->appendChild($soap_binding); 
        foreach ($this->wsdlStruct[$this->classname]['method'] AS $methodName => $methodVars) { 
            $operation = $this->wsdl->createElement('operation'); 
            $operation->setAttribute('name', $methodName); 
            $binding->appendChild($operation); 
            $soap_operation = $this->wsdl->createElement('soap:operation'); 
            $soap_operation->setAttribute('soapAction', 'urn:'.$this->classname.'Action'); 
            $operation->appendChild($soap_operation);            
            $input  = $this->wsdl->createElement('input'); 
            $output = $this->wsdl->createElement('output'); 
            $operation->appendChild($input); 
            $operation->appendChild($output); 
            $soap_body = $this->wsdl->createElement('soap:body'); 
            $soap_body->setAttribute('use', 'encoded'); 
            $soap_body->setAttribute('namespace', 'urn:'.$this->namespace); 
            $soap_body->setAttribute('encodingStyle', self::SOAP_SCHEMA_ENCODING );
            $input->appendChild($soap_body); 
            $soap_body = $this->wsdl->createElement('soap:body'); 
            $soap_body->setAttribute('use', 'encoded'); 
            $soap_body->setAttribute('namespace', 'urn:'.$this->namespace); 
            $soap_body->setAttribute('encodingStyle', self::SOAP_SCHEMA_ENCODING );
            $output->appendChild($soap_body); 
        } 
        $this->wsdl_definitions->appendChild($binding); 
    } 

    // }}} 
    // {{{ createWSDL_portType() 
    /** 
     * Create the portType node 
     * 
     * @return void 
     */ 
    protected function createWSDL_portType() 
    { 
       /* 
       <portType name="myServicePort"> 
           <operation name="hello"> 
               <input message="typens:hello"/> 
               <output message="typens:helloResponse"/> 
           </operation> 
       </portType> 
       */ 
        $portType = $this->wsdl->createElement('portType'); 
        $portType->setAttribute('name', $this->classname.'Port'); 
        foreach ($this->wsdlStruct[$this->classname]['method'] AS $methodName => $methodVars) { 
            $operation = $this->wsdl->createElement('operation'); 
            $operation->setAttribute('name', $methodName); 
            $portType->appendChild($operation); 

            $documentation = $this->wsdl->createElement('documentation'); 
            $documentation->appendChild($this->wsdl->createTextNode($methodVars['description'])); 
            $operation->appendChild($documentation); 

            $input  = $this->wsdl->createElement('input'); 
            $output = $this->wsdl->createElement('output'); 
            $input->setAttribute('message', 'typens:' . $methodName ); 
            $output->setAttribute('message', 'typens:' . $methodName . 'Response');
            $operation->appendChild($input); 
            $operation->appendChild($output); 
        } 
        $this->wsdl_definitions->appendChild($portType); 
    } 

    // }}} 
    // {{{ createWSDL_service() 
    /** 
     * Create the service node 
     * 
     * @return void 
     */ 
    protected function createWSDL_service() 
    { 
       /* 
       <service name="myService"> 
           <port name="myServicePort" binding="typens:myServiceBinding"> 
               <soap:address location="http://dschini.org/test1.php"/> 
           </port> 
       </service> 
        */ 
        $service = $this->wsdl->createElement('service'); 
        $service->setAttribute('name', $this->classname); 
        $port = $this->wsdl->createElement('port'); 
        $port->setAttribute('name', $this->classname . 'Port'); 
        $port->setAttribute('binding', 'typens:' . $this->classname . 'Binding'); 
        $adress = $this->wsdl->createElement('soap:address'); 
        $adress->setAttribute('location', $this->protocol . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']); 
        $port->appendChild($adress); 
        $service->appendChild($port); 
        $this->wsdl_definitions->appendChild($service); 
    } 
}