From 97dddf3cf23f7d2829d23efb9d44b746ac7d52cc Mon Sep 17 00:00:00 2001 From: knut <> Date: Thu, 6 Jul 2006 19:45:32 +0000 Subject: Added a TSoapService prototype with a simple demo app --- framework/3rdParty/WsdlGen/WsdlGenerator.php | 288 +++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 framework/3rdParty/WsdlGen/WsdlGenerator.php (limited to 'framework/3rdParty/WsdlGen/WsdlGenerator.php') diff --git a/framework/3rdParty/WsdlGen/WsdlGenerator.php b/framework/3rdParty/WsdlGen/WsdlGenerator.php new file mode 100644 index 00000000..958f5da4 --- /dev/null +++ b/framework/3rdParty/WsdlGen/WsdlGenerator.php @@ -0,0 +1,288 @@ + + * @version $Revision$ + * @package System.Web.Services.SOAP + */ + +require_once(dirname(__FILE__).'/Wsdl.php'); +require_once(dirname(__FILE__).'/WsdlMessage.php'); +require_once(dirname(__FILE__).'/WsdlOperation.php'); + +/** + * Generator for the wsdl. + * Special thanks to Cristian Losada for implementing the Complex Types section of the WSDL. + * @author Marcus Nyeholt + * @author Cristian Losada + * @version $Revision$ + */ +class WsdlGenerator +{ + /** + * The instance. + * 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 + */ + public static function getInstance() + { + if (is_null(self::$instance)) { + self::$instance = new WsdlGenerator(); + } + return self::$instance; + } + + /** + * Get the Wsdl generated + * @return string The Wsdl for this wsdl + */ + public function getWsdl() + { + 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 + * @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 + */ + public function generateWsdl($className, $serviceUri='') + { + $this->wsdlDocument = new Wsdl($className, $serviceUri); + + $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 + * @param string $serviceUri The URI of the service that handles this WSDL + */ + public static function generate($className, $serviceUri='') + { + $generator = WsdlGenerator::getInstance(); + $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 + */ + protected function processMethod(ReflectionMethod $method) + { + $comment = $method->getDocComment(); + + if (strpos($comment, '@soapmethod') === false) { + return; + } + $comment = preg_replace("/(^[\\s]*\\/\\*\\*) + |(^[\\s]\\*\\/) + |(^[\\s]*\\*?\\s) + |(^[\\s]*) + |(^[\\t]*)/ixm", "", $comment); + + $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['name'] = $match[2]; + $param['desc'] = $match[3]; + $params[] = $param; + } + else if (preg_match('/^@return\s+([\w\[\]()]+)\s*(.*)/i', $line, $match)) { + $gotParams = true; + $return['type'] = $this->convertType($match[1]); + $return['desc'] = $match[2]; + $return['name'] = 'return'; + } + } + else { + if (!$gotDesc) { + $methodDoc .= trim($line); + } + else if (!$gotParams) { + $params[count($params)-1]['desc'] .= trim($line); + } + else { + if ($line == '*/') continue; + $return['desc'] .= trim($line); + } + } + } + + $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 + * Cerebral Cortex (let me know and I'll remove asap). + * + * TODO: date and dateTime + * @param string $type The php type to convert + * @return string The XSD type. + */ + private function convertType($type) + { + switch ($type) { + case 'string': + case 'str': + return 'xsd:string'; + break; + case 'int': + case 'integer': + return 'xsd:int'; + break; + case 'float': + case 'double': + return 'xsd:float'; + break; + case 'boolean': + case 'bool': + return 'xsd:boolean'; + break; + case 'array': + return 'soap-enc:Array'; + break; + case 'object': + return 'xsd:struct'; + break; + case 'mixed': + return 'xsd:anyType'; + break; + case 'void': + return ''; + 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 + { + if(!isset($this->types[$type])) + $this->extractClassProperties($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 + */ + 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++) + { + $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); + $pos = strpos($file, '@var', $pos) + 5; + } + } + +} +?> \ No newline at end of file -- cgit v1.2.3