Spec-Zone.ru › Yii 1.1

CWsdlGenerator

Пакет system.web.services
Наследование класс CWsdlGenerator » CComponent
С момента 1.0
Исходный код framework/web/services/CWsdlGenerator.php
CWsdlGenerator генерирует WSDL для заданного класса сервиса.

Генерация WSDL основана на комментариях в файле класса сервиса. В частности, он распознаёт тег «@soap» в комментариях и извлекает определения методов и типов API.

В классе сервиса удалённо вызываемый метод должен быть публичным методом с блоком комментариев, содержащим тег «@soap». В комментарии необходимо указать тип и имя каждого входного параметра и тип возвращаемого значения в формате phpdoc.

CWsdlGenerator распознаёт следующие примитивные типы (регистрозависимые) в объявлениях параметров и возвращаемого значения:
  • str/string: сопоставляется с xsd:string;
  • int/integer: сопоставляется с xsd:int;
  • float/double: сопоставляется с xsd:float;
  • bool/boolean: сопоставляется с xsd:boolean;
  • date: сопоставляется с xsd:date;
  • time: сопоставляется с xsd:time;
  • datetime: сопоставляется с xsd:dateTime;
  • array: сопоставляется с xsd:string;
  • object: сопоставляется с xsd:struct;
  • mixed: сопоставляется с xsd:anyType.


Если тип не является примитивным типом, он рассматривается как тип класса, и CWsdlGenerator будет искать его объявления свойств. Учитываются только публичные свойства, и каждое из них должно быть связано с блоком комментариев, содержащим тег «@soap». В блоке комментариев необходимо указать тип свойства.

CWsdlGenerator распознаёт тип массива в следующем формате:
typeName[]: maps to tns:typeNameArray


Пример объявления удалённо вызываемого метода:
/ **
  * A foo method.
  * @param string name of something
  * @param string value of something
  * @return string[] some array
  * @soap
  * /
public function foo($name,$value) {...}


Пример объявления класса с удалённо доступными свойствами:
class Foo {
    / **
      * @var string name of foo {nillable=1, minOccurs=0, maxOccurs=2}
      * @soap
      * /
    public $name;
    / **
      * @var Member[] members of foo
      * @soap
      * /
    public $members;
}
В примере свойство 'members' представляет собой массив объектов 'Member'. Поскольку 'Member' не является примитивным типом, CWsdlGenerator продолжит поиск определения 'Member'.

Допускается определение дополнительных атрибутов (nillable, minOccurs, maxOccurs) для каждого свойства, заключив определения в фигурные скобки и разделив их запятыми:

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

где атрибут может быть одним из следующих:
  • nillable = [0|1|true|false]
  • minOccurs = n; где n>=0
  • maxOccurs = n; где [n>=0|unbounded]


Кроме того, каждому сложному типу данных можно назначить флаг индикатора soap, объявляющий специальное использование для такого типа данных. Индикатор soap должен быть объявлен в блоке комментариев с тегом «@soap-indicator». В настоящее время поддерживаются следующие индикаторы soap:
  • all - (по умолчанию) позволяет любой порядок сортировки дочерних узлов
  • sequence - все дочерние узлы в файле WSDL XML будут ожидаться в заданном порядке
  • choice - предоставленное значение может быть любым из дочерних элементов
Индикаторы группы также могут быть внедрены с помощью пользовательских определений soap в качестве узла XML в структуру WSDL.

В следующем примере класс Foo создаст узел XML <xsd:Foo><xsd:sequence> ... </xsd:sequence></xsd:Foo> с ожидаемыми дочерними атрибутами в определённом порядке.
/ *
  * @soap-indicator sequence
  * /
class Foo {
    ...
}
Подробнее об индикаторах soap см. http://www.w3schools.com/schema/schema_complex_indicators.asp.

