diff options
Diffstat (limited to 'framework')
| -rw-r--r-- | framework/3rdParty/WsdlGen/Wsdl.php | 102 | ||||
| -rw-r--r-- | framework/3rdParty/WsdlGen/WsdlGenerator.php | 97 | ||||
| -rw-r--r-- | framework/Exceptions/messages.txt | 9 | ||||
| -rw-r--r-- | framework/Web/Services/TSoapService.php | 569 | 
4 files changed, 607 insertions, 170 deletions
diff --git a/framework/3rdParty/WsdlGen/Wsdl.php b/framework/3rdParty/WsdlGen/Wsdl.php index dcccc5cd..55694438 100644 --- a/framework/3rdParty/WsdlGen/Wsdl.php +++ b/framework/3rdParty/WsdlGen/Wsdl.php @@ -16,7 +16,7 @@   */  /** - * Contains the dom object used to build up the wsdl. The  + * Contains the dom object used to build up the wsdl. The   * operations generated by the generator are stored in here until the getWsdl()   * method is called which builds and returns the generated XML string.   * @author 		Marcus Nyeholt		<tanus@users.sourceforge.net> @@ -29,51 +29,51 @@ class Wsdl  	 * @var 	string  	 */  	private $serviceName; -	 +  	/**  	 * The URI to find the service at. If empty, the current  	 * uri will be used (minus any query string)  	 */  	private $serviceUri; -	 +  	/**  	 * The complex types declarations  	 * @var 	ArrayObject  	 */  	private $types; -	 -	 + +  	/**  	 * A collection of SOAP operations -	 * @var 	ArrayObject +	 * @var 	array  	 */ -	private $operations; -	 +	private $operations=array(); +  	/**  	 * Wsdl DOMDocument that's generated.  	 */  	private $wsdl = null; -	 +  	/**  	 * The definitions created for the WSDL  	 */  	private $definitions = null; -	 +  	/**  	 * The target namespace variable?  	 */  	private $targetNamespace =''; -	 +  	/**  	 * The binding style (default at the moment)  	 */  	private $bindingStyle = 'rpc'; -	 +  	/**  	 * The binding uri  	 */  	private $bindingTransport = 'http://schemas.xmlsoap.org/soap/http'; -	 +  	/**  	 * Creates a new Wsdl thing  	 * @param 	string		$name the name of the service. @@ -87,13 +87,13 @@ class Wsdl  		$this->types = new ArrayObject();  		$this->targetNamespace = 'urn:'.$name.'wsdl';  	} -	 +  	public function getWsdl()  	{  		$this->buildWsdl();  		return $this->wsdl;  	} -	 +  	/**  	 * Generates the WSDL file into the $this->wsdl variable  	 */ @@ -105,37 +105,37 @@ class Wsdl                       xmlns:tns="'.$this->targetNamespace.'"                       xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"                       xmlns:xsd="http://www.w3.org/2001/XMLSchema" -                     xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/"></definitions>';		 +                     xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/"></definitions>';  		$dom = DOMDocument::loadXml($xml);  		$this->definitions = $dom->documentElement; -		 +  		$this->addTypes($dom); -	 +  		$this->addMessages($dom);  		$this->addPortTypes($dom);  		$this->addBindings($dom);  		$this->addService($dom); -		 +  		$this->wsdl = $dom->saveXML();  	} -	 +  	/**  	 * Adds complexType definitions to the document  	 * @param		DomDocument 		$dom		The document to add to  	 */  	public function addTypes(DomDocument $dom)  	{ -		if (!count($this->types)) return;				 -		$types = $dom->createElement('types');		 +		if (!count($this->types)) return; +		$types = $dom->createElement('types');  		$schema = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:schema');  		$schema->setAttribute('targetNamespace', $this->targetNamespace); -		foreach($this->types as $type => $elements)  +		foreach($this->types as $type => $elements)  		{  			$complexType = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:complexType'); -			$complexType->setAttribute('name', $type);		 +			$complexType->setAttribute('name', $type);  			if(substr($type, strlen($type) - 5, 5) == 'Array')  // if it's an array -			{   +			{  				$complexContent = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:complexContent');  				$restriction = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:restriction');  				$restriction->setAttribute('base', 'SOAP-ENC:Array'); @@ -144,27 +144,27 @@ class Wsdl  				$attribute->setAttribute('arrayType', 'tns:' . substr($type, 0, strlen($type) - 5) . '[]');  				$restriction->appendChild($attribute);  				$complexContent->appendChild($restriction); -				$complexType->appendChild($complexContent);							 -			}  -			else  +				$complexType->appendChild($complexContent); +			} +			else  			{  				$all = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:all'); -				foreach($elements as $elem)  +				foreach($elements as $elem)  				{  					$e = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:element'); -					$e->setAttribute('name', $elem['name']);				 +					$e->setAttribute('name', $elem['name']);  					$e->setAttribute('type', $elem['type']); -					$all->appendChild($e);	 +					$all->appendChild($e);  				}  				$complexType->appendChild($all); -			}			 +			}  			$schema->appendChild($complexType); -			$types->appendChild($schema);						 +			$types->appendChild($schema);  		} -				 +  		$this->definitions->appendChild($types);  	} -	 +  	/**  	 * Add messages for the service  	 * @param		DomDocument 		$dom		The document to add to @@ -175,7 +175,7 @@ class Wsdl  			$operation->setMessageElements($this->definitions, $dom);  		}  	} -	 +  	/**  	 * Add the port types for the service  	 * @param		DomDocument 		$dom		The document to add to @@ -184,14 +184,14 @@ class Wsdl  	{  		$portType = $dom->createElement('portType');  		$portType->setAttribute('name', $this->serviceName.'PortType'); -		 +  		$this->definitions->appendChild($portType);  		foreach ($this->operations as $operation) {  			$portOperation = $operation->getPortOperation($dom);  			$portType->appendChild($portOperation);  		}  	} -	 +  	/**  	 * Add the bindings for the service  	 * @param		DomDocument 		$dom		The document to add to @@ -201,20 +201,20 @@ class Wsdl  		$binding = $dom->createElement('binding');  		$binding->setAttribute('name', $this->serviceName.'Binding');  		$binding->setAttribute('type', 'tns:'.$this->serviceName.'PortType'); -		 +  		$soapBinding = $dom->createElementNS('http://schemas.xmlsoap.org/wsdl/soap/', 'soap:binding');  		$soapBinding->setAttribute('style', $this->bindingStyle);  		$soapBinding->setAttribute('transport', $this->bindingTransport);  		$binding->appendChild($soapBinding); -		 +  		$this->definitions->appendChild($binding); -		 +  		foreach ($this->operations as $operation) {  			$bindingOperation = $operation->getBindingOperation($dom, $this->targetNamespace, $this->bindingStyle);  			$binding->appendChild($bindingOperation);  		}  	} -	 +  	/**  	 * Add the service definition  	 * @param		DomDocument 		$dom		The document to add to @@ -223,20 +223,20 @@ class Wsdl  	{  		$service = $dom->createElement('service');  		$service->setAttribute('name', $this->serviceName.'Service'); -		 +  		$port = $dom->createElement('port');  		$port->setAttribute('name', $this->serviceName.'Port');  		$port->setAttribute('binding', 'tns:'.$this->serviceName.'Binding'); -		 +  		$soapAddress = $dom->createElementNS('http://schemas.xmlsoap.org/wsdl/soap/', 'soap:address');  		$soapAddress->setAttribute('location', $this->serviceUri);  		$port->appendChild($soapAddress); -		 +  		$service->appendChild($port); -		 -		$this->definitions->appendChild($service);		 + +		$this->definitions->appendChild($service);  	} -	 +  	/**  	 * Adds an operation to have port types and bindings output  	 * @param 		WsdlOperation		$operation 		The operation to add @@ -245,15 +245,15 @@ class Wsdl  	{  		$this->operations[] = $operation;  	} -	 +  	/**  	 * Adds complexTypes to the wsdl  	 * @param string 	$type 	Name of the type -	 * @param Array		$elements	Elements of the type (each one is an associative array('name','type'))	 +	 * @param Array		$elements	Elements of the type (each one is an associative array('name','type'))  	 */  	public function addComplexType($type, $elements)  	{ -		$this->types[$type] = $elements;	 +		$this->types[$type] = $elements;  	}  }  ?>
\ No newline at end of file diff --git a/framework/3rdParty/WsdlGen/WsdlGenerator.php b/framework/3rdParty/WsdlGen/WsdlGenerator.php index 3d788769..b7ab544d 100644 --- a/framework/3rdParty/WsdlGen/WsdlGenerator.php +++ b/framework/3rdParty/WsdlGen/WsdlGenerator.php @@ -20,7 +20,7 @@ require_once(dirname(__FILE__).'/WsdlMessage.php');  require_once(dirname(__FILE__).'/WsdlOperation.php');  /** - * Generator for the wsdl.  + * Generator for the wsdl.   * Special thanks to Cristian Losada for implementing the Complex Types section of the WSDL.   * @author 		Marcus Nyeholt		<tanus@users.sourceforge.net>   * @author 		Cristian Losada		<cristian@teaxul.com> @@ -33,37 +33,37 @@ class WsdlGenerator  	 * var		WsdlGenerator  	 */  	private static $instance; -	 +  	/**  	 * The name of this service (the classname)  	 * @var 	string  	 */  	private $serviceName = ''; -	 +  	/**  	 * The complex types to use in the wsdl  	 * @var 	Array  	 */  	private $types = array(); -	 +  	/**  	 * The operations available in this wsdl  	 * @var 	ArrayObject  	 */  	private $operations; -	 +  	/**  	 * The wsdl object.  	 * @var 	object  	 */  	private $wsdlDocument; -	 +  	/**  	 * The actual wsdl string  	 * @var 	string  	 */  	private $wsdl = ''; -	 +  	/**  	 * The singleton instance for the generator  	 */ @@ -74,7 +74,7 @@ class WsdlGenerator  		}  		return self::$instance;  	} -	 +  	/**  	 * Get the Wsdl generated  	 * @return 	string		The Wsdl for this wsdl @@ -83,10 +83,10 @@ class WsdlGenerator  	{  		return $this->wsdl;  	} -	 +  	/**  	 * Generates WSDL for a passed in class, and saves it in the current object. The -	 * WSDL can then be retrieved by calling  +	 * WSDL can then be retrieved by calling  	 * @param 	string		$className		The name of the class to generate for  	 * @param 	string		$serviceUri		The URI of the service that handles this WSDL  	 * @return 	void @@ -94,24 +94,24 @@ class WsdlGenerator  	public function generateWsdl($className, $serviceUri='')  	{  		$this->wsdlDocument = new Wsdl($className, $serviceUri); -					 -		$classReflect = new ReflectionClass($className);		 + +		$classReflect = new ReflectionClass($className);  		$methods = $classReflect->getMethods(); -		 +  		foreach ($methods as $method) {  			// Only process public methods  			if ($method->isPublic()) {  				$this->processMethod($method);  			}  		} -		 +  		foreach($this->types as $type => $elements) {  			$this->wsdlDocument->addComplexType($type, $elements);  		} -				 +  		$this->wsdl = $this->wsdlDocument->getWsdl();  	} -	 +  	/**  	 * Static method that generates and outputs the generated wsdl  	 * @param 		string		$className		The name of the class to export @@ -120,13 +120,13 @@ class WsdlGenerator  	public static function generate($className, $serviceUri='')  	{  		$generator = WsdlGenerator::getInstance(); -		$generator->generateWsdl($className, $serviceUri);		 +		$generator->generateWsdl($className, $serviceUri);  		//header('Content-type: text/xml');  		return $generator->getWsdl();  		//exit(); -		 +  	} -	 +  	/**  	 * Process a method found in the passed in class.  	 * @param 		ReflectionMethod		$method		The method to process @@ -134,7 +134,6 @@ class WsdlGenerator  	protected function processMethod(ReflectionMethod $method)  	{  		$comment = $method->getDocComment(); -		  		if (strpos($comment, '@soapmethod') === false) {  			return;  		} @@ -147,25 +146,25 @@ class WsdlGenerator  	    $comment = str_replace("\r", "", $comment);  	    $comment = preg_replace("/([\\t])+/", "\t", $comment);  	    $commentLines = explode("\n", $comment); -	     +  		$methodDoc = '';  		$params = array();  		$return = array();  		$gotDesc = false;  		$gotParams = false; -		 +  		foreach ($commentLines as $line) {  			if ($line == '') continue;  			if ($line{0} == '@') {  				$gotDesc = true;  				if (preg_match('/^@param\s+([\w\[\]()]+)\s+\$([\w()]+)\s*(.*)/i', $line, $match)) {  					$param = array(); -					$param['type'] = $this->convertType($match[1]);					 +					$param['type'] = $this->convertType($match[1]);  					$param['name'] = $match[2]; -					$param['desc'] = $match[3];					 +					$param['desc'] = $match[3];  					$params[] = $param;  				} -				else if (preg_match('/^@return\s+([\w\[\]()]+)\s*(.*)/i', $line, $match)) {			 +				else if (preg_match('/^@return\s+([\w\[\]()]+)\s*(.*)/i', $line, $match)) {  					$gotParams = true;  					$return['type'] = $this->convertType($match[1]);  					$return['desc'] = $match[2]; @@ -185,19 +184,19 @@ class WsdlGenerator  				}  			}  		} -		 +  		$methodName = $method->getName();  		$operation = new WsdlOperation($methodName, $methodDoc); -		 +  		$operation->setInputMessage(new WsdlMessage($methodName.'Request', $params));  		$operation->setOutputMessage(new WsdlMessage($methodName.'Response', array($return))); -		 +  		$this->wsdlDocument->addOperation($operation); -		 +  	} -	 +  	/** -	 * Converts from a PHP type into a WSDL type. This is borrowed from  +	 * Converts from a PHP type into a WSDL type. This is borrowed from  	 * Cerebral Cortex (let me know and I'll remove asap).  	 *  	 * TODO: date and dateTime @@ -234,55 +233,55 @@ class WsdlGenerator                   break;               case 'void':                   return ''; -             default:     +             default:               	 if(strpos($type, '[]'))  // if it is an array -             	 {  +             	 {               	 	$className = substr($type, 0, strlen($type) - 2);               	 	$type = $className . 'Array';               	 	$this->types[$type] = '';               	 	$this->convertType($className); -             	 }  -             	 else  +             	 } +             	 else               	 { -             	 	 if(!isset($this->types[$type]))  +             	 	 if(!isset($this->types[$type]))  	             		$this->extractClassProperties($type); -             	 }             	  -                 return 'tns:' . $type;    +             	 } +                 return 'tns:' . $type;           }  	} -	 +  	/**  	 * Extract the type and the name of all properties of the $className class and saves it in the $types array  	 * This method extract properties from PHPDoc formatted comments for variables. Unfortunately the reflectionproperty  	 * class doesn't have a getDocComment method to extract comments about it, so we have to extract the information  	 * about the variables manually. Thanks heaps to Cristian Losada for implementing this. -	 * @param string $className The name of the class   +	 * @param string $className The name of the class  	 */ -	private function extractClassProperties($className)  +	private function extractClassProperties($className)  	{  		// Lets get the class' file so we can read the full contents of it.  		$classReflect = new ReflectionClass($className); -		 +  		if (!file_exists($classReflect->getFileName())) {  			throw new Exception('Could not find class file for '.$className);  		} -		 +  		$file = file_get_contents($classReflect->getFileName());  		if ($file == '') {  			throw new Exception("File {$classReflect->getFileName()} could not be opened");  		} -		 +  		$pos = strpos($file, 'class ' . $className);  		$pos = strpos($file, '@var', $pos) + 5; -		for($t = 0; $pos > 5; $t++)  -		{	 +		for($t = 0; $pos > 5; $t++) +		{  			$type = $this->convertType(substr($file, $pos, strpos($file, ' ', $pos) - $pos));  			$pos = strpos($file, '$', $pos) + 1; -			$name = substr($file, $pos, strpos($file, ';', $pos) - $pos);			 -			$this->types[$className][$t] = array('type' => $type, 'name' => $name);   +			$name = substr($file, $pos, strpos($file, ';', $pos) - $pos); +			$this->types[$className][$t] = array('type' => $type, 'name' => $name);  			$pos = strpos($file, '@var', $pos) + 5;  		}  	} -	 +  }  ?>
\ No newline at end of file diff --git a/framework/Exceptions/messages.txt b/framework/Exceptions/messages.txt index d176b5f7..28b0b1e7 100644 --- a/framework/Exceptions/messages.txt +++ b/framework/Exceptions/messages.txt @@ -365,4 +365,11 @@ dbdatareader_rewind_invalid				= TDbDataReader is a forward-only stream. It can  dbtransaction_transaction_inactive		= TDbTransaction is inactive.
  directorycachedependency_directory_invalid = TDirectoryCacheDependency.Directory {0} does not refer to a valid directory.
 -cachedependencylist_cachedependency_required = Only objects implementing ICacheDependency can be added into TCacheDependencyList.
\ No newline at end of file +cachedependencylist_cachedependency_required = Only objects implementing ICacheDependency can be added into TCacheDependencyList.
 +
 +soapservice_configfile_invalid			= TSoapService.ConfigFile '{0}' does not exist. Note, it has to be specified in a namespace format and the file extension must be '.xml'.
 +soapservice_request_invalid				= SOAP server '{0}' not found.
 +soapservice_serverid_required			= <soap> element must have 'id' attribute.
 +soapservice_serverid_duplicated			= SOAP server ID '{0}' is duplicated.
 +soapserver_id_invalid					= Invalid SOAP server ID '{0}'. It should not end with '.wsdl'.
 +soapserver_version_invalid				= Invalid SOAP version '{0}'. It must be either '1.1' or '1.2'.
\ No newline at end of file diff --git a/framework/Web/Services/TSoapService.php b/framework/Web/Services/TSoapService.php index a2db2e27..b1b04998 100644 --- a/framework/Web/Services/TSoapService.php +++ b/framework/Web/Services/TSoapService.php @@ -1,101 +1,532 @@  <?php  /** - * TSoapService class file + * TSoapService and TSoapServer class file   *   * @author Knut Urdalen <knut.urdalen@gmail.com> - * @link http://www.pradosoft.com + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/   * @copyright Copyright © 2006 PradoSoft   * @license http://www.pradosoft.com/license/ + * @version $Id: $   * @package System.Web.Services   */ -//Prado::using('System.Web.Services.TWebService'); - -require_once dirname(__FILE__).'/../../3rdParty/WsdlGen/WsdlGenerator.php'; -  /**   * TSoapService class   * - * TSoapService provides + * TSoapService processes SOAP requests for a PRADO application. + * TSoapService requires PHP SOAP extension to be loaded. + * + * TSoapService manages a set of SOAP providers. Each SOAP provider + * is a class that implements a set of SOAP methods which are exposed + * to SOAP clients for remote invocation. TSoapService generates WSDL + * automatically for the SOAP providers by default. + * + * To use TSoapService, configure it in the application specification like following: + * <code> + *   <services> + *     <service id="soap" class="System.Web.Services.TSoapService"> + *       <soap id="stockquote" provider="MyStockQuote" /> + *     </service> + *   </services> + * </code> + * + * The above example specifies a single SOAP provider named "stockquote" + * whose class is "MyStockQuote". A SOAP client can then obtain the WSDL for + * this provider via the following URL: + * <code> + *   http://hostname/path/to/index.php?soap=stockquote.wsdl + * </code> + * + * The WSDL for the provider class "MyStockQuote" is generated based on special + * comment tags in the class. In particular, if a class method's comment + * contains the keyword "@soapmethod", it is considered to be a SOAP method + * and will be exposed to SOAP clients. For example, + * <code> + *   class MyStockQuote { + *      / ** + *       * @param string $symbol the stock symbol + *       * @return float the stock price + *       * @soapmethod + *       * / + *      public function getQuote($symbol) {...} + *   } + * </code> + * + * With the above SOAP provider, a typical SOAP client may call the method "getQuote" + * remotely like the following: + * <code> + *   $client=new SoapClient("http://hostname/path/to/index.php?soap=stockquote.wsdl"); + *   echo $client->getQuote("ibm"); + * </code> + * + * Each <soap> element in the application specification actually configures + * the properties of a SOAP server which defaults to {@link TSoapServer}. + * Therefore, any writable property of {@link TSoapServer} may appear as an attribute + * in the <soap> element. For example, the "provider" attribute refers to + * the {@link TSoapServer::setProvider Provider} property of {@link TSoapServer}. + * The following configuration specifies that the SOAP server is persistent within + * the user session (that means a MyStockQuote object will be stored in session) + * <code> + *   <services> + *     <service id="soap" class="System.Web.Services.TSoapService"> + *       <soap id="stockquote" provider="MyStockQuote" SessionPersistent="true" /> + *     </service> + *   </services> + * </code> + * + * You may also use your own SOAP server class by specifying the "class" attribute of <soap>.   *   * @author Knut Urdalen <knut.urdalen@gmail.com> + * @author Qiang Xue <qiang.xue@gmail.com> + * @package System.Web.Services + * @since 3.1 + */ +class TSoapService extends TService +{ +	const DEFAULT_SOAP_SERVER='TSoapServer'; +	const CONFIG_FILE_EXT='.xml'; +	private $_servers=array(); +	private $_configFile=null; +	private $_wsdlRequest=false; +	private $_serverID=null; + +	/** +	 * Constructor. +	 * Sets default service ID to 'soap'. +	 */ +	public function __construct() +	{ +		$this->setID('soap'); +	} + +	/** +	 * Initializes this module. +	 * This method is required by the IModule interface. +	 * @param TXmlElement configuration for this module, can be null +	 * @throws TConfigurationException if {@link getConfigFile ConfigFile} is invalid. +	 */ +	public function init($config) +	{ +		if($this->_configFile!==null) +		{ + 			if(is_file($this->_configFile)) + 			{ +				$dom=new TXmlDocument; +				$dom->loadFromFile($this->_configFile); +				$this->loadConfig($dom); +			} +			else +				throw new TConfigurationException('soapservice_configfile_invalid',$this->_configFile); +		} +		$this->loadConfig($config); + +		$this->resolveRequest(); +	} + +	/** +	 * Resolves the request parameter. +	 * It identifies the server ID and whether the request is for WSDL. +	 * @throws THttpException if the server ID cannot be found +	 * @see getServerID +	 * @see getIsWsdlRequest +	 */ +	protected function resolveRequest() +	{ +		$serverID=$this->getRequest()->getServiceParameter(); +		if(($pos=strrpos($serverID,'.wsdl'))===strlen($serverID)-5) +		{ +			$serverID=substr($serverID,0,$pos); +			$this->_wsdlRequest=true; +		} +		else +			$this->_wsdlRequest=false; +		$this->_serverID=$serverID; +		if(!isset($this->_servers[$serverID])) +			throw new THttpException(400,'soapservice_request_invalid',$serverID); +	} + +	/** +	 * Loads configuration from an XML element +	 * @param TXmlElement configuration node +	 * @throws TConfigurationException if soap server id is not specified or duplicated +	 */ +	private function loadConfig($xml) +	{ +		foreach($xml->getElementsByTagName('soap') as $serverXML) +		{ +			$properties=$serverXML->getAttributes(); +			if(($id=$properties->remove('id'))===null) +				throw new TConfigurationException('soapservice_serverid_required'); +			if(isset($this->_servers[$id])) +				throw new TConfigurationException('soapservice_serverid_duplicated',$id); +			$this->_servers[$id]=$properties; +		} +	} + +	/** +	 * @return string external configuration file. Defaults to null. +	 */ +	public function getConfigFile() +	{ +		return $this->_configFile; +	} + +	/** +	 * @param string external configuration file in namespace format. The file +	 * must be suffixed with '.xml'. +	 * @throws TInvalidDataValueException if the file is invalid. +	 */ +	public function setConfigFile($value) +	{ +		if(($this->_configFile=Prado::getPathOfNamespace($value,self::CONFIG_FILE_EXT))===null) +			throw new TConfigurationException('soapservice_configfile_invalid',$value); +	} + +	/** +	 * Constructs a URL with specified page path and GET parameters. +	 * @param string soap server ID +	 * @param array list of GET parameters, null if no GET parameters required +	 * @param boolean whether to encode the ampersand in URL, defaults to true. +	 * @param boolean whether to encode the GET parameters (their names and values), defaults to true. +	 * @return string URL for the page and GET parameters +	 */ +	public function constructUrl($serverID,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true) +	{ +		return $this->getRequest()->constructUrl($this->getID(),$serverID,$getParams,$encodeAmpersand,$encodeGetItems); +	} + +	/** +	 * @return boolean whether this is a request for WSDL +	 */ +	public function getIsWsdlRequest() +	{ +		return $this->_wsdlRequest; +	} + +	/** +	 * @return string the SOAP server ID +	 */ +	public function getServerID() +	{ +		return $this->_serverID; +	} + +	/** +	 * Creates the requested SOAP server. +	 * The SOAP server is initialized with the property values specified +	 * in the configuration. +	 * @return TSoapServer the SOAP server instance +	 */ +	protected function createServer() +	{ +		$properties=$this->_servers[$this->_serverID]; +		if(($serverClass=$properties->remove('class'))===null) +			$serverClass=self::DEFAULT_SOAP_SERVER; +		Prado::using($serverClass); +		$className=($pos=strrpos($serverClass,'.'))!==false?substr($serverClass,$pos+1):$serverClass; +		if($className!==self::DEFAULT_SOAP_SERVER && !is_subclass_of($className,self::DEFAULT_SOAP_SERVER)) +			throw new TConfigurationException('soapservice_server_invalid',$serverClass); +		$server=new $className; +		$server->setID($this->_serverID); +		foreach($properties as $name=>$value) +			$server->setSubproperty($name,$value); +		return $server; +	} + +	/** +	 * Runs the service. +	 * If the service parameter ends with '.wsdl', it will serve a WSDL file for +	 * the specified soap server. +	 * Otherwise, it will handle the soap request using the specified server. +	 */ +	public function run() +	{ +		Prado::trace("Running SOAP service",'System.Web.Services.TSoapService'); +		$server=$this->createServer(); +		if($this->getIsWsdlRequest()) +		{ +			// server WSDL file +			Prado::trace("Generating WSDL",'System.Web.Services.TSoapService'); +			$this->getResponse()->setContentType('text/xml'); +			$this->getResponse()->write($server->getWsdl()); +		} +		else +		{ +			// provide SOAP service +			Prado::trace("Handling SOAP request",'System.Web.Services.TSoapService'); +			$server->run(); +		} +	} +} + + +/** + * TSoapServer class. + * + * TSoapServer is a wrapper of the PHP SoapServer class. + * It associates a SOAP provider class to the SoapServer object. + * It also manages the URI for the SOAP service and WSDL. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: $   * @package System.Web.Services   * @since 3.1   */ -class TSoapService extends TService { +class TSoapServer extends TApplicationComponent +{ +	const WSDL_CACHE_PREFIX='wsdl.'; + +	private $_id; +	private $_provider; + +	private $_version=''; +	private $_actor=''; +	private $_encoding=''; +	private $_uri=''; +	private $_classMap; +	private $_persistent=false; +	private $_wsdlUri=''; + +	/** +	 * Constructor. +	 * It creates the classmap object. +	 */ +	public function __construct() +	{ +		$this->_classMap=new TAttributeCollection; +	} + +	/** +	 * @return string the ID of the SOAP server +	 */ +	public function getID() +	{ +		return $this->_id; +	} + +	/** +	 * @param string the ID of the SOAP server +	 * @throws TInvalidDataValueException if the ID ends with '.wsdl'. +	 */ +	public function setID($id) +	{ +		if(strrpos($this->_id,'.wsdl')===strlen($this->_id)-5) +			throw new TInvalidDataValueException('soapserver_id_invalid',$id); +		$this->_id=$id; +	} + +	/** +	 * Handles the SOAP request. +	 */ +	public function run() +	{ +		if(($provider=$this->getProvider())!==null) +		{ +			Prado::using($provider); +			$providerClass=($pos=strrpos($provider,'.'))!==false?substr($provider,$pos+1):$provider; +			$server=$this->createServer(); +			$server->setClass($providerClass); +			if($this->_persistent) +				$server->setPersistence(SOAP_PERSISTENCE_SESSION); +		} +		else +			$server=$this->createServer(); +		$server->handle(); +	} + +	/** +	 * Creates the SoapServer instance. +	 */ +	protected function createServer() +	{ +		return new SoapServer($this->getWsdlUri(),$this->getOptions()); +	} + +	/** +	 * @return array options for creating SoapServer instance +	 */ +	protected function getOptions() +	{ +		$options=array(); +		if($this->_version==='1.1') +			$options['soap_version']=SOAP_1_1; +		else if($this->_version==='1.2') +			$options['soap_version']=SOAP_1_2; +		if(!empty($this->_actor)) +			$options['actor']=$this->_actor; +		if(!empty($this->_encoding)) +			$options['encoding']=$this->_encoding; +		if(!empty($this->_uri)) +			$options['uri']=$this->_uri; +		if($this->_classMap->getCount()>0) +			$options['classmap']=$this->_classMap->toArray(); +		return $options; +	} + +	/** +	 * Returns the WSDL content of the SOAP server. +	 * If {@link getWsdlUri WsdlUri} is set, its content will be returned. +	 * If not, the {@link setProvider Provider} class will be investigated +	 * and the WSDL will be automatically genearted. +	 * @return string the WSDL content of the SOAP server +	 */ +	public function getWsdl() +	{ +		if($this->_wsdlUri==='') +		{ +			$provider=$this->getProvider(); +			$providerClass=($pos=strrpos($provider,'.'))!==false?substr($provider,$pos+1):$provider; +			Prado::using($provider); +			if($this->getApplication()->getMode()===TApplicationMode::Performance && ($cache=$this->getApplication()->getCache())!==null) +			{ +				$wsdl=$cache->get(self::WSDL_CACHE_PREFIX.$providerClass); +				if(is_string($wsdl)) +					return $wsdl; +				Prado::using('System.3rdParty.WsdlGen.WsdlGenerator'); +				$wsdl=WsdlGenerator::generate($providerClass, $this->getUri()); +				$cache->set(self::WSDL_CACHE_PREFIX.$providerClass,$wsdl); +				return $wsdl; +			} +			else +			{ +				Prado::using('System.3rdParty.WsdlGen.WsdlGenerator'); +				return WsdlGenerator::generate($providerClass, $this->getUri()); +			} +		} +		else +			return file_get_contents($this->_wsdlUri); +	} + +	/** +	 * @return string the URI for WSDL +	 */ +	public function getWsdlUri() +	{ +		if($this->_wsdlUri==='') +			return $this->getRequest()->getBaseUrl().$this->getService()->constructUrl($this->getID().'.wsdl',false); +		else +			return $this->_wsdlUri; +	} + +	/** +	 * @param string the URI for WSDL +	 */ +	public function setWsdlUri($value) +	{ +		$this->_wsdlUri=$value; +	} + +	/** +	 * @return string the URI for the SOAP service +	 */ +	public function getUri() +	{ +		if($this->_uri==='') +			return $this->getRequest()->getBaseUrl().$this->getService()->constructUrl($this->getID(),false); +		else +			return $this->_uri; +	} -  private $_class; +	/** +	 * @param string the URI for the SOAP service +	 */ +	public function setUri($uri) +	{ +		$this->_uri=$uri; +	} -  private $_server; // reference to the SOAP server +	/** +	 * @return string the SOAP provider class (in namespace format) +	 */ +	public function getProvider() +	{ +		return $this->_provider; +	} -  /** -   * Constructor. -   * Sets default service ID to 'soap'. -   */ -  public function __construct() { -    $this->setID('soap'); -  } +	/** +	 * @param string the SOAP provider class (in namespace format) +	 */ +	public function setProvider($provider) +	{ +		$this->_provider=$provider; +	} -  /** -   * Initializes the service. -   * This method is required by IService interface and is invoked by application. -   * @param TXmlElement service configuration -   */ -  public function init($config) { -    // nothing to do here -  } +	/** +	 * @return string SOAP version, defaults to empty (meaning not set). +	 */ +	public function getVersion() +	{ +		return $this->_version; +	} -  /** -   * Runs the service. -   *  -   * This will serve a WSDL-file of the Soap server if 'wsdl' is provided as a key in -   * the URL, else if will serve the Soap server. -   */ -  public function run() { -    Prado::trace("Running SOAP service",'System.Web.Services.TSoapService'); +	/** +	 * @param string SOAP version, either '1.1' or '1.2' +	 * @throws TInvalidDataValueException if neither '1.1' nor '1.2' +	 */ +	public function setVersion($value) +	{ +		if($value==='1.1' || $value==='1.2' || $value==='') +			$this->_version=$value; +		else +			throw new TInvalidDataValueException('soapserver_version_invalid',$value); +	} -    $this->setSoapServer($this->getRequest()->getServiceParameter()); -    Prado::using($this->getSoapServer()); // Load class +	/** +	 * @return string actor of the SOAP service +	 */ +	public function getActor() +	{ +		return $this->_actor; +	} -    // TODO: Fix protocol and host -    $uri = 'http://'.$_SERVER['HTTP_HOST'].$this->getRequest()->getRequestUri(); +	/** +	 * @param string actor of the SOAP service +	 */ +	public function setActor($value) +	{ +		$this->_actor=$value; +	} -    //print_r($this->getRequest()); -    if($this->getRequest()->itemAt('wsdl') !== null) { // Show WSDL-file -      // TODO: Check WSDL cache -      // Solution: Use Application Mode 'Debug' = no caching, 'Performance' = use cachez -      $uri = str_replace('&wsdl', '', $uri); // throw away the 'wsdl' key (this is a bit dirty) -      $uri = str_replace('wsdl', '', $uri); // throw away the 'wsdl' key (this is a bit dirty) -      $wsdl = WsdlGenerator::generate($this->_class, $uri); -      $this->getResponse()->setContentType('text/xml'); -      $this->getResponse()->write($wsdl); -    } else { // Provide service -      // TODO: use TSoapServer -      $this->_server = new SoapServer($uri.'&wsdl'); -      $this->_server->setClass($this->getSoapServer()); -      $this->_server->handle(); -    } -  } +	/** +	 * @return string encoding of the SOAP service +	 */ +	public function getEncoding() +	{ +		return $this->_encoding; +	} -  /** -   * @return TSoapServer -   */ -  public function getSoapServer() { -    return $this->_class; -  } +	/** +	 * @param string encoding of the SOAP service +	 */ +	public function setEncoding($value) +	{ +		$this->_encoding=$value; +	} -  /** -   * @param TSoapServer $class -   */ -  public function setSoapServer($class) { -    // TODO: ensure $class instanceof TSoapServer -    $this->_class = $class; -  } +	/** +	 * @return boolean whether the SOAP service is persistent within session. Defaults to false. +	 */ +	public function getSessionPersistent() +	{ +		return $this->_persistent; +	} -  public function getPersistence() { +	/** +	 * @param boolean whether the SOAP service is persistent within session. +	 */ +	public function setSessionPersistent($value) +	{ +		$this->_persistent=TPropertyValue::ensureBoolean($value); +	} -  } -   +	/** +	 * @return TAttributeCollection the class map for the SOAP service +	 */ +	public function getClassMap() +	{ +		return $this->_classMap; +	}  }  ?>
\ No newline at end of file  | 
