338 lines
11 KiB
PHP
338 lines
11 KiB
PHP
|
|
<?php
|
||
|
|
/**
|
||
|
|
* Class that can generate a WSDL document from PHP code
|
||
|
|
*
|
||
|
|
* This class generates a WSDL document for the given
|
||
|
|
* methods when the the methods and parameters are documented
|
||
|
|
* enough. When there is not enough documentation available (ie
|
||
|
|
* unclear what the type of a variable or return type is) a
|
||
|
|
* WSDLException is thrown.
|
||
|
|
*
|
||
|
|
*
|
||
|
|
*@author KnowledgeTree Team
|
||
|
|
*@package Webservice
|
||
|
|
*@version Version 0.9
|
||
|
|
*/
|
||
|
|
class WSDLStruct {
|
||
|
|
/** @var boolean */
|
||
|
|
public $_debug = false;
|
||
|
|
|
||
|
|
/** @var int binding type: SOAP_RPC | SOAP_DOCUMENT */
|
||
|
|
public $binding_style;
|
||
|
|
|
||
|
|
/** @var int use: SOAP_LITERAL | SOAP_ENCODED */
|
||
|
|
public $use;
|
||
|
|
/************************** Private properties ***************************/
|
||
|
|
|
||
|
|
/** @var SOAPService[] */
|
||
|
|
private $services = Array();
|
||
|
|
|
||
|
|
/** @var domElement[] */
|
||
|
|
private $serviceTags = Array();
|
||
|
|
|
||
|
|
/** @var domElement[] */
|
||
|
|
private $operationTags = Array();
|
||
|
|
|
||
|
|
/** @var domElement[] references to the portType tags. servicename as key */
|
||
|
|
private $portTypeTags = Array();
|
||
|
|
|
||
|
|
/** @var domElement[] references to the binding tags. servicename as key */
|
||
|
|
private $bindingTags = Array();
|
||
|
|
|
||
|
|
/** @var domElement[] references to the binding operation tags. servicename as first key, operationname as second */
|
||
|
|
private $bindingOperationTags = Array();
|
||
|
|
|
||
|
|
/** @var domDocument */
|
||
|
|
private $doc;
|
||
|
|
|
||
|
|
/** @var domelement */
|
||
|
|
private $definitions;
|
||
|
|
|
||
|
|
/** @var domelement Refference tot the types tag*/
|
||
|
|
private $typesTag;
|
||
|
|
|
||
|
|
/** @var domelement Refference to the xsd:schema tag*/
|
||
|
|
private $xsdSchema;
|
||
|
|
|
||
|
|
/** @var IPXMLSchema */
|
||
|
|
private $xmlSchema;
|
||
|
|
|
||
|
|
//namespaces used
|
||
|
|
const NS_WSDL = "http://schemas.xmlsoap.org/wsdl/";
|
||
|
|
const NS_SOAP = "http://schemas.xmlsoap.org/wsdl/soap/";
|
||
|
|
const NS_ENC = "http://schemas.xmlsoap.org/soap/encoding/";
|
||
|
|
const NS_XSD = "http://www.w3.org/2001/XMLSchema";
|
||
|
|
|
||
|
|
const CREATE_EMPTY_INPUTS = true;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* @param string Target namespace
|
||
|
|
* @param string URL for the webservice
|
||
|
|
* @return void
|
||
|
|
*/
|
||
|
|
public function __construct($tns, $url, $type = SOAP_RPC, $use = SOAP_ENCODED){
|
||
|
|
if($type != SOAP_RPC && $type != SOAP_DOCUMENT) throw new Exception("Webservice type parameter should be either SOAP_RPC or SOAP_DOCUMENT");
|
||
|
|
if($use != SOAP_ENCODED && $use != SOAP_LITERAL) throw new Exception("Webservice use parameter should be either SOAP_ENCODED or SOAP_LITERAL");
|
||
|
|
|
||
|
|
$this->use = $use;
|
||
|
|
$this->binding_style=$type;
|
||
|
|
$this->tns = $tns;
|
||
|
|
$this->url = $url;
|
||
|
|
$this->doc = new domDocument();
|
||
|
|
$this->definitions = $this->addElement("wsdl:definitions",$this->doc);
|
||
|
|
|
||
|
|
$this->typesTag = $this->addElement("wsdl:types", $this->definitions);
|
||
|
|
$this->xsdSchema = $this->addElement("xsd:schema", $this->typesTag);
|
||
|
|
$this->xsdSchema->setAttribute("targetNamespace", $this->tns);
|
||
|
|
$this->xmlSchema = new IPXMLSchema($this->xsdSchema);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Adds the class to the services for this WSDL
|
||
|
|
*
|
||
|
|
* @param IPReflectionClass The service
|
||
|
|
* @return void
|
||
|
|
*/
|
||
|
|
public function setService(IPReflectionClass $class){
|
||
|
|
$this->services[$class->classname] = $class;
|
||
|
|
$this->services[$class->classname]->getMethods(false, false);
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* @return string The WSDL document for this structure
|
||
|
|
*/
|
||
|
|
public function generateDocument(){
|
||
|
|
$this->addToDebug("Generating document");
|
||
|
|
|
||
|
|
//add all definitions
|
||
|
|
$definitions=$this->definitions;
|
||
|
|
$definitions->setAttribute("xmlns", self::NS_WSDL);
|
||
|
|
$definitions->setAttribute("xmlns:soap", self::NS_SOAP);
|
||
|
|
$definitions->setAttribute("xmlns:SOAP-ENC", self::NS_ENC);
|
||
|
|
$definitions->setAttribute("xmlns:wsdl", self::NS_WSDL);
|
||
|
|
$definitions->setAttribute("xmlns:xsd", self::NS_XSD);
|
||
|
|
$definitions->setAttribute("xmlns:tns", $this->tns);
|
||
|
|
$definitions->setAttribute("targetNamespace", $this->tns);
|
||
|
|
|
||
|
|
//add all the services
|
||
|
|
foreach((array)$this->services as $serviceName => $service){
|
||
|
|
//add the portType
|
||
|
|
$portType = $this->addPortType($serviceName);
|
||
|
|
|
||
|
|
//add binding
|
||
|
|
$binding = $this->addBinding($serviceName);
|
||
|
|
|
||
|
|
//loop the operations
|
||
|
|
foreach((array)$service->methods as $operation){
|
||
|
|
$operationName = $operation->name;
|
||
|
|
$operationTag = $this->addOperation($operationName, $serviceName);
|
||
|
|
|
||
|
|
//input
|
||
|
|
//only when to operation needs arguments
|
||
|
|
$parameters = $operation->getParameters();
|
||
|
|
if(count($parameters)>0 || self::CREATE_EMPTY_INPUTS){
|
||
|
|
$messageName = $operationName."Request";
|
||
|
|
$input=$this->addElement("wsdl:input", $operationTag);
|
||
|
|
$input->setAttribute("message", "tns:".$messageName);
|
||
|
|
$para=Array();
|
||
|
|
foreach((array)$parameters as $parameterName => $parameter){
|
||
|
|
$para[$parameterName] = $parameter->type;
|
||
|
|
}
|
||
|
|
$this->addMessage($messageName, $para);
|
||
|
|
$this->addInput($this->bindingOperationTags[$serviceName][$operationName]);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
//output
|
||
|
|
//only when the operation returns something
|
||
|
|
if(!$operation->return || trim($operation->return) == "") throw new WSDLException('No return type for '.$operationName);
|
||
|
|
if(strtolower(trim($operation->return))!='void'){
|
||
|
|
$messageName = $operationName."Response";
|
||
|
|
$output = $this->addElement("wsdl:output", $operationTag);
|
||
|
|
$output->setAttribute("message", "tns:".$messageName);
|
||
|
|
$this->addOutput($this->bindingOperationTags[$serviceName][$operationName]);
|
||
|
|
$this->addMessage($messageName,Array($operation->name."Return" => $operation->return));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// SH. now add the portType and binding
|
||
|
|
$this->definitions->AppendChild($portType);
|
||
|
|
$this->definitions->AppendChild($binding);
|
||
|
|
|
||
|
|
//add the service
|
||
|
|
$this->addService($serviceName);
|
||
|
|
|
||
|
|
}
|
||
|
|
return $this->doc->saveXML();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Adds a new operation to the given service
|
||
|
|
* @param string operation name
|
||
|
|
* @param string service name
|
||
|
|
* @return domElement
|
||
|
|
*/
|
||
|
|
private function addOperation($operationName, $serviceName){
|
||
|
|
$this->addToDebug("Adding Operation: '$operationName : $serviceName'");
|
||
|
|
$operationTag = $this->addElement("wsdl:operation",$this->portTypeTags[$serviceName]);
|
||
|
|
$operationTag->setAttribute("name",$operationName);
|
||
|
|
|
||
|
|
//create operation tag for binding
|
||
|
|
$bindingOperationTag = $this->addElement("wsdl:operation",$this->bindingTags[$serviceName]);
|
||
|
|
$bindingOperationTag->setAttribute("name",$operationName);
|
||
|
|
|
||
|
|
//soap operation tag
|
||
|
|
$soapOperationTag = $this->addElement("soap:operation",$bindingOperationTag);
|
||
|
|
$soapOperationTag->setAttribute("soapAction",$this->url."&method=".$operationName);
|
||
|
|
$soapOperationTag->setAttribute("style",($this->binding_style == SOAP_RPC)? "rpc" : "document");
|
||
|
|
|
||
|
|
//save references
|
||
|
|
$this->operationTags[$serviceName][$operationName] = $operationTag;
|
||
|
|
$this->bindingOperationTags[$serviceName][$operationName] = $bindingOperationTag;
|
||
|
|
|
||
|
|
//and return
|
||
|
|
return $operationTag;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* adds a new service tag to the WSDL file
|
||
|
|
* @param string the service name
|
||
|
|
* @return domElement
|
||
|
|
*/
|
||
|
|
private function addService($serviceName){
|
||
|
|
$this->addToDebug("Adding service: '$serviceName'");
|
||
|
|
//create service
|
||
|
|
$serviceTag=$this->addElement("wsdl:service",$this->definitions);
|
||
|
|
$serviceTag->setAttribute("name",$serviceName);
|
||
|
|
|
||
|
|
//port tag
|
||
|
|
$portTag=$this->addElement("wsdl:port", $serviceTag);
|
||
|
|
$portTag->setAttribute("name", $serviceName."Port");
|
||
|
|
$portTag->setAttribute("binding", "tns:".$serviceName."Binding");
|
||
|
|
|
||
|
|
//address tag
|
||
|
|
$addressTag = $this->addElement("soap:address", $portTag);
|
||
|
|
$addressTag->setAttribute("location", $this->url);
|
||
|
|
|
||
|
|
//keep a reference
|
||
|
|
$this->serviceTags[$serviceName] = $serviceTag;
|
||
|
|
//and return
|
||
|
|
return $serviceTag;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Adds a new portType to the WSDL structure
|
||
|
|
* @param string the service name for which we create a portType
|
||
|
|
* @return domElement
|
||
|
|
*/
|
||
|
|
private function addPortType($serviceName){
|
||
|
|
$this->addToDebug("Adding portType: '$serviceName'");
|
||
|
|
// SH don't add to main doc just yet
|
||
|
|
// $portTypeTag=$this->addElement("wsdl:portType", $this->definitions);
|
||
|
|
$portTypeTag = $this->addElement("wsdl:portType");
|
||
|
|
$portTypeTag->setAttribute("name", $serviceName."PortType");
|
||
|
|
|
||
|
|
//keep a reference
|
||
|
|
$this->portTypeTags[$serviceName]=$portTypeTag;
|
||
|
|
//and return
|
||
|
|
return $portTypeTag;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Adds a new binding to the WSDL structure
|
||
|
|
* @param string serviceName to bind
|
||
|
|
* @return domElement
|
||
|
|
*/
|
||
|
|
private function addBinding($serviceName){
|
||
|
|
$this->addToDebug("Adding binding: '$serviceName'");
|
||
|
|
// SH. don't add to main doc just yet
|
||
|
|
// $bindingTag=$this->addElement("binding");
|
||
|
|
$bindingTag=$this->addElement("binding",$this->definitions);
|
||
|
|
$bindingTag->setAttribute("name", $serviceName."Binding");
|
||
|
|
$bindingTag->setAttribute("type", "tns:".$serviceName."PortType");
|
||
|
|
|
||
|
|
//soap binding tag
|
||
|
|
$soapBindingTag = $this->addElement("soap:binding", $bindingTag);
|
||
|
|
$soapBindingTag->setAttribute("style", ($this->binding_style == SOAP_RPC)? "rpc" : "document");
|
||
|
|
$soapBindingTag->setAttribute("transport", "http://schemas.xmlsoap.org/soap/http");
|
||
|
|
|
||
|
|
//keep a reference
|
||
|
|
$this->bindingTags[$serviceName] = $bindingTag;
|
||
|
|
//and return
|
||
|
|
return $bindingTag;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Adds a message tag to the WSDL document
|
||
|
|
* @param string Message name
|
||
|
|
* @param Array[string=>string] Array with variables & types
|
||
|
|
*/
|
||
|
|
private function addMessage($name, $parts){
|
||
|
|
$this->addToDebug("Adding message: '$name'");
|
||
|
|
$msg = $this->addElement("message", $this->definitions);
|
||
|
|
$msg->setAttribute("name", $name);
|
||
|
|
foreach((array)$parts as $partName => $partType){
|
||
|
|
$this->addToDebug("Adding Message part: '$partName => $partType'");
|
||
|
|
$part=$this->addElement("part", $msg);
|
||
|
|
$part->setAttribute("name", $partName);
|
||
|
|
|
||
|
|
//check if it is a valid XML Schema datatype
|
||
|
|
if($t = IPXMLSchema::checkSchemaType(strtolower($partType)))
|
||
|
|
$part->setAttribute("type", "xsd:".$t);
|
||
|
|
else{
|
||
|
|
//If it is an array, change the type name
|
||
|
|
$partName = (substr($partType,-2) == "[]")?substr($partType,0,strpos($partType,"["))."Array":$partType;
|
||
|
|
|
||
|
|
$part->setAttribute("type", "tns:".$partName);
|
||
|
|
$this->xmlSchema->addComplexType($partType, $partName);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Adds an input element to the given parent (an operation tag)
|
||
|
|
* @param domNode The Parent domNode
|
||
|
|
* @param boolean Kind of tag. true=input tag, false=output tag
|
||
|
|
* @return domNode The input/output node
|
||
|
|
*/
|
||
|
|
private function addInput($parent, $input=true){
|
||
|
|
$name = $input ? "wsdl:input" : "wsdl:output";
|
||
|
|
$tag=$this->addElement($name, $parent);
|
||
|
|
$soapOperation=$this->addElement("soap:body", $tag);
|
||
|
|
$soapOperation->setAttribute("use", ($this->use == SOAP_ENCODED)? "encoded" : "literal");
|
||
|
|
$soapOperation->setAttribute("namespace", $this->tns);
|
||
|
|
if($this->use == SOAP_ENCODED)
|
||
|
|
$soapOperation->setAttribute("encodingStyle", self::NS_ENC);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Adds an output element to the given parent (an operation tag)
|
||
|
|
* @param domNode The Parent domNode
|
||
|
|
* @return domNode The output node
|
||
|
|
*/
|
||
|
|
private function addOutput($parent){
|
||
|
|
return $this->addInput($parent,false);
|
||
|
|
}
|
||
|
|
|
||
|
|
/************************* Supporting functions ****************************/
|
||
|
|
|
||
|
|
private function addToDebug($msg){
|
||
|
|
if($this->_debug) echo '-'.$msg." <br>\n";
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Adds an child element to the parent
|
||
|
|
* @param string The name element
|
||
|
|
* @param domNode
|
||
|
|
* @return domNode
|
||
|
|
*/
|
||
|
|
private function addElement($name, $parent=false, $ns=false){
|
||
|
|
if($ns)
|
||
|
|
$el=$this->doc->createElementNS($ns,$name);
|
||
|
|
else
|
||
|
|
$el=$this->doc->createElement($name);
|
||
|
|
if($parent)
|
||
|
|
$parent->appendChild($el);
|
||
|
|
return $el;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
?>
|