diff --git a/classes/BaseWsdlWriter.php b/classes/BaseWsdlWriter.php index 3d13cc9..3a6d055 100644 --- a/classes/BaseWsdlWriter.php +++ b/classes/BaseWsdlWriter.php @@ -154,8 +154,10 @@ private function addType(WsdlType &$wsdlType) $wsdlSequence = $this->createElement("sequence"); // Create WSDL Elements + /* @var $elements WsdlProperty[] */ $elements = $wsdlType->getElements(); foreach ($elements as &$element) { + /* @var $element WsdlProperty */ $wsdlElement = $this->createElement("element"); $wsdlElement->setAttribute("name", $element->name); if (WsdlType::isPrimitiveType($element->type)) { @@ -163,7 +165,10 @@ private function addType(WsdlType &$wsdlType) } else { $wsdlElement->setAttribute("type", "tns:" . $element->type); } - + if($element->usage && $element->usage=='optional'){ + $wsdlElement->setAttribute("minOccurs", "0"); + } + // Add WSDL Element to the Sequence $wsdlSequence->appendChild($wsdlElement); } @@ -268,8 +273,8 @@ private function addBindingOperation($operation) $binding = $this->getBinding(); $definition = $this->getDefinitionName(); - $soapAction = "urn:{$definition}#{$definition}Server#{$operation->name}"; - + $soapAction = $this->getWsdlDefinition()->getNameSpace()."{$operation->name}"; + // Create a new WSDL Operation $wsdlOperation = $this->createElement("operation"); $wsdlOperation->setAttribute("name", $operation->name); @@ -583,9 +588,12 @@ public function getDefinitionName() */ public function getClassName() { - $className = $this->getWsdlDefinition()->getClassFileName(); - $className = basename($className, ".inc"); - $className = basename($className, ".php"); + $className = $this->getWsdlDefinition()->getClassName(); + if(!$className){ + $className = $this->getWsdlDefinition()->getClassFileName(); + $className = basename($className, ".inc"); + $className = basename($className, ".php"); + } return $className; } diff --git a/classes/DocBlockParser.php b/classes/DocBlockParser.php index 3a5ce6b..1cb37f5 100644 --- a/classes/DocBlockParser.php +++ b/classes/DocBlockParser.php @@ -22,11 +22,11 @@ class DocBlockParser private static $docBlockTags = array( "@param" => array( - "regex" => "|@param\s+([a-zA-Z0-9\[\]]+)\s+\\\$([a-zA-Z0-9]+)\s+(.*)|", - "matches" => array("type", "name", "desc") + "regex" => "#@param\s+([_a-zA-Z0-9\[\]]+)\s+\\\$([_a-zA-Z0-9]+)(\=null|)\s+(.*)#", + "matches" => array("type", "name", "optional", "desc") ), "@return" => array( - "regex" => "|@return\s+([a-zA-Z0-9\[\]]+)\s+(.*)|", + "regex" => "|@return\s+([_a-zA-Z0-9\[\]]+)\s+(.*)|", "matches" => array("type", "desc") ), "@author" => array( @@ -37,14 +37,16 @@ class DocBlockParser "regex" => "|@internal\s+(.*)|", "matches" => array("usage") ), + "@var" => array( + "regex" => "|@var\s+([_a-zA-Z0-9\[\]]+)\s+(.*)|", + "matches" => array("type", "desc") + ) ); /** * Get the Type and Description Information for a Property * - * @param string $name The name of the Property - * @param string $className the name file which contains - * the Class that the property is defined + * @param ReflectionProperty $property The reflected property */ public static function getPropertyInfo(ReflectionProperty $property) { @@ -52,12 +54,23 @@ public static function getPropertyInfo(ReflectionProperty $property) $commentLine = $property->getDocComment(); if (strlen($commentLine)) { - if (preg_match("|/\*\*\s+@var\s+([a-zA-Z0-9\[\]]+)([^(\*/)]*)\*/|", $commentLine, $matches)) { - $info['type'] = $matches[1]; - if (isset($matches[2])) { - $info['desc'] = $matches[2]; + // parse docblock + $taginfoarr=self::getTagInfo($commentLine); + $info=array(); + // flatten the parsed data + foreach($taginfoarr as $taginfo){ + foreach($taginfo as $tag => $tagdata){ + foreach($tagdata as $key => $value){ + if($value){ + // trim value because it can contain newlines etc + $info[$key]=trim($value); + } } - return $info; + } + } + // if we found the type, return + if(isset($info['type'])){ + return $info; } } return null; @@ -72,7 +85,7 @@ public static function getPropertyInfo(ReflectionProperty $property) public static function getDescription($doc) { $tagRegex = self::getTagRegex(); - $lines = split("\n", self::stripCommentChars($doc)); + $lines = explode("\n", self::stripCommentChars($doc)); $desc = ""; foreach ($lines as $line) { @@ -101,8 +114,8 @@ public static function getTagInfo($doc) $currentTag = null; // Do a Line at a time - $lines = split("\n", self::stripCommentChars($doc)); - + $lines = explode("\n", self::stripCommentChars($doc)); + for ($i = 0, $c = count($lines); $i < $c; $i++) { // Loop through the Doc Tag list and Find Matches @@ -156,7 +169,7 @@ public static function getTagInfo($doc) private static function stripCommentChars($doc) { $out = ""; - $lines = split("\n", $doc); + $lines = explode("\n", $doc); foreach ($lines as $line) { $line = preg_replace("|^\s*/\**|", "", $line); $line = preg_replace("|^\s*\**|", "", $line); diff --git a/classes/WsdlDefinition.php b/classes/WsdlDefinition.php index 01623c5..7dee006 100644 --- a/classes/WsdlDefinition.php +++ b/classes/WsdlDefinition.php @@ -26,7 +26,10 @@ class WsdlDefinition /** @var string */ private $classFileName; + /** @var string */ + private $className; + /** @var string */ private $wsdlFileName; @@ -46,8 +49,10 @@ class WsdlDefinition /** @var string */ private $baseUrl; - - + /** @var string[] */ + private $typeMapping = array(); + + /** * Get the value of classFileName * @@ -58,6 +63,26 @@ public function getClassFileName() return $this->classFileName; } + /** + * Set the value of className + * + * @param string $className The value of className + */ + public function setClassName($className) + { + $this->className = $className; + } + + /** + * Get the value of className + * + * @return string The value of className + */ + public function getClassName() + { + return $this->className; + } + /** * Set the value of classFileName * @@ -174,4 +199,25 @@ public function setBaseUrl($baseUrl) $this->baseUrl = $baseUrl; } + + /** + * Get the value of typeMapping + * + * @return string[] The typeMapping as assoc array + */ + public function getTypeMapping() + { + return $this->typeMapping; + } + + /** + * Set the value of typeMapping + * + * @param string[] $mapping The value of typeMapping + */ + public function setTypeMapping($mapping) + { + $this->typeMapping = $mapping; + } + } diff --git a/classes/WsdlMethod.php b/classes/WsdlMethod.php index b8503ba..f6251db 100644 --- a/classes/WsdlMethod.php +++ b/classes/WsdlMethod.php @@ -10,6 +10,7 @@ */ require_once("WsdlPart.php"); +require_once("WsdlType.php"); /** * WSDL Generator for PHP5 @@ -25,6 +26,8 @@ class WsdlMethod private $desc = null; private $header = false; private $reqHeaders = array(); + + private $typeMapping = array(); private $params = array(); private $returnType = null; @@ -60,6 +63,16 @@ public function setDesc($desc) $this->desc = $desc; } + /** + * Set the Description of the Method + * + * @param string[] $mapping Assoc array with type mapping old => new + */ + public function setTypeMappings($mapping) + { + $this->typeMapping = $mapping; + } + /** * Set whether the Method represents a SOAP Body or Header element * @@ -122,7 +135,17 @@ public function resolveHeaders($wsdlMethods) public function addParameter($varType, $varName, $varDesc) { $param = new StdClass(); - + if (WsdlType::isArrayTypeClass($varType)) { + $varTypeCheck = WsdlType::stripArrayNotation($varType); + if(array_key_exists($varTypeCheck,$this->typeMapping)){ + $varType = $this->typeMapping[$varTypeCheck].'[]'; + } + }else{ + if(array_key_exists($varType,$this->typeMapping)){ + $varType = $this->typeMapping[$varType]; + } + } + $param->type = $varType; $param->name = $varName; $param->desc = $varDesc; @@ -138,6 +161,17 @@ public function addParameter($varType, $varName, $varDesc) */ public function setReturn($varType, $varDesc) { + if (WsdlType::isArrayTypeClass($varType)) { + $varTypeCheck = WsdlType::stripArrayNotation($varType); + if(array_key_exists($varTypeCheck,$this->typeMapping)){ + $varType = $this->typeMapping[$varTypeCheck].'[]'; + } + }else{ + if(array_key_exists($varType,$this->typeMapping)){ + $varType = $this->typeMapping[$varType]; + } + } + $this->returnType = $varType; $this->returnDesc = $varDesc; } diff --git a/classes/WsdlProperty.php b/classes/WsdlProperty.php index bfe76ed..e96f99f 100644 --- a/classes/WsdlProperty.php +++ b/classes/WsdlProperty.php @@ -23,6 +23,7 @@ class WsdlProperty public $type = null; public $name = null; public $description = null; + public $usage = null; public function setName($name) @@ -45,4 +46,9 @@ public function setDesc($desc) $this->description = $desc; } + public function setUsage($usage) + { + $this->usage = $usage; + } + } diff --git a/classes/WsdlType.php b/classes/WsdlType.php index a744c7b..6624a5e 100644 --- a/classes/WsdlType.php +++ b/classes/WsdlType.php @@ -20,12 +20,13 @@ */ class WsdlType { - + // see http://www.w3schools.com/Schema/schema_dtypes_string.asp for starting point on data types // The List of Primitive WSDL Types - private static $primitives = array('string', 'int', 'array', 'boolean', 'base64binary' ); - private static $badTypes = array('mixed', ''); - + private static $primitives = array("string", "int", "array", "boolean", "base64binary", "binary", "float", "date", "time", "datetime" ); + private static $badTypes = array("mixed", ""); + private $className = null; + private $orgClassName = null; private $properties = array(); private $isArray = false; @@ -34,13 +35,22 @@ class WsdlType * The Name of the Class * * + * @param string $className The Name of the Type + * @param string $unmappedClassName If the name of the type was mapped, set this to the original name */ - public function __construct($className) + public function __construct($className, $unmappedClassName=null) { if (self::isArrayTypeClass($className)) { $className = self::stripArrayNotation($className); $this->isArray = true; } + if(!is_null($unmappedClassName)){ + if($this->isArray){ + $this->orgClassName = self::stripArrayNotation($unmappedClassName); + }else{ + $this->orgClassName = $unmappedClassName; + } + } $this->className = $className; } @@ -74,6 +84,19 @@ public static function getArrayComplexTypeName($typeName) return "ArrayOf{$typeName}"; } + + /** + * Strip the Array syntax from the Class Name + * + * @param string $className The Array Type Class Name + * @return string The class name without the array notation + */ + public static function stripArrayNotation($className) + { + return substr($className, 0, (strlen($className) - 2)); + } + + /** * Get the Name of the Type @@ -116,7 +139,7 @@ public function getArrayTypeName() /** * Get The Elements for this Type * - * @return array The list of element objects + * @return WsdlProperty[] The list of element objects */ public function getElements() { @@ -179,12 +202,14 @@ public static function isPrimitiveType($type) * array of WsdlTypes for them... * * @param array The array of WsdlMethods + * @param array Optional assoc array of classmappings * @return array The array of WsdlTypes */ - public static function getComplexTypes(&$wsdlMethods) + public static function getComplexTypes(&$wsdlMethods, $classMappings=array()) { $wsdlTypes = array(); $argumentTypes = array(); + $invertedClassMappings = array_flip($classMappings); // Find the types used as arguments and return parameters to each SOAP method foreach ($wsdlMethods as &$method) { @@ -207,11 +232,15 @@ public static function getComplexTypes(&$wsdlMethods) // Recurse through each argument and return parameter for each method // to build a complete list of complexTypes required by all methods - $complexTypes = self::findComplexTypes($argumentTypes, array()); - + $complexTypes = self::findComplexTypes($argumentTypes, array(), $invertedClassMappings); + // Create WSDL type list foreach ($complexTypes as $complexType) { - $wsdlTypes[] = new WsdlType($complexType); + $orgClassName = null; + if(array_key_exists($complexType,$invertedClassMappings)){ + $orgClassName = $invertedClassMappings[$complexType]; + } + $wsdlTypes[] = new WsdlType($complexType, $orgClassName); } return $wsdlTypes; } @@ -225,11 +254,12 @@ public static function getComplexTypes(&$wsdlMethods) /** * Get the WSDL Properties from the Class File * - * @return array An array of properties + * @return WsdlProperty[] An array of properties */ private function getProperties() { - $reflect = new ReflectionClass($this->className); + $classname = (is_null($this->orgClassName)? $this->className : $this->orgClassName); + $reflect = new ReflectionClass($classname); $properties = $reflect->getProperties(); $wsdlProperties = array(); @@ -247,7 +277,7 @@ private function getProperties() * Get information for a Property * * @param ReflectionProperty $property The property to get Information for - * @return WsdlService The Service Information object + * @return WsdlProperty The Service Information object */ private static function getWsdlProperty(ReflectionProperty $property) { @@ -262,23 +292,16 @@ private static function getWsdlProperty(ReflectionProperty $property) $wsdlProperty->setName($property->getName()); $wsdlProperty->setType($propertyInfo['type']); $wsdlProperty->setDesc($propertyInfo['desc']); + if (isset($propertyInfo['optional'])){ + $wsdlProperty->setUsage("optional"); + } + if (isset($propertyInfo['usage'])){ + $wsdlProperty->setUsage($propertyInfo['usage']); + } return $wsdlProperty; } - - /** - * Strip the Array syntax from the Class Name - * - * @param string $className The Array Type Class Name - * @return string The class name without the array notation - */ - private static function stripArrayNotation($className) - { - return substr($className, 0, (strlen($className) - 2)); - } - - /** * Find all types needed to fully define the specified types and their properties * @@ -290,9 +313,10 @@ private static function stripArrayNotation($className) * * @param array $types List of types to iterate over * @param array $foundTypes List of types discovered so far + * @param array $invertedClassMappings Assoc array of class mappings $type => $org_classname * @return array List of types required to fully define all the types in $types */ - private static function findComplexTypes(&$types, $foundTypes) + private static function findComplexTypes(&$types, $foundTypes, $invertedClassMappings=array()) { // Iterate over each type foreach ($types as $type) { @@ -309,7 +333,8 @@ private static function findComplexTypes(&$types, $foundTypes) // Process objects only - not arrays if (!self::isArrayTypeClass($type)) { - $reflect = new ReflectionClass($type); + $classname = (array_key_exists($type,$invertedClassMappings)? $invertedClassMappings[$type] : $type); + $reflect = new ReflectionClass($classname); $properties = $reflect->getProperties(); $searchTypes = array(); @@ -322,7 +347,7 @@ private static function findComplexTypes(&$types, $foundTypes) // Iterate over all the found types to search their properties etc. if (count($searchTypes)) { - $foundTypes = self::findComplexTypes($searchTypes, $foundTypes); + $foundTypes = self::findComplexTypes($searchTypes, $foundTypes, $invertedClassMappings); } } @@ -331,7 +356,7 @@ private static function findComplexTypes(&$types, $foundTypes) // referenced anywhere else else { $searchTypes = array(self::stripArrayNotation($type)); - $foundTypes = self::findComplexTypes($searchTypes, $foundTypes); + $foundTypes = self::findComplexTypes($searchTypes, $foundTypes, $invertedClassMappings); } } } diff --git a/classes/WsdlWriter.php b/classes/WsdlWriter.php index bf1a020..20c8d34 100644 --- a/classes/WsdlWriter.php +++ b/classes/WsdlWriter.php @@ -47,7 +47,7 @@ public function classToWsdl() $wsdlMethods = $this->getMethods($className); // Find the Complex Types - $complexTypes = WsdlType::getComplexTypes($wsdlMethods); + $complexTypes = WsdlType::getComplexTypes($wsdlMethods, $this->getWsdlDefinition()->getTypeMapping()); foreach ($complexTypes as &$complexType) { $this->addComplexType($complexType); @@ -79,7 +79,10 @@ private function getMethods($className) || substr($method->getName(), 0, 2) == '__') { continue; } - $wsdlMethods[] = $this->getWsdlMethod($method); + // print "Found Method: " . $method->getName() . "\n"; + $wsdlmethod=$this->getWsdlMethod($method); + if(is_null($wsdlmethod)) continue; + $wsdlMethods[] = $wsdlmethod; } foreach ($wsdlMethods as $wsdlMethod) @@ -101,7 +104,8 @@ private function getWsdlMethod(ReflectionMethod $method) $wsdlMethod = new WsdlMethod(); $wsdlMethod->setName($method->getName()); $wsdlMethod->setDesc(DocBlockParser::getDescription($doc)); - + $wsdlMethod->setTypeMappings($this->getWsdlDefinition()->getTypeMapping()); + $params = DocBlockParser::getTagInfo($doc); for ($i = 0, $c = count($params); $i < $c; $i++) { @@ -114,15 +118,18 @@ private function getWsdlMethod(ReflectionMethod $method) break; case "@return": $wsdlMethod->setReturn($param['type'], $param['desc']); - break; - case "@internal": - if (trim(strtolower($param['usage'])) == 'soapheader') - $wsdlMethod->setIsHeader(true); - - if (substr(trim(strtolower($param['usage'])), 0, 13) == 'soaprequires ') - $wsdlMethod->setRequiredHeaders(explode(' ', substr(trim($param['usage']), 13))); - - break; + break; + case "@internal": + if (trim(strtolower($param['usage'])) == 'ignore') + return null; + + if (trim(strtolower($param['usage'])) == 'soapheader') + $wsdlMethod->setIsHeader(true); + + if (substr(trim(strtolower($param['usage'])), 0, 13) == 'soaprequires ') + $wsdlMethod->setRequiredHeaders(explode(' ', substr(trim($param['usage']), 13))); + + break; default: break; }