Поскольку вариативность определений WSDL практически неограниченна, для внедрения любого пользовательского XML-строки в сгенерированный файл WSDL можно использовать специальный тег комментариев «@soap-wsdl». Если такой блок кода находится в блоке комментариев класса, то он будет использован вместо разбора и генерации стандартных атрибутов в классе. Это даёт практически неограниченную гибкость в определении структур данных любой сложности. Следующий пример определяет пользовательский фрагмент узла WSDL XML:
/ *
  * @soap-wsdl <xsd:sequence>
  * @soap-wsdl 	<xsd:element minOccurs="1" maxOccurs="1" nillable="false" name="name" type="xsd:string"/>
  * @soap-wsdl 	<xsd:choice minOccurs="1" maxOccurs="1" nillable="false">
  * @soap-wsdl 		<xsd:element minOccurs="1" maxOccurs="1" nillable="false" name="age" type="xsd:integer"/>
  * @soap-wsdl 		<xsd:element minOccurs="1" maxOccurs="1" nillable="false" name="date_of_birth" type="xsd:date"/>
  * @soap-wsdl 	</xsd:choice>
  * @soap-wsdl </xsd:sequence>
  * /
class User {
    / **
      * @var string User name {minOccurs=1, maxOccurs=1}
      * @soap
      * /
    public $name;
    / **
      * @var integer User age {nillable=0, minOccurs=1, maxOccurs=1}
      * @example 35
      * @soap
      * /
    public $age;
    / **
      * @var date User's birthday {nillable=0, minOccurs=1, maxOccurs=1}
      * @example 1980-05-27
      * @soap
      * /
    public $date_of_birth;
}
В приведенном выше примере генератор WSDL вставит в узел XML <xsd:User> блок кода, определённый строками @soap-wsdl.

Вставка в URL SOAP ссылки параметра «?makedoc» позволит генератору WSDL вывести удобное для человека описание всех сложных типов данных вместо файла WSDL XML. Каждый сложный тип описывается в отдельной таблице HTML и также распознаёт тег PHPDoc «@example». См. buildHtmlDocs().

Публичные свойства

Свойство Тип Описание Определено в
bindingStyle массив стиль soap:operation CWsdlGenerator
bindingTransport строка транспорт soap:operation CWsdlGenerator
namespace строка пространство имён, которое будет использоваться в сгенерированном WSDL. CWsdlGenerator
operationBodyStyle массив варианты стиля soap:body operation CWsdlGenerator
serviceName строка имя сгенерированного WSDL. CWsdlGenerator

Защищённые свойства

Свойство Тип Описание Определено в
elements массив CWsdlGenerator
messages массив Карта типов запросов и ответов для всех операций. CWsdlGenerator
operations массив Список распознанных SOAP-операций, которые станут удалённо доступными. CWsdlGenerator
typeMap CWsdlGenerator
types массив Список сложных типов, используемых операциями. CWsdlGenerator
END_OF_DOCUMENT_MARKER

Общедоступные методы

Метод Описание Определено в
__call() Вызывает метод с указанным именем, который не является методом класса. CComponent
__get() Возвращает значение свойства, список обработчиков событий или поведение на основе его имени. CComponent
__isset() Проверяет, является ли значение свойства null. CComponent
__set() Устанавливает значение свойства компонента. CComponent
__unset() Устанавливает свойство компонента в null. CComponent
asa() Возвращает объект поведения с указанным именем. CComponent
attachBehavior() Прикрепляет поведение к этому компоненту. CComponent
attachBehaviors() Прикрепляет список поведений к компоненту. CComponent
attachEventHandler() Прикрепляет обработчик событий к событию. CComponent
buildHtmlDocs() Генерирует удобную для человека HTML-документацию для сложных типов данных. CWsdlGenerator
canGetProperty() Определяет, может ли свойство быть прочитано. CComponent
canSetProperty() Определяет, может ли свойство быть установлено. CComponent
detachBehavior() Открепляет поведение от компонента. CComponent
detachBehaviors() Открепляет все поведения от компонента. CComponent
detachEventHandler() Открепляет существующий обработчик событий. CComponent
disableBehavior() Отключает прикрепленное поведение. CComponent
disableBehaviors() Отключает все прикрепленные поведения к этому компоненту. CComponent
enableBehavior() Включает прикрепленное поведение. CComponent
enableBehaviors() Включает все прикрепленные поведения к этому компоненту. CComponent
evaluateExpression() Вычисляет выражение PHP или обратный вызов в контексте этого компонента. CComponent
generateWsdl() Генерирует WSDL для данного класса. CWsdlGenerator
getEventHandlers() Возвращает список прикрепленных обработчиков событий для события. CComponent
hasEvent() Определяет, определено ли событие. CComponent
hasEventHandler() Проверяет, есть ли прикрепленные обработчики для события с заданным именем. CComponent
hasProperty() Определяет, определено ли свойство. CComponent
raiseEvent() Вызывает событие. CComponent

