/** * Return the ArrayOf or simple type name based on the singular xsdtype and the nesting level * * @param string $singularType * @param int $level * @return string */ protected function _getTypeBasedOnNestingLevel($singularType, $level) { if ($level == 0) { // This is not an Array anymore, return the xsd simple type return $this->getContext()->getType($singularType); } else { return 'tns:' . str_repeat('ArrayOf', $level) . ucfirst(Wsdl::translateType($singularType)); } }
/** * Add a complex type by recursivly using all the class properties fetched via Reflection. * * @param string $type Name of the class to be specified * @return string XSD Type for the given PHP type */ public function addComplexType($type) { if (!class_exists($type)) { throw new Exception\InvalidArgumentException(sprintf('Cannot add a complex type %s that is not an object or where ' . 'class could not be found in \'DefaultComplexType\' strategy.', $type)); } if (($soapType = $this->scanRegisteredTypes($type)) !== null) { return $soapType; } $dom = $this->getContext()->toDomDocument(); $class = new \ReflectionClass($type); $soapTypeName = Soap\Wsdl::translateType($type); $soapType = 'tns:' . $soapTypeName; // Register type here to avoid recursion $this->getContext()->addType($type, $soapType); $defaultProperties = $class->getDefaultProperties(); $defaultProperties = $class->getDefaultProperties(); $complexType = $dom->createElement('xsd:complexType'); $complexType->setAttribute('name', $soapTypeName); $all = $dom->createElement('xsd:all'); foreach ($class->getProperties() as $property) { if ($property->isPublic() && preg_match_all('/@var\\s+([^\\s]+)/m', $property->getDocComment(), $matches)) { /** * @todo check if 'xsd:element' must be used here (it may not be compatible with using 'complexType' * node for describing other classes used as attribute types for current class */ $element = $dom->createElement('xsd:element'); $element->setAttribute('name', $propertyName = $property->getName()); $element->setAttribute('type', $this->getContext()->getType(trim($matches[1][0]))); // If the default value is null, then this property is nillable. if ($defaultProperties[$propertyName] === null) { $element->setAttribute('nillable', 'true'); } $all->appendChild($element); } } $complexType->appendChild($all); $this->getContext()->getSchema()->appendChild($complexType); return $soapType; }
/** * Add an ArrayOfType based on the xsd:complexType syntax if type[] is detected in return value doc comment. * * @param string $singularType e.g. '\MyNamespace\MyClassname' * @param string $type e.g. '\MyNamespace\MyClassname[]' * @return string tns:xsd-type e.g. 'tns:ArrayOfMyNamespace.MyClassname' */ protected function _addArrayOfComplexType($singularType, $type) { if (($soapType = $this->scanRegisteredTypes($type)) !== null) { return $soapType; } $xsdComplexTypeName = 'ArrayOf' . Wsdl::translateType($singularType); $xsdComplexType = 'tns:' . $xsdComplexTypeName; // Register type here to avoid recursion $this->getContext()->addType($type, $xsdComplexType); // Process singular type using DefaultComplexType strategy parent::addComplexType($singularType); // Add array type structure to WSDL document $dom = $this->getContext()->toDomDocument(); $complexType = $dom->createElement('xsd:complexType'); $complexType->setAttribute('name', $xsdComplexTypeName); $complexContent = $dom->createElement('xsd:complexContent'); $complexType->appendChild($complexContent); $xsdRestriction = $dom->createElement('xsd:restriction'); $xsdRestriction->setAttribute('base', 'soap-enc:Array'); $complexContent->appendChild($xsdRestriction); $xsdAttribute = $dom->createElement('xsd:attribute'); $xsdAttribute->setAttribute('ref', 'soap-enc:arrayType'); $xsdAttribute->setAttribute('wsdl:arrayType', 'tns:' . Wsdl::translateType($singularType) . '[]'); $xsdRestriction->appendChild($xsdAttribute); $this->getContext()->getSchema()->appendChild($complexType); return $xsdComplexType; }
/** * Add a function to the WSDL document. * * @param $function \Zend\Server\Reflection\AbstractFunction function to add * @param $wsdl \Zend\Soap\Wsdl WSDL document * @param $port object wsdl:portType * @param $binding object wsdl:binding * @return void */ protected function _addFunctionToWsdl($function, $wsdl, $port, $binding) { $uri = $this->getUri(); // We only support one prototype: the one with the maximum number of arguments $prototype = null; $maxNumArgumentsOfPrototype = -1; foreach ($function->getPrototypes() as $tmpPrototype) { $numParams = count($tmpPrototype->getParameters()); if ($numParams > $maxNumArgumentsOfPrototype) { $maxNumArgumentsOfPrototype = $numParams; $prototype = $tmpPrototype; } } if ($prototype === null) { throw new Exception\InvalidArgumentException("No prototypes could be found for the '" . $function->getName() . "' function"); } $functionName = Wsdl::translateType($function->getName()); // Add the input message (parameters) $args = array(); if ($this->_bindingStyle['style'] == 'document') { // Document style: wrap all parameters in a sequence element $sequence = array(); foreach ($prototype->getParameters() as $param) { $sequenceElement = array('name' => $param->getName(), 'type' => $wsdl->getType($param->getType())); if ($param->isOptional()) { $sequenceElement['nillable'] = 'true'; } $sequence[] = $sequenceElement; } $element = array('name' => $functionName, 'sequence' => $sequence); // Add the wrapper element part, which must be named 'parameters' $args['parameters'] = array('element' => $wsdl->addElement($element)); } else { // RPC style: add each parameter as a typed part foreach ($prototype->getParameters() as $param) { $args[$param->getName()] = array('type' => $wsdl->getType($param->getType())); } } $wsdl->addMessage($functionName . 'In', $args); $isOneWayMessage = false; if ($prototype->getReturnType() == "void") { $isOneWayMessage = true; } if ($isOneWayMessage == false) { // Add the output message (return value) $args = array(); if ($this->_bindingStyle['style'] == 'document') { // Document style: wrap the return value in a sequence element $sequence = array(); if ($prototype->getReturnType() != "void") { $sequence[] = array('name' => $functionName . 'Result', 'type' => $wsdl->getType($prototype->getReturnType())); } $element = array('name' => $functionName . 'Response', 'sequence' => $sequence); // Add the wrapper element part, which must be named 'parameters' $args['parameters'] = array('element' => $wsdl->addElement($element)); } else { if ($prototype->getReturnType() != "void") { // RPC style: add the return value as a typed part $args['return'] = array('type' => $wsdl->getType($prototype->getReturnType())); } } $wsdl->addMessage($functionName . 'Out', $args); } // Add the portType operation if ($isOneWayMessage == false) { $portOperation = $wsdl->addPortOperation($port, $functionName, 'tns:' . $functionName . 'In', 'tns:' . $functionName . 'Out'); } else { $portOperation = $wsdl->addPortOperation($port, $functionName, 'tns:' . $functionName . 'In', false); } $desc = $function->getDescription(); if (strlen($desc) > 0) { $wsdl->addDocumentation($portOperation, $desc); } // When using the RPC style, make sure the operation style includes a 'namespace' attribute (WS-I Basic Profile 1.1 R2717) if ($this->_bindingStyle['style'] == 'rpc' && !isset($this->_operationBodyStyle['namespace'])) { $this->_operationBodyStyle['namespace'] = '' . $uri; } // Add the binding operation $operation = $wsdl->addBindingOperation($binding, $functionName, $this->_operationBodyStyle, $this->_operationBodyStyle); $wsdl->addSoapOperation($operation, $uri . '#' . $functionName); // Add the function name to the list $this->_functions[] = $function->getName(); }