summaryrefslogtreecommitdiff
path: root/framework
diff options
context:
space:
mode:
authorxue <>2007-01-01 17:09:55 +0000
committerxue <>2007-01-01 17:09:55 +0000
commitfac69c59fab801bdc793cd500492f23d69427c33 (patch)
treec5462df88304cd7433e355815eec302187c15e62 /framework
parent279aa3bb883563d26ce316563ee3ef083f9905da (diff)
added TSoapService and TSoapServer.
Diffstat (limited to 'framework')
-rw-r--r--framework/3rdParty/WsdlGen/Wsdl.php102
-rw-r--r--framework/3rdParty/WsdlGen/WsdlGenerator.php97
-rw-r--r--framework/Exceptions/messages.txt9
-rw-r--r--framework/Web/Services/TSoapService.php593
4 files changed, 619 insertions, 182 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 &copy; 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 {
-
- private $_class;
-
- private $_server; // reference to the SOAP server
-
- /**
- * Constructor.
- * Sets default service ID to 'soap'.
- */
- public function __construct() {
- $this->setID('soap');
- }
-
- /**
- * 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
- }
-
- /**
- * 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');
-
- $this->setSoapServer($this->getRequest()->getServiceParameter());
- Prado::using($this->getSoapServer()); // Load class
-
- // TODO: Fix protocol and host
- $uri = 'http://'.$_SERVER['HTTP_HOST'].$this->getRequest()->getRequestUri();
-
- //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 TSoapServer
- */
- public function getSoapServer() {
- return $this->_class;
- }
-
- /**
- * @param TSoapServer $class
- */
- public function setSoapServer($class) {
- // TODO: ensure $class instanceof TSoapServer
- $this->_class = $class;
- }
-
- public function getPersistence() {
-
- }
-
+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;
+ }
+
+ /**
+ * @param string the URI for the SOAP service
+ */
+ public function setUri($uri)
+ {
+ $this->_uri=$uri;
+ }
+
+ /**
+ * @return string the SOAP provider class (in namespace format)
+ */
+ public function getProvider()
+ {
+ return $this->_provider;
+ }
+
+ /**
+ * @param string the SOAP provider class (in namespace format)
+ */
+ public function setProvider($provider)
+ {
+ $this->_provider=$provider;
+ }
+
+ /**
+ * @return string SOAP version, defaults to empty (meaning not set).
+ */
+ public function getVersion()
+ {
+ return $this->_version;
+ }
+
+ /**
+ * @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);
+ }
+
+ /**
+ * @return string actor of the SOAP service
+ */
+ public function getActor()
+ {
+ return $this->_actor;
+ }
+
+ /**
+ * @param string actor of the SOAP service
+ */
+ public function setActor($value)
+ {
+ $this->_actor=$value;
+ }
+
+ /**
+ * @return string encoding of the SOAP service
+ */
+ public function getEncoding()
+ {
+ return $this->_encoding;
+ }
+
+ /**
+ * @param string encoding of the SOAP service
+ */
+ public function setEncoding($value)
+ {
+ $this->_encoding=$value;
+ }
+
+ /**
+ * @return boolean whether the SOAP service is persistent within session. Defaults to false.
+ */
+ public function getSessionPersistent()
+ {
+ return $this->_persistent;
+ }
+
+ /**
+ * @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