Защищенные методы

Метод Описание Определено в
addBindings() CWsdlGenerator
addMessages() CWsdlGenerator
addPortTypes() CWsdlGenerator
addService() CWsdlGenerator
addTypes() CWsdlGenerator
buildDOM() CWsdlGenerator
createOperationElement() CWsdlGenerator
createPortElement() CWsdlGenerator
getWsdlElementAttributes() Парсинг атрибутов nillable, minOccurs, maxOccurs CWsdlGenerator
injectDom() Импортирует пользовательский узел XML-источника в документ WSDL под указанный целевой узел. CWsdlGenerator
processMethod() CWsdlGenerator
processType() CWsdlGenerator

Подробное описание свойств

bindingStyle свойство

public array $bindingStyle;

стиль soap:operation

bindingTransport свойство

public string $bindingTransport;

транспорт soap:operation

elements свойство

protected array $elements;

messages свойство

protected array $messages;

Карта типов запроса и ответа для всех операций.

namespace свойство

public string $namespace;

пространство имен, используемое в сгенерированном WSDL. Если не задано, по умолчанию используется имя класса, для которого генерируется WSDL.

operationBodyStyle свойство

public array $operationBodyStyle;

варианты стиля soap:body операции

operations свойство

protected array $operations;

Список распознанных операций SOAP, которые будут доступны удаленно. Все методы с объявленным параметром @soap будут включены здесь в формате operation1 => description1, operation2 => description2, ..

serviceName свойство

public string $serviceName;

имя сгенерированного WSDL. Если не задано, по умолчанию используется "urn:{$className}wsdl".

typeMap свойство

protected static $typeMap;

types свойство

protected array $types;

Список сложных типов, используемых операциями. Если операция SOAP определяет сложный тип входных или выходных данных, все объекты включаются сюда, содержащие все подпараметры. Например, если операция SOAP «createUser» требует сложный объект «User», то объект «User» будет включен сюда с объявленными подпараметрами, такими как «firstname», «lastname» и т. д..

Подробное описание методов

addBindings() метод

protected void addBindings(DOMDocument $dom)
$dom DOMDocument Представляет весь документ HTML или XML; служит корнем дерева документа
Исходный код: framework/web/services/CWsdlGenerator.php#712 (показать)
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',$this->bindingStyle);
    
$soapBinding->setAttribute('transport',$this->bindingTransport);
    
$binding->appendChild($soapBinding);

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

    foreach(
$this->operations as $name=>$operation)
        
$binding->appendChild($this->createOperationElement($dom,$name,$operation['headers']));
}

addMessages() метод

protected void addMessages(DOMDocument $dom)
$dom DOMDocument Представляет весь документ HTML или XML; служит корнем дерева документа
Исходный код: framework/web/services/CWsdlGenerator.php#647 (показать)
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);
                if (isset(
$part['type']))
                {
                    
$partElement->setAttribute('type',$part['type']);
                }
                if (isset(
$part['element']))
                {
                    
$partElement->setAttribute('element',$part['element']);
                }
                
$element->appendChild($partElement);
            }
        }
        
$dom->documentElement->appendChild($element);
    }
}

addPortTypes() метод

protected void addPortTypes(DOMDocument $dom)
$dom DOMDocument Представляет весь HTML- или XML-документ; служит корнем дерева документа
Исходный код: framework/web/services/CWsdlGenerator.php#677 (показать)
protected function addPortTypes($dom)
{
    
$portType=$dom->createElement('wsdl:portType');
    
$portType->setAttribute('name',$this->serviceName.'PortType');
    
$dom->documentElement->appendChild($portType);
    foreach(
$this->operations as $name=>$operation)
        
$portType->appendChild($this->createPortElement($dom,$name,$operation['doc']));
}

