Versions
Look up a class, method, property or event

CWsdlGenerator

Package system.web.services
Inheritance class CWsdlGenerator » CComponent
Since 1.0
Source Code framework/web/services/CWsdlGenerator.php
CWsdlGenerator generates the WSDL for a given service class.

The WSDL generation is based on the doc comments found in the service class file. In particular, it recognizes the '@soap' tag in the comment and extracts API method and type definitions.

In a service class, a remote invokable method must be a public method with a doc comment block containing the '@soap' tag. In the doc comment, the type and name of every input parameter and the type of the return value should be declared using the standard phpdoc format.

CWsdlGenerator recognizes the following primitive types (case-sensitive) in the parameter and return type declarations:
  • str/string: maps to xsd:string;
  • int/integer: maps to xsd:int;
  • float/double: maps to xsd:float;
  • bool/boolean: maps to xsd:boolean;
  • date: maps to xsd:date;
  • time: maps to xsd:time;
  • datetime: maps to xsd:dateTime;
  • array: maps to xsd:string;
  • object: maps to xsd:struct;
  • mixed: maps to xsd:anyType.


If a type is not a primitive type, it is considered as a class type, and CWsdlGenerator will look for its property declarations. Only public properties are considered, and they each must be associated with a doc comment block containg the '@soap' tag. The doc comment block should declare the type of the property.

CWsdlGenerator recognizes the array type with the following format:
typeName[]: maps to tns:typeNameArray


The following is an example declaring a remote invokable method:
/ **
  * A foo method.
  * @param string name of something
  * @param string value of something
  * @return string[] some array
  * @soap
  * /
public function foo($name,$value) {...}


And the following is an example declaring a class with remote accessible properties:
class Foo {
    / **
      * @var string name of foo {nillable = 1, minOccurs=0, maxOccurs = 2}
      * @soap
      * /
    public $name;
    / **
      * @var Member[] members of foo
      * @soap
      * /
    public $members;
}
In the above, the 'members' property is an array of 'Member' objects. Since 'Member' is not a primitive type, CWsdlGenerator will look further to find the definition of 'Member'.

Optionally, extra attributes (nillable, minOccurs, maxOccurs) can be defined for each property by enclosing definitions into curly brackets and separated by comma like so:

{[attribute1 = value1], [attribute2 = value2], ...}

where the attribute can be one of following: nillable = [0|1|true|false] minOccurs = n; where n>=0 maxOccurs = n; where n>=0

Public Properties

Hide inherited properties

PropertyTypeDescriptionDefined By
namespace string the namespace to be used in the generated WSDL. CWsdlGenerator
serviceName string the name of the generated WSDL. CWsdlGenerator

Protected Properties

Hide inherited properties

PropertyTypeDescriptionDefined By
messages CWsdlGenerator
operations CWsdlGenerator
typeMap CWsdlGenerator
types CWsdlGenerator

Public Methods

Hide inherited methods

MethodDescriptionDefined By
__call() Calls the named method which is not a class method. CComponent
__get() Returns a property value, an event handler list or a behavior based on its name. CComponent
__isset() Checks if a property value is null. CComponent
__set() Sets value of a component property. CComponent
__unset() Sets a component property to be null. CComponent
asa() Returns the named behavior object. CComponent
attachBehavior() Attaches a behavior to this component. CComponent
attachBehaviors() Attaches a list of behaviors to the component. CComponent
attachEventHandler() Attaches an event handler to an event. CComponent
canGetProperty() Determines whether a property can be read. CComponent
canSetProperty() Determines whether a property can be set. CComponent
detachBehavior() Detaches a behavior from the component. CComponent
detachBehaviors() Detaches all behaviors from the component. CComponent
detachEventHandler() Detaches an existing event handler. CComponent
disableBehavior() Disables an attached behavior. CComponent
disableBehaviors() Disables all behaviors attached to this component. CComponent
enableBehavior() Enables an attached behavior. CComponent
enableBehaviors() Enables all behaviors attached to this component. CComponent
evaluateExpression() Evaluates a PHP expression or callback under the context of this component. CComponent
generateWsdl() Generates the WSDL for the given class. CWsdlGenerator
getEventHandlers() Returns the list of attached event handlers for an event. CComponent
hasEvent() Determines whether an event is defined. CComponent
hasEventHandler() Checks whether the named event has attached handlers. CComponent
hasProperty() Determines whether a property is defined. CComponent
raiseEvent() Raises an event. CComponent

