This repository has been archived on 2024-11-28. You can view files and clone it, but cannot push or open issues or pull requests.
Incam_SGD/webservice/classes/soap/WSDLStruct.class.php

338 lines
11 KiB
PHP
Raw Permalink Normal View History

<?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;
}
}
?>