addService() метод

protected void addService(DOMDocument $dom, string $serviceUrl)
$dom DOMDocument Представляет весь HTML- или XML-документ; служит корнем дерева документа
$serviceUrl string URL веб-сервиса
Исходный код: framework/web/services/CWsdlGenerator.php#796 (показать)
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() метод

protected void addTypes(DOMDocument $dom)
$dom DOMDocument Представляет весь HTML- или XML-документ; служит корнем дерева документа
Исходный код: framework/web/services/CWsdlGenerator.php#533 (показать)
protected function addTypes($dom)
{
    if(
$this->types===array() && $this->elements===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);

            
$arrayType = ($dppos=strpos($xmlType,':')) !==false ? substr($xmlType,$dppos + 1) : $xmlType; // strip namespace, if any
            
$arrayType = substr($arrayType,0,-5); // strip 'Array' from name
            
if ($this->operationBodyStyle['use'] == self::USE_ENCODED)
            {
                
$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',(isset(self::$typeMap[$arrayType]) ? 'xsd:' : 'tns:') .$arrayType.'[]');
                
                
$restriction->appendChild($attribute);
                
$complexContent->appendChild($restriction);
                
$complexType->appendChild($complexContent);
            }
            else
            {
                
$sequence=$dom->createElement('xsd:sequence');
                
$element=$dom->createElement('xsd:element');
                
$element->setAttribute('name','item');
                
$element->setAttribute('type',(isset(self::$typeMap[$arrayType]) ? self::$typeMap[$arrayType] : 'tns:'.$arrayType));
                
$element->setAttribute('minOccurs','0');
                
$element->setAttribute('maxOccurs','unbounded');
                
$sequence->appendChild($element);
                
$complexType->appendChild($sequence);
            }
        }
        elseif(
is_array($xmlType))
        {
            
$complexType->setAttribute('name',$phpType);
            if(
$xmlType['custom_wsdl']!==false)
            {
                
$custom_dom=new DOMDocument();
                
$custom_dom->loadXML('<root xmlns:xsd="http://www.w3.org/2001/XMLSchema">'.$xmlType['custom_wsdl'].'</root>');
                foreach(
$custom_dom->documentElement->childNodes as $el)
                    
$this->injectDom($dom,$complexType,$el);
            }else{
                
$all=$dom->createElement('xsd:' . $xmlType['indicator']);

                if(!
is_null($xmlType['minOccurs']))
                    
$all->setAttribute('minOccurs',$xmlType['minOccurs']);
                if(!
is_null($xmlType['maxOccurs']))
                    
$all->setAttribute('maxOccurs',$xmlType['maxOccurs']);
                if(!
is_null($xmlType['nillable']))
                    
$all->setAttribute('nillable',$xmlType['nillable']);

                foreach(
$xmlType['properties'] as $name=>$type)
                {
                    
$element=$dom->createElement('xsd:element');
                    if(!
is_null($type[3]))
                        
$element->setAttribute('minOccurs',$type[3]);
                    if(!
is_null($type[4]))
                        
$element->setAttribute('maxOccurs',$type[4]);
                    if(!
is_null($type[2]))
                        
$element->setAttribute('nillable',$type[2]);
                    
$element->setAttribute('name',$name);
                    
$element->setAttribute('type',$type[0]);
                    
$all->appendChild($element);
                }
                
$complexType->appendChild($all);
            }
        }
        
$schema->appendChild($complexType);
    }
    foreach(
$this->elements as $name=>$parameters)
    {
        
$element=$dom->createElement('xsd:element');
        
$element->setAttribute('name',$name);
        
$complexType=$dom->createElement('xsd:complexType');
        if (!empty(
$parameters))
        {
            
$sequence=$dom->createElement('xsd:sequence');
            foreach(
$parameters as $paramName=>$paramOpts)
            {
                
$innerElement=$dom->createElement('xsd:element');
                
$innerElement->setAttribute('name',$paramName);
                
$innerElement->setAttribute('type',$paramOpts['type']);
                if (isset(
$paramOpts['nillable']) && $paramOpts['nillable'])
                {
                    
$innerElement->setAttribute('nillable','true');
                }
                
$sequence->appendChild($innerElement);
            }
            
$complexType->appendChild($sequence);
        }
        
$element->appendChild($complexType);
        
$schema->appendChild($element);
    }
    
