diff options
| author | Patrick Seeger <pseeger@ccwn.org> | 2012-04-13 23:11:05 +0200 |
|---|---|---|
| committer | Patrick Seeger <pseeger@ccwn.org> | 2012-04-13 23:11:05 +0200 |
| commit | 341cc4dd9c53ffbfb863e026dd58549c1082c7a7 (patch) | |
| tree | 1bbbed20313bafb9b063b6b4d894fe580d8b000f /framework/web/services | |
Diffstat (limited to 'framework/web/services')
| -rw-r--r-- | framework/web/services/CWebService.php | 283 | ||||
| -rw-r--r-- | framework/web/services/CWebServiceAction.php | 132 | ||||
| -rw-r--r-- | framework/web/services/CWsdlGenerator.php | 419 |
3 files changed, 834 insertions, 0 deletions
diff --git a/framework/web/services/CWebService.php b/framework/web/services/CWebService.php new file mode 100644 index 0000000..c1de152 --- /dev/null +++ b/framework/web/services/CWebService.php @@ -0,0 +1,283 @@ +<?php +/** + * CWebService class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CWebService encapsulates SoapServer and provides a WSDL-based web service. + * + * PHP SOAP extension is required. + * + * CWebService makes use of {@link CWsdlGenerator} and can generate the WSDL + * on-the-fly without requiring you to write complex WSDL. + * + * To generate the WSDL based on doc comment blocks in the service provider class, + * call {@link generateWsdl} or {@link renderWsdl}. To process the web service + * requests, call {@link run}. + * + * @property string $methodName The currently requested method name. Empty if no method is being requested. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CWebService.php 3515 2011-12-28 12:29:24Z mdomba $ + * @package system.web.services + * @since 1.0 + */ +class CWebService extends CComponent +{ + const SOAP_ERROR=1001; + /** + * @var string|object the web service provider class or object. + * If specified as a class name, it can be a path alias. + */ + public $provider; + /** + * @var string the URL for WSDL. This is required by {@link run()}. + */ + public $wsdlUrl; + /** + * @var string the URL for the Web service. This is required by {@link generateWsdl()} and {@link renderWsdl()}. + */ + public $serviceUrl; + /** + * @var integer number of seconds that the generated WSDL can remain valid in cache. Defaults to 0, meaning no caching. + */ + public $wsdlCacheDuration=0; + /** + * @var string the ID of the cache application component that is used to cache the generated WSDL. + * Defaults to 'cache' which refers to the primary cache application component. + * Set this property to false if you want to disable caching WSDL. + */ + public $cacheID='cache'; + /** + * @var string encoding of the Web service. Defaults to 'UTF-8'. + */ + public $encoding='UTF-8'; + /** + * @var array a list of classes that are declared as complex types in WSDL. + * This should be an array with WSDL types as keys and names of PHP classes as values. + * A PHP class can also be specified as a path alias. + * @see http://www.php.net/manual/en/function.soap-soapserver-construct.php + */ + public $classMap=array(); + /** + * @var string actor of the SOAP service. Defaults to null, meaning not set. + */ + public $actor; + /** + * @var string SOAP version (e.g. '1.1' or '1.2'). Defaults to null, meaning not set. + */ + public $soapVersion; + /** + * @var integer the persistence mode of the SOAP server. + * @see http://www.php.net/manual/en/function.soap-soapserver-setpersistence.php + */ + public $persistence; + + private $_method; + + + /** + * Constructor. + * @param mixed $provider the web service provider class name or object + * @param string $wsdlUrl the URL for WSDL. This is required by {@link run()}. + * @param string $serviceUrl the URL for the Web service. This is required by {@link generateWsdl()} and {@link renderWsdl()}. + */ + public function __construct($provider,$wsdlUrl,$serviceUrl) + { + $this->provider=$provider; + $this->wsdlUrl=$wsdlUrl; + $this->serviceUrl=$serviceUrl; + } + + /** + * The PHP error handler. + * @param CErrorEvent $event the PHP error event + */ + public function handleError($event) + { + $event->handled=true; + $message=$event->message; + if(YII_DEBUG) + { + $trace=debug_backtrace(); + if(isset($trace[2]) && isset($trace[2]['file']) && isset($trace[2]['line'])) + $message.=' ('.$trace[2]['file'].':'.$trace[2]['line'].')'; + } + throw new CException($message,self::SOAP_ERROR); + } + + /** + * Generates and displays the WSDL as defined by the provider. + * @see generateWsdl + */ + public function renderWsdl() + { + $wsdl=$this->generateWsdl(); + header('Content-Type: text/xml;charset='.$this->encoding); + header('Content-Length: '.(function_exists('mb_strlen') ? mb_strlen($wsdl,'8bit') : strlen($wsdl))); + echo $wsdl; + } + + /** + * Generates the WSDL as defined by the provider. + * The cached version may be used if the WSDL is found valid in cache. + * @return string the generated WSDL + * @see wsdlCacheDuration + */ + public function generateWsdl() + { + $providerClass=is_object($this->provider) ? get_class($this->provider) : Yii::import($this->provider,true); + if($this->wsdlCacheDuration>0 && $this->cacheID!==false && ($cache=Yii::app()->getComponent($this->cacheID))!==null) + { + $key='Yii.CWebService.'.$providerClass.$this->serviceUrl.$this->encoding; + if(($wsdl=$cache->get($key))!==false) + return $wsdl; + } + $generator=new CWsdlGenerator; + $wsdl=$generator->generateWsdl($providerClass,$this->serviceUrl,$this->encoding); + if(isset($key)) + $cache->set($key,$wsdl,$this->wsdlCacheDuration); + return $wsdl; + } + + /** + * Handles the web service request. + */ + public function run() + { + header('Content-Type: text/xml;charset='.$this->encoding); + if(YII_DEBUG) + ini_set("soap.wsdl_cache_enabled",0); + $server=new SoapServer($this->wsdlUrl,$this->getOptions()); + Yii::app()->attachEventHandler('onError',array($this,'handleError')); + try + { + if($this->persistence!==null) + $server->setPersistence($this->persistence); + if(is_string($this->provider)) + $provider=Yii::createComponent($this->provider); + else + $provider=$this->provider; + + if(method_exists($server,'setObject')) + $server->setObject($provider); + else + $server->setClass('CSoapObjectWrapper',$provider); + + if($provider instanceof IWebServiceProvider) + { + if($provider->beforeWebMethod($this)) + { + $server->handle(); + $provider->afterWebMethod($this); + } + } + else + $server->handle(); + } + catch(Exception $e) + { + if($e->getCode()!==self::SOAP_ERROR) // non-PHP error + { + // only log for non-PHP-error case because application's error handler already logs it + // php <5.2 doesn't support string conversion auto-magically + Yii::log($e->__toString(),CLogger::LEVEL_ERROR,'application'); + } + $message=$e->getMessage(); + if(YII_DEBUG) + $message.=' ('.$e->getFile().':'.$e->getLine().")\n".$e->getTraceAsString(); + + // We need to end application explicitly because of + // http://bugs.php.net/bug.php?id=49513 + Yii::app()->onEndRequest(new CEvent($this)); + $server->fault(get_class($e),$message); + exit(1); + } + } + + /** + * @return string the currently requested method name. Empty if no method is being requested. + */ + public function getMethodName() + { + if($this->_method===null) + { + if(isset($HTTP_RAW_POST_DATA)) + $request=$HTTP_RAW_POST_DATA; + else + $request=file_get_contents('php://input'); + if(preg_match('/<.*?:Body[^>]*>\s*<.*?:(\w+)/mi',$request,$matches)) + $this->_method=$matches[1]; + else + $this->_method=''; + } + return $this->_method; + } + + /** + * @return array options for creating SoapServer instance + * @see http://www.php.net/manual/en/function.soap-soapserver-construct.php + */ + protected function getOptions() + { + $options=array(); + if($this->soapVersion==='1.1') + $options['soap_version']=SOAP_1_1; + else if($this->soapVersion==='1.2') + $options['soap_version']=SOAP_1_2; + if($this->actor!==null) + $options['actor']=$this->actor; + $options['encoding']=$this->encoding; + foreach($this->classMap as $type=>$className) + { + $className=Yii::import($className,true); + if(is_int($type)) + $type=$className; + $options['classmap'][$type]=$className; + } + return $options; + } +} + + +/** + * CSoapObjectWrapper is a wrapper class internally used when SoapServer::setObject() is not defined. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CWebService.php 3515 2011-12-28 12:29:24Z mdomba $ + * @package system.web.services + */ +class CSoapObjectWrapper +{ + /** + * @var object the service provider + */ + public $object=null; + + /** + * Constructor. + * @param object $object the service provider + */ + public function __construct($object) + { + $this->object=$object; + } + + /** + * PHP __call magic method. + * This method calls the service provider to execute the actual logic. + * @param string $name method name + * @param array $arguments method arguments + * @return mixed method return value + */ + public function __call($name,$arguments) + { + return call_user_func_array(array($this->object,$name),$arguments); + } +} + diff --git a/framework/web/services/CWebServiceAction.php b/framework/web/services/CWebServiceAction.php new file mode 100644 index 0000000..d4dfbc9 --- /dev/null +++ b/framework/web/services/CWebServiceAction.php @@ -0,0 +1,132 @@ +<?php +/** + * CWebServiceAction class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CWebServiceAction implements an action that provides Web services. + * + * CWebServiceAction serves for two purposes. On the one hand, it displays + * the WSDL content specifying the Web service APIs. On the other hand, it + * invokes the requested Web service API. A GET parameter named <code>ws</code> + * is used to differentiate these two aspects: the existence of the GET parameter + * indicates performing the latter action. + * + * By default, CWebServiceAction will use the current controller as + * the Web service provider. See {@link CWsdlGenerator} on how to declare + * methods that can be remotely invoked. + * + * Note, PHP SOAP extension is required for this action. + * + * @property CWebService $service The Web service instance. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CWebServiceAction.php 3426 2011-10-25 00:01:09Z alexander.makarow $ + * @package system.web.services + * @since 1.0 + */ +class CWebServiceAction extends CAction +{ + /** + * @var mixed the Web service provider object or class name. + * If specified as a class name, it can be a path alias. + * Defaults to null, meaning the current controller is used as the service provider. + * If the provider implements the interface {@link IWebServiceProvider}, + * it will be able to intercept the remote method invocation and perform + * additional tasks (e.g. authentication, logging). + */ + public $provider; + /** + * @var string the URL for the Web service. Defaults to null, meaning + * the URL for this action is used to provide Web services. + * In this case, a GET parameter named {@link serviceVar} will be used to + * deteremine whether the current request is for WSDL or Web service. + */ + public $serviceUrl; + /** + * @var string the URL for WSDL. Defaults to null, meaning + * the URL for this action is used to serve WSDL document. + */ + public $wsdlUrl; + /** + * @var string the name of the GET parameter that differentiates a WSDL request + * from a Web service request. If this GET parameter exists, the request is considered + * as a Web service request; otherwise, it is a WSDL request. Defaults to 'ws'. + */ + public $serviceVar='ws'; + /** + * @var array a list of PHP classes that are declared as complex types in WSDL. + * This should be an array with WSDL types as keys and names of PHP classes as values. + * A PHP class can also be specified as a path alias. + * @see http://www.php.net/manual/en/soapclient.soapclient.php + */ + public $classMap; + /** + * @var array the initial property values for the {@link CWebService} object. + * The array keys are property names of {@link CWebService} and the array values + * are the corresponding property initial values. + */ + public $serviceOptions=array(); + + private $_service; + + + /** + * Runs the action. + * If the GET parameter {@link serviceVar} exists, the action handle the remote method invocation. + * If not, the action will serve WSDL content; + */ + public function run() + { + $hostInfo=Yii::app()->getRequest()->getHostInfo(); + $controller=$this->getController(); + if(($serviceUrl=$this->serviceUrl)===null) + $serviceUrl=$hostInfo.$controller->createUrl($this->getId(),array($this->serviceVar=>1)); + if(($wsdlUrl=$this->wsdlUrl)===null) + $wsdlUrl=$hostInfo.$controller->createUrl($this->getId()); + if(($provider=$this->provider)===null) + $provider=$controller; + + $this->_service=$this->createWebService($provider,$wsdlUrl,$serviceUrl); + + if(is_array($this->classMap)) + $this->_service->classMap=$this->classMap; + + foreach($this->serviceOptions as $name=>$value) + $this->_service->$name=$value; + + if(isset($_GET[$this->serviceVar])) + $this->_service->run(); + else + $this->_service->renderWsdl(); + + Yii::app()->end(); + } + + /** + * Returns the Web service instance currently being used. + * @return CWebService the Web service instance + */ + public function getService() + { + return $this->_service; + } + + /** + * Creates a {@link CWebService} instance. + * You may override this method to customize the created instance. + * @param mixed $provider the web service provider class name or object + * @param string $wsdlUrl the URL for WSDL. + * @param string $serviceUrl the URL for the Web service. + * @return CWebService the Web service instance + */ + protected function createWebService($provider,$wsdlUrl,$serviceUrl) + { + return new CWebService($provider,$wsdlUrl,$serviceUrl); + } +}
\ No newline at end of file diff --git a/framework/web/services/CWsdlGenerator.php b/framework/web/services/CWsdlGenerator.php new file mode 100644 index 0000000..db0419e --- /dev/null +++ b/framework/web/services/CWsdlGenerator.php @@ -0,0 +1,419 @@ +<?php +/** + * CWsdlGenerator class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * 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: + * <ul> + * <li>str/string: maps to xsd:string;</li> + * <li>int/integer: maps to xsd:int;</li> + * <li>float/double: maps to xsd:float;</li> + * <li>bool/boolean: maps to xsd:boolean;</li> + * <li>date: maps to xsd:date;</li> + * <li>time: maps to xsd:time;</li> + * <li>datetime: maps to xsd:dateTime;</li> + * <li>array: maps to xsd:string;</li> + * <li>object: maps to xsd:struct;</li> + * <li>mixed: maps to xsd:anyType.</li> + * </ul> + * + * 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: + * <pre> + * typeName[]: maps to tns:typeNameArray + * </pre> + * + * The following is an example declaring a remote invokable method: + * <pre> + * / ** + * * A foo method. + * * @param string name of something + * * @param string value of something + * * @return string[] some array + * * @soap + * * / + * public function foo($name,$value) {...} + * </pre> + * + * And the following is an example declaring a class with remote accessible properties: + * <pre> + * class Foo { + * / ** + * * @var string name of foo + * * @soap + * * / + * public $name; + * / ** + * * @var Member[] members of foo + * * @soap + * * / + * public $members; + * } + * </pre> + * 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'. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CWsdlGenerator.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @package system.web.services + * @since 1.0 + */ +class CWsdlGenerator extends CComponent +{ + /** + * @var string 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. + */ + public $namespace; + /** + * @var string the name of the generated WSDL. + * If not set, it defaults to "urn:{$className}wsdl". + */ + public $serviceName; + + private $_operations; + private $_types; + private $_messages; + + /** + * Generates the WSDL for the given class. + * @param string $className class name + * @param string $serviceUrl Web service URL + * @param string $encoding encoding of the WSDL. Defaults to 'UTF-8'. + * @return string the generated WSDL + */ + 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:{$className}wsdl"; + + $reflection=new ReflectionClass($className); + foreach($reflection->getMethods() as $method) + { + if($method->isPublic()) + $this->processMethod($method); + } + + return $this->buildDOM($serviceUrl,$encoding)->saveXML(); + } + + /* + * @param ReflectionMethod $method method + */ + private function processMethod($method) + { + $comment=$method->getDocComment(); + if(strpos($comment,'@soap')===false) + return; + + $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; + } + + /* + * @param string $type PHP variable type + */ + private function processType($type) + { + static $typeMap=array( + 'string'=>'xsd:string', + 'str'=>'xsd:string', + 'int'=>'xsd:int', + 'integer'=>'xsd:integer', + 'float'=>'xsd:float', + 'double'=>'xsd:float', + 'bool'=>'xsd:boolean', + 'boolean'=>'xsd:boolean', + 'date'=>'xsd:date', + 'time'=>'xsd:time', + 'datetime'=>'xsd:dateTime', + 'array'=>'soap-enc:Array', + 'object'=>'xsd:struct', + 'mixed'=>'xsd:anyType', + ); + if(isset($typeMap[$type])) + return $typeMap[$type]; + else if(isset($this->_types[$type])) + return is_array($this->_types[$type]) ? 'tns:'.$type : $this->_types[$type]; + else if(($pos=strpos($type,'[]'))!==false) // if it is an array + { + $type=substr($type,0,$pos); + if(isset($typeMap[$type])) + $this->_types[$type.'[]']='xsd:'.$type.'Array'; + else + { + $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)) + $this->_types[$type][$property->getName()]=array($this->processType($matches[1]),trim($matches[3])); // name => type, doc + } + } + return 'tns:'.$type; + } + } + + /* + * @param string $serviceUrl Web service URL + * @param string $encoding encoding of the WSDL. Defaults to 'UTF-8'. + */ + private 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->loadXml($xml); + $this->addTypes($dom); + + $this->addMessages($dom); + $this->addPortTypes($dom); + $this->addBindings($dom); + $this->addService($dom,$serviceUrl); + + return $dom; + } + + /* + * @param DOMDocument $dom Represents an entire HTML or XML document; serves as the root of the document tree + */ + private 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).'[]'); + $restriction->appendChild($attribute); + $complexContent->appendChild($restriction); + $complexType->appendChild($complexContent); + } + else if(is_array($xmlType)) + { + $complexType->setAttribute('name',$phpType); + $all=$dom->createElement('xsd:all'); + foreach($xmlType as $name=>$type) + { + $element=$dom->createElement('xsd:element'); + $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); + } + + /* + * @param DOMDocument $dom Represents an entire HTML or XML document; serves as the root of the document tree + */ + private 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); + } + } + + /* + * @param DOMDocument $dom Represents an entire HTML or XML document; serves as the root of the document tree + */ + private 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)); + } + + /* + * @param DOMDocument $dom Represents an entire HTML or XML document; serves as the root of the document tree + * @param string $name method name + * @param string $doc doc + */ + private 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; + } + + /* + * @param DOMDocument $dom Represents an entire HTML or XML document; serves as the root of the document tree + */ + private 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)); + } + + /* + * @param DOMDocument $dom Represents an entire HTML or XML document; serves as the root of the document tree + * @param string $name method name + */ + private 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; + } + + /* + * @param DOMDocument $dom Represents an entire HTML or XML document; serves as the root of the document tree + * @param string $serviceUrl Web service URL + */ + private 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); + } +} |