Protected Methods

Hide inherited methods

MethodDescriptionDefined By
addBindings() CWsdlGenerator
addMessages() CWsdlGenerator
addPortTypes() CWsdlGenerator
addService() CWsdlGenerator
addTypes() CWsdlGenerator
buildDOM() CWsdlGenerator
createOperationElement() CWsdlGenerator
createPortElement() CWsdlGenerator
processMethod() CWsdlGenerator
processType() CWsdlGenerator

Property Details

messages property
protected $messages;

namespace property
public string $namespace;

the namespace to be used in the generated WSDL. If not set, it defaults to the name of the class that WSDL is generated upon.

operations property
protected $operations;

serviceName property
public string $serviceName;

the name of the generated WSDL. If not set, it defaults to "urn:{$className}wsdl".

typeMap property
protected static $typeMap;

types property
protected $types;

Method Details

addBindings() method
protected void addBindings(DOMDocument $dom)
$dom DOMDocument Represents an entire HTML or XML document; serves as the root of the document tree
Source Code: framework/web/services/CWsdlGenerator.php#400 (show)
protected function addBindings($dom)
{
    
$binding=$dom->createElement('wsdl:binding');
    
$binding->setAttribute('name',$this->serviceName.'Binding');
    
$binding->setAttribute('type','tns:'.$this->serviceName.'PortType');

    
$soapBinding=$dom->createElement('soap:binding');
    
$soapBinding->setAttribute('style','rpc');
    
$soapBinding->setAttribute('transport','http://schemas.xmlsoap.org/soap/http');
    
$binding->appendChild($soapBinding);

    
$dom->documentElement->appendChild($binding);

    foreach(
$this->operations as $name=>$doc)
        
$binding->appendChild($this->createOperationElement($dom,$name));
}

addMessages() method
protected void addMessages(DOMDocument $dom)
$dom DOMDocument Represents an entire HTML or XML document; serves as the root of the document tree
Source Code: framework/web/services/CWsdlGenerator.php#343 (show)
protected function addMessages($dom)
{
    foreach(
$this->messages as $name=>$message)
    {
        
$element=$dom->createElement('wsdl:message');
        
$element->setAttribute('name',$name);
        foreach(
$this->messages[$name] as $partName=>$part)
        {
            if(
is_array($part))
            {
                
$partElement=$dom->createElement('wsdl:part');
                
$partElement->setAttribute('name',$partName);
                
$partElement->setAttribute('type',$part[0]);
                
$element->appendChild($partElement);
            }
        }
        
$dom->documentElement->appendChild($element);
    }
}

addPortTypes() method
protected void addPortTypes(DOMDocument $dom)
$dom DOMDocument Represents an entire HTML or XML document; serves as the root of the document tree
Source Code: framework/web/services/CWsdlGenerator.php#366 (show)
protected function addPortTypes($dom)
{
    
$portType=$dom->createElement('wsdl:portType');
    
$portType->setAttribute('name',$this->serviceName.'PortType');
    
$dom->documentElement->appendChild($portType);
    foreach(
$this->operations as $name=>$doc)
        
$portType->appendChild($this->createPortElement($dom,$name,$doc));
}

addService() method
protected void addService(DOMDocument $dom, string $serviceUrl)
$dom DOMDocument Represents an entire HTML or XML document; serves as the root of the document tree
$serviceUrl string Web service URL
Source Code: framework/web/services/CWsdlGenerator.php#450 (show)
protected function addService($dom,$serviceUrl)
{
    
$service=$dom->createElement('wsdl:service');
    
$service->setAttribute('name'$this->serviceName.'Service');

    
$port=$dom->createElement('wsdl:port');
    
$port->setAttribute('name'$this->serviceName.'Port');
    
$port->setAttribute('binding''tns:'.$this->serviceName.'Binding');

    
$soapAddress=$dom->createElement('soap:address');
    
$soapAddress->setAttribute('location',$serviceUrl);
    
$port->appendChild($soapAddress);
    
$service->appendChild($port);
    
$dom->documentElement->appendChild($service);
}

addTypes() method
protected void addTypes(DOMDocument $dom)
$dom DOMDocument Represents an entire HTML or XML document; serves as the root of the document tree
Source Code: framework/web/services/CWsdlGenerator.php#280 (show)
protected function addTypes($dom)
{
    if(
$this->types===array())
        return;
    
$types=$dom->createElement('wsdl:types');
    
$schema=$dom->createElement('xsd:schema');
    
$schema->setAttribute('targetNamespace',$this->namespace);
    foreach(
$this->types as $phpType=>$xmlType)
    {
        if(
is_string($xmlType) && strrpos($xmlType,'Array')!==strlen($xmlType)-5)
            continue;  
// simple type
        
$complexType=$dom->createElement('xsd:complexType');
        if(
is_string($xmlType))
        {
            if((
$pos=strpos($xmlType,'tns:'))!==false)
                
$complexType->setAttribute('name',substr($xmlType,4));
            else
                
$complexType->setAttribute('name',$xmlType);
            
$complexContent=$dom->createElement('xsd:complexContent');
            
$restriction=$dom->createElement('xsd:restriction');
            
$restriction->setAttribute('base','soap-enc:Array');
            
$attribute=$dom->createElement('xsd:attribute');
            
$attribute->setAttribute('ref','soap-enc:arrayType');
            
$attribute->setAttribute('wsdl:arrayType',substr($xmlType,0,strlen($xmlType)-5).'[]');

            
$arrayType = ($dppos=strpos($xmlType,':')) !==false substr($xmlType,$dppos 1) : $xmlType// strip namespace, if any
            
$arrayType substr($arrayType,0,-5); // strip 'Array' from name
            
$arrayType = (isset(self::$typeMap[$arrayType]) ? 'xsd:' 'tns:') .$arrayType.'[]';
            
$attribute->setAttribute('wsdl:arrayType',$arrayType);

            
$restriction->appendChild($attribute);
            
$complexContent->appendChild($restriction);
            
$complexType->appendChild($complexContent);
        }
        elseif(
is_array($xmlType))
        {
            
$complexType->setAttribute('name',$phpType);
            
$all=$dom->createElement('xsd:all');
            foreach(
$xmlType as $name=>$type)
            {
                
$element=$dom->createElement('xsd:element');
                if(
$type[3]!==false)
                    
$element->setAttribute('minOccurs',$type[3]);
                if(
$type[4]!==false)
                    
$element->setAttribute('maxOccurs',$type[4]);
                if(
$type[2]!==false)
                    
$element->setAttribute('nillable',$type[2]);
                
$element->setAttribute('name',$name);
                
$element->setAttribute('type',$type[0]);
                
$all->appendChild($element);
            }
            
$complexType->appendChild($all);
        }
        
$schema->appendChild($complexType);
        
$types->appendChild($schema);
    }

    
$dom->documentElement->appendChild($types);
}

buildDOM() method
protected void buildDOM(string $serviceUrl, string $encoding)
$serviceUrl string Web service URL
$encoding string encoding of the WSDL. Defaults to 'UTF-8'.
Source Code: framework/web/services/CWsdlGenerator.php#253 (show)
protected function buildDOM($serviceUrl,$encoding)
{
    
$xml="<?xml version=\"1.0\" encoding=\"$encoding\"?>
<definitions name=\"
{$this->serviceName}\" targetNamespace=\"{$this->namespace}\"
 xmlns=\"http://schemas.xmlsoap.org/wsdl/\"
 xmlns:tns=\"
{$this->namespace}\"
 xmlns:soap=\"http://schemas.xmlsoap.org/wsdl/soap/\"
 xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
 xmlns:wsdl=\"http://schemas.xmlsoap.org/wsdl/\"
 xmlns:soap-enc=\"http://schemas.xmlsoap.org/soap/encoding/\"></definitions>"
;

    
$dom=new DOMDocument();
    
$dom->formatOutput=true;
    
$dom->loadXml($xml);
    
$this->addTypes($dom);

    
$this->addMessages($dom);
    
$this->addPortTypes($dom);
    
$this->addBindings($dom);
    
$this->addService($dom,$serviceUrl);

    return 
$dom;
}

createOperationElement() method
protected void createOperationElement(DOMDocument $dom, string $name)
$dom DOMDocument Represents an entire HTML or XML document; serves as the root of the document tree
$name string method name
Source Code: framework/web/services/CWsdlGenerator.php#421 (show)
protected function createOperationElement($dom,$name)
{
    
$operation=$dom->createElement('wsdl:operation');
    
$operation->setAttribute('name'$name);
    
$soapOperation $dom->createElement('soap:operation');
    
$soapOperation->setAttribute('soapAction'$this->namespace.'#'.$name);
    
$soapOperation->setAttribute('style','rpc');

    
$input $dom->createElement('wsdl:input');
    
$output $dom->createElement('wsdl:output');

    
$soapBody $dom->createElement('soap:body');
    
$soapBody->setAttribute('use''encoded');
    
$soapBody->setAttribute('namespace'$this->namespace);
    
$soapBody->setAttribute('encodingStyle''http://schemas.xmlsoap.org/soap/encoding/');
    
$input->appendChild($soapBody);
    
$output->appendChild(clone $soapBody);

    
$operation->appendChild($soapOperation);
    
$operation->appendChild($input);
    
$operation->appendChild($output);

    return 
$operation;
}

createPortElement() method
protected void createPortElement(DOMDocument $dom, string $name, string $doc)
$dom DOMDocument Represents an entire HTML or XML document; serves as the root of the document tree
$name string method name
$doc string doc
Source Code: framework/web/services/CWsdlGenerator.php#380 (show)
protected function createPortElement($dom,$name,$doc)
{
    
$operation=$dom->createElement('wsdl:operation');
    
$operation->setAttribute('name',$name);

    
$input $dom->createElement('wsdl:input');
    
$input->setAttribute('message''tns:'.$name.'Request');
    
$output $dom->createElement('wsdl:output');
    
$output->setAttribute('message''tns:'.$name.'Response');

    
$operation->appendChild($dom->createElement('wsdl:documentation',$doc));
    
$operation->appendChild($input);
    
$operation->appendChild($output);

    return 
$operation;
}

generateWsdl() method
public string generateWsdl(string $className, string $serviceUrl, string $encoding='UTF-8')
$className string class name
$serviceUrl string Web service URL
$encoding string encoding of the WSDL. Defaults to 'UTF-8'.
{return} string the generated WSDL
Source Code: framework/web/services/CWsdlGenerator.php#133 (show)
public function generateWsdl($className$serviceUrl$encoding='UTF-8')
{
    
$this->operations=array();
    
$this->types=array();
    
$this->messages=array();
    if(
$this->serviceName===null)
        
$this->serviceName=$className;
    if(
$this->namespace===null)
        
$this->namespace='urn:'.str_replace('\\','/',$className).'wsdl';

    
$reflection=new ReflectionClass($className);
    foreach(
$reflection->getMethods() as $method)
    {
        if(
$method->isPublic())
            
$this->processMethod($method);
    }

    return 
$this->buildDOM($serviceUrl,$encoding)->saveXML();
}

Generates the WSDL for the given class.

processMethod() method
protected void processMethod(ReflectionMethod $method)
$method ReflectionMethod method
Source Code: framework/web/services/CWsdlGenerator.php#156 (show)
protected function processMethod($method)
{
    
$comment=$method->getDocComment();
    if(
strpos($comment,'@soap')===false)
        return;
    
$comment=strtr($comment,array("\r\n"=>"\n","\r"=>"\n")); // make line endings consistent: win -> unix, mac -> unix

    
$methodName=$method->getName();
    
$comment=preg_replace('/^\s*\**(\s*?$|\s*)/m','',$comment);
    
$params=$method->getParameters();
    
$message=array();
    
$n=preg_match_all('/^@param\s+([\w\.]+(\[\s*\])?)\s*?(.*)$/im',$comment,$matches);
    if(
$n>count($params))
        
$n=count($params);
    for(
$i=0;$i<$n;++$i)
        
$message[$params[$i]->getName()]=array($this->processType($matches[1][$i]), trim($matches[3][$i])); // name => type, doc

    
$this->messages[$methodName.'Request']=$message;

    if(
preg_match('/^@return\s+([\w\.]+(\[\s*\])?)\s*?(.*)$/im',$comment,$matches))
        
$return=array($this->processType($matches[1]),trim($matches[2])); // type, doc
    
else
        
$return=null;
    
$this->messages[$methodName.'Response']=array('return'=>$return);

    if(
preg_match('/^\/\*+\s*([^@]*?)\n@/s',$comment,$matches))
        
$doc=trim($matches[1]);
    else
        
$doc='';
    
$this->operations[$methodName]=$doc;
}

processType() method
protected void processType(string $type)
$type string PHP variable type
Source Code: framework/web/services/CWsdlGenerator.php#191 (show)
protected function processType($type)
{
    if(isset(
self::$typeMap[$type]))
        return 
self::$typeMap[$type];
    elseif(isset(
$this->types[$type]))
        return 
is_array($this->types[$type]) ? 'tns:'.$type $this->types[$type];
    elseif((
$pos=strpos($type,'[]'))!==false// if it is an array
    
{
        
$type=substr($type,0,$pos);
        
$this->types[$type.'[]']='tns:'.$type.'Array';
        
$this->processType($type);
        return 
$this->types[$type.'[]'];
    }
    else 
// class type
    
{
        
$type=Yii::import($type,true);
        
$this->types[$type]=array();
        
$class=new ReflectionClass($type);
        
        foreach(
$class->getProperties() as $property)
        {
            
$comment=$property->getDocComment();
            if(
$property->isPublic() && strpos($comment,'@soap')!==false)
            {
                if(
preg_match('/@var\s+([\w\.]+(\[\s*\])?)\s*?(.*)$/mi',$comment,$matches))
                {
                    
// support nillable, minOccurs, maxOccurs attributes
                    
$nillable=$minOccurs=$maxOccurs=false;
                    if(
preg_match('/{(.+)}/',$matches[3],$attr))
                    {
                        
$matches[3]=str_replace($attr[0],'',$matches[3]);
                        if(
preg_match_all('/((\w+)\s*=\s*(\w+))/mi',$attr[1],$attr))
                        {
                            foreach(
$attr[2] as $id=>$prop)
                            {
                                if(
strcasecmp($prop,'nillable')===0)
                                    
$nillable=$attr[3][$id] ? 'true' 'false';
                                elseif(
strcasecmp($prop,'minOccurs')===0)
                                    
$minOccurs=(int)$attr[3][$id];
                                elseif(
strcasecmp($prop,'maxOccurs')===0)
                                    
$maxOccurs=(int)$attr[3][$id];
                            }
                        }
                    }
                    
$this->types[$type][$property->getName()]=array(
                        
$this->processType($matches[1]), // type
                        
trim($matches[3]),                 // doc
                        
$nillable,
                        
$minOccurs,
                        
$maxOccurs
                    
);
                }
            }
        }
        return 
'tns:'.$type;
    }
}

Be the first person to leave a comment

Please to leave your comment.