$types->appendChild($schema);
    
$dom->documentElement->appendChild($types);
}

buildDOM() метод

protected DOMDocument buildDOM(string $serviceUrl, string $encoding)
$serviceUrl string URL веб-сервиса
$encoding string кодировка WSDL. По умолчанию 'UTF-8'.
{return} DOMDocument
Исходный код: framework/web/services/CWsdlGenerator.php#506 (показать)
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;
}

buildHtmlDocs() метод

public void buildHtmlDocs(bool $return=false)
$return bool Если true, сгенерированный HTML-вывод будет возвращён, а не отправлен напрямую в буфер вывода
Исходный код: framework/web/services/CWsdlGenerator.php#830 (показать)
public function buildHtmlDocs($return=false)
{
    
$html='<html><head>';
    
$html.='<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
    
$html.='<style type="text/css">
table{border-collapse: collapse;background-color: #DDDDDD;}
tr{background-color: #FFFFFF;}
th{background-color: #EEEEEE;}
th, td{font-size: 12px;font-family: courier;padding: 3px;}
</style>'
;
    
$html.='</head><body>';
    
$html.='<h2>WSDL documentation for service '.$this->serviceName.'</h2>';
    
$html.='<p>Generated on '.date('d.m.Y H:i:s').'</p>';
    
$html.='<table border="0" cellspacing="1" cellpadding="1">';
    
$html.='<tr><td>';

    if(!empty(
$this->types))
    {
        foreach(
$this->types as $object=>$options){
            if(!
is_array($options) || empty($options) || !is_array($options['properties']) || empty($options['properties'])){
                continue;
            }
            
$params=$options['properties'];
            
$html.="\n\n<h3>Object: {$object}</h3>";
            
$html.='<table border="1" cellspacing="1" cellpadding="1">';
            
$html.='<tr><th>#</th><th>Attribute</th><th>Type</th><th>Nill</th><th>Min</th><th>Max</th><th>Description</th><th>Example</th></tr>';
            
$c=0;
            foreach(
$params as $param=>$prop){
                ++
$c;
                
$html.="\n<tr>"
                            
."\n\t<td>{$c}</td>"
                            
."\n\t<td>{$param}</td>"
                            
."\n\t<td>".(str_replace('xsd:','',$prop[0]))."</td>"
                            
."\n\t<td>".$prop[2]."</td>"
                            
."\n\t<td>".($prop[3]==null ? '&nbsp;' : $prop[3])."</td>"
                            
."\n\t<td>".($prop[4]==null ? '&nbsp;' : $prop[4])."</td>"
                            
."\n\t<td>{$prop[1]}</td>"
                            
."\n\t<td>".(trim($prop[5])=='' ? '&nbsp;' : $prop[5])."</td>"
                        
."\n</tr>";
            }
            
$html.="\n</table><br/>";
        }
    }
    else
        
$html.='No complex data type found!';

    
$html.='</td></tr></table></body></html>';

    if(
$return)
        return 
$html;

    echo 
$html;
    
Yii::app()->end(); // end the app to avoid conflict with text/xml header
}

Генерирует удобочитаемую HTML-документацию для сложных типов данных. Этот метод можно вызвать, добавив параметр URL «&makedoc» в ссылку URL, например, «http://www.mydomain.com/soap/create?makedoc», или просто вызвав из другого скрипта с аргументом $return=true.

Каждый сложный тип данных описывается в отдельной HTML-таблице, содержащей следующие столбцы:

  • # - идентификатор атрибута
  • Атрибут - имя атрибута, например, firstname
  • Тип - тип атрибута, например, integer, date, tns:SoapPovCalculationResultArray
  • Nill - true|false - указывает, является ли атрибут необязательным
  • Min - минимальное количество повторений
  • Max - максимальное количество повторений
  • Описание - Подробное описание атрибута.
  • Пример - Пример значения атрибута, если он предоставлен через PHPDoc свойство @example.

createOperationElement() метод

protected DOMElement createOperationElement(DOMDocument $dom, string $name, array $headers=NULL)
$dom DOMDocument Представляет весь HTML- или XML-документ; служит корнем дерева документа
$name string имя метода
$headers array массив типа array('input'=>array(MESSAGE,PART),'output=>array(MESSAGE,PART))
{return} DOMElement новая instance элемента wsdl:operation
Исходный код: framework/web/services/CWsdlGenerator.php#735 (показать)
protected function createOperationElement($dom,$name,$headers=null)
{
    
$operation=$dom->createElement('wsdl:operation');
    
$operation->setAttribute('name', $name);
    
$soapOperation=$dom->createElement('soap:operation');
    
$soapOperation->setAttribute('soapAction', $this->namespace.'#'.$name);
    if (
$this->bindingStyle == self::STYLE_RPC)
    {
        
$soapOperation->setAttribute('style', self::STYLE_RPC);
    }

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

    
$soapBody=$dom->createElement('soap:body');
    
$operationBodyStyle=$this->operationBodyStyle;
    if (
$this->bindingStyle == self::STYLE_RPC && !isset($operationBodyStyle['namespace']))
    {
        
$operationBodyStyle['namespace'] = $this->namespace;
    }
    foreach(
$operationBodyStyle as $attributeName=>$attributeValue)
    {
        
$soapBody->setAttribute($attributeName, $attributeValue);
    }
    
$input->appendChild($soapBody);
    
$output->appendChild(clone $soapBody);
    if (
is_array($headers))
    {
        if (isset(
$headers['input']) && is_array($headers['input']) && count($headers['input'])==2)
        {
            
$soapHeader = $dom->createElement('soap:header');
            foreach(
$operationBodyStyle as $attributeName=>$attributeValue) {
                
$soapHeader->setAttribute($attributeName, $attributeValue);
            }
            
$soapHeader->setAttribute('message', $headers['input'][0]);
            
$soapHeader->setAttribute('part', $headers['input'][1]);
            
$input->appendChild($soapHeader);
        }
        if (isset(
$headers['output']) && is_array($headers['output']) && count($headers['output'])==2)
        {
            
$soapHeader = $dom->createElement('soap:header');
            foreach(
$operationBodyStyle as $attributeName=>$attributeValue) {
                
$soapHeader->setAttribute($attributeName, $attributeValue);
            }
            
$soapHeader->setAttribute('message', $headers['output'][0]);
            
$soapHeader->setAttribute('part', $headers['output'][1]);
            
$output->appendChild($soapHeader);
        }
    }

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

    return 
$operation;
}

createPortElement() метод

protected DOMElement createPortElement(DOMDocument $dom, string $name, string $doc)
$dom DOMDocument Представляет весь HTML- или XML-документ; служит корнем дерева документа
$name string имя метода
$doc string doc
{return} DOMElement новый экземпляр элемента wsdl:operation, заполненный данными tns In/Out
Исходный код: framework/web/services/CWsdlGenerator.php#692 (показать)
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.'In');
    
$output=$dom->createElement('wsdl:output');
    
$output->setAttribute('message', 'tns:'.$name.'Out');

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

    return 
$operation;
}

generateWsdl() метод

public string generateWsdl(string $className, string $serviceUrl, string $encoding='UTF-8')
$className string имя класса
$serviceUrl string URL веб-сервиса
$encoding string кодировка WSDL. По умолчанию 'UTF-8'.
{return} string сгенерированный WSDL
Исходный код: framework/web/services/CWsdlGenerator.php#236 (показать)
public function generateWsdl($className, $serviceUrl, $encoding='UTF-8')
{
    
$this->operations=array();
    
$this->types=array();
    
$this->elements=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);
    }

    
$wsdl=$this->buildDOM($serviceUrl,$encoding)->saveXML();

    if(isset(
$_GET['makedoc']))
        
$this->buildHtmlDocs();

    return 
$wsdl;
}

Генерирует WSDL для данного класса.

getWsdlElementAttributes() метод

protected array getWsdlElementAttributes(string $comment)
$comment string Извлечённый комментарий PHPDoc
{return} array массив [nillable, minOccurs, maxOccurs]
Исходный код: framework/web/services/CWsdlGenerator.php#450 (показать)
protected function getWsdlElementAttributes($comment) {
    
$nillable=$minOccurs=$maxOccurs=null;
    if(
preg_match('/{(.+)}/',$comment,$attr))
    {
        if(
preg_match_all('/((\w+)\s*=\s*(\w+))/mi',$attr[1],$attr))
        {
            foreach(
$attr[2] as $id=>$prop)
            {
                
$prop=strtolower($prop);
                
$val=strtolower($attr[3][$id]);
                if(
$prop=='nillable'){
                    if(
$val=='false' || $val=='true')
                        
$nillable=$val;
                    else
                        
$nillable=$val ? 'true' : 'false';
                }elseif(
$prop=='minoccurs')
                    
$minOccurs=intval($val);
                elseif(
$prop=='maxoccurs')
                    
$maxOccurs=($val=='unbounded') ? 'unbounded' : intval($val);
            }
        }
    }
    return array(
        
'nillable'=>$nillable,
        
'minOccurs'=>$minOccurs,
        
'maxOccurs'=>$maxOccurs
    
);
}

Разбор атрибутов nillable, minOccurs, maxOccurs

injectDom() метод

protected void injectDom(DOMDocument $dom, DOMElement $target, DOMNode $source)
$dom DOMDocument Генерируемый XML-документ WSDL
$target DOMElement XML-узел, в который будет добавлен узел $source
$source DOMNode Исходный XML-узел, который будет импортирован
Исходный код: framework/web/services/CWsdlGenerator.php#485 (показать)
protected function injectDom(DOMDocument $dom, DOMElement $target, DOMNode $source)
{
    if (
$source->nodeType!=XML_ELEMENT_NODE)
        return;

    
$import=$dom->createElement($source->nodeName);

    foreach(
$source->attributes as $attr)
        
$import->setAttribute($attr->name,$attr->value);

    foreach(
$source->childNodes as $child)
        
$this->injectDom($dom,$import,$child);

    
$target->appendChild($import);
}

Импорт пользовательского XML-узла в WSDL-документ под указанным узлом-целью

processMethod() метод

protected void processMethod(ReflectionMethod $method)
$method ReflectionMethod метод
Исходный код: framework/web/services/CWsdlGenerator.php#265 (показать)
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();
    
$headers=array();
    
$n=preg_match_all('/^@param\s+([\w\.]+(\[\s*\])?)\s*?(.*)$/im',$comment,$matches);
    if(
$n>count($params))
        
$n=count($params);
    if (
$this->bindingStyle == self::STYLE_RPC)
    {
        for(
$i=0;$i<$n;++$i)
            
$message[$params[$i]->getName()]=array(
                
'type'=>$this->processType($matches[1][$i]),
                
'doc'=>trim($matches[3][$i]),
            );
    }
    else
    {
        
$this->elements[$methodName] = array();
        for(
$i=0;$i<$n;++$i)
            
$this->elements[$methodName][$params[$i]->getName()]=array(
                
'type'=>$this->processType($matches[1][$i]),
                
'nillable'=>$params[$i]->isOptional(),
            );
        
$message['parameters'] = array('element'=>'tns:'.$methodName);
    }

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

    
$n=preg_match_all('/^@header\s+([\w\.]+(\[\s*\])?)\s*?(.*)$/im',$comment,$matches);
    for(
$i=0;$i<$n;++$i)
    {
        
$name = $matches[1][$i];
        
$type = $this->processType($matches[1][$i]);
        
$doc = trim($matches[3][$i]);
        if (
$this->bindingStyle == self::STYLE_RPC)
        {
            
$headers[$name]=array($type,$doc);
        }
        else
        {
            
$this->elements[$name][$name]=array('type'=>$type);
            
$headers[$name] = array('element'=>$type);
        }
    }

    if (
$headers !== array())
    {
        
$this->messages[$methodName.'Headers']=$headers;
        
$headerKeys = array_keys($headers);
        
$firstHeaderKey = reset($headerKeys);
        
$firstHeader = $headers[$firstHeaderKey];
    }
    else
    {
        
$firstHeader = null;
    }

    if (
$this->bindingStyle == self::STYLE_RPC)
    {
        if(
preg_match('/^@return\s+([\w\.]+(\[\s*\])?)\s*?(.*)$/im',$comment,$matches))
            
$return=array(
                
'type'=>$this->processType($matches[1]),
                
'doc'=>trim($matches[2]),
            );
        else
            
$return=null;
        
$this->messages[$methodName.'Out']=array('return'=>$return);
    }
    else
    {
        if(
preg_match('/^@return\s+([\w\.]+(\[\s*\])?)\s*?(.*)$/im',$comment,$matches))
        {
            
$this->elements[$methodName.'Response'][$methodName.'Result']=array(
                
'type'=>$this->processType($matches[1]),
            );
        }
        
$this->messages[$methodName.'Out']=array('parameters'=>array('element'=>'tns:'.$methodName.'Response'));
    }

    if(
preg_match('/^\/\*+\s*([^@]*?)\n@/s',$comment,$matches))
        
$doc=trim($matches[1]);
    else
        
$doc='';
    
$this->operations[$methodName]=array(
        
'doc'=>$doc,
        
'headers'=>$firstHeader === null ? null : array('input'=>array($methodName.'Headers', $firstHeaderKey)),
    );
}

processType() метод

protected mixed|string processType(string $type)
$type string Тип PHP переменной
{return} mixed|string
Исходный код: framework/web/services/CWsdlGenerator.php#367 (показать)
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)
    {    
// array of types
        
$type=substr($type,0,$pos);
        
$this->types[$type.'[]']='tns:'.$type.'Array';
        
$this->processType($type);
        return 
$this->types[$type.'[]'];
    }
    else
    {    
// process class / complex type
        
$type=Yii::import($type,true);
        
$class=new ReflectionClass($type);

        
$comment=$class->getDocComment();
        
$comment=strtr($comment,array("\r\n"=>"\n","\r"=>"\n")); // make line endings consistent: win -> unix, mac -> unix
        
$comment=preg_replace('/^\s*\**(\s*?$|\s*)/m','',$comment);

        
// extract soap indicator flag, if defined, e.g. @soap-indicator sequence
        // see http://www.w3schools.com/schema/schema_complex_indicators.asp
        
if(preg_match('/^@soap-indicator\s+(\w+)\s*?(.*)$/im', $comment, $matches))
        {
            
$indicator=$matches[1];
            
$attributes=$this->getWsdlElementAttributes($matches[2]);
        }else{
            
$indicator='all';
            
$attributes=$this->getWsdlElementAttributes('');
        }

        
$custom_wsdl=false;
        if(
preg_match_all('/^@soap-wsdl\s+(\S.*)$/im',$comment,$matches)>0)
            
$custom_wsdl=implode("\n", $matches[1]);

        
$this->types[$type]=array(
            
'indicator'=>$indicator,
            
'nillable'=>$attributes['nillable'],
            
'minOccurs'=>$attributes['minOccurs'],
            
'maxOccurs'=>$attributes['maxOccurs'],
            
'custom_wsdl'=>$custom_wsdl,
            
'properties'=>array()
        );

        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))
                {
                    
$attributes=$this->getWsdlElementAttributes($matches[3]);

                    if(
preg_match('/{(.+)}/',$comment,$attr))
                        
$matches[3]=str_replace($attr[0],'',$matches[3]);

                    
// extract PHPDoc @example
                    
$example='';
                    if(
preg_match("/@example[:]?(.+)/mi",$comment,$match))
                        
$example=trim($match[1]);

                    
$this->types[$type]['properties'][$property->getName()]=array(
                        
$this->processType($matches[1]),
                        
trim($matches[3]),
                        
$attributes['nillable'],
                        
$attributes['minOccurs'],
                        
$attributes['maxOccurs'],
                        
$example
                    
); // name => type, doc, nillable, minOccurs, maxOccurs, example
                
}
            }
        }
        return 
'tns:'.$type;
    }
}

© 2008–2017 by Yii Software LLC
Licensed under the three clause BSD license.
http://www.yiiframework.com/doc/api/1.1/CWsdlGenerator

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API