diff --git a/src/AutoDiscover.php b/src/AutoDiscover.php index 5dc3fc54..18c568d2 100644 --- a/src/AutoDiscover.php +++ b/src/AutoDiscover.php @@ -86,6 +86,12 @@ class AutoDiscover */ protected $discoveryStrategy; + /** + * Custom targetNamespace. + * @var Uri + */ + protected $targetNamespace; + /** * Constructor * @@ -408,7 +414,9 @@ protected function generateWsdl(array $reflectionMethods) $serviceName = $this->getServiceName(); - $wsdl = new $this->wsdlClass($serviceName, $uri, $this->strategy, $this->classMap); + $targetNamespace = $this->getTargetNamespace(); + + $wsdl = new $this->wsdlClass($serviceName, $uri, $this->strategy, $this->classMap, $targetNamespace); // The wsdl:types element must precede all other elements (WS-I Basic Profile 1.1 R2023) $wsdl->addSchemaTypeSection(); @@ -443,6 +451,7 @@ protected function generateWsdl(array $reflectionMethods) protected function addFunctionToWsdl($function, $wsdl, $port, $binding) { $uri = $this->getUri(); + $targetNamespace = $this->getTargetNamespace(); // We only support one prototype: the one with the maximum number of arguments $prototype = null; @@ -554,7 +563,7 @@ protected function addFunctionToWsdl($function, $wsdl, $port, $binding) // attribute (WS-I Basic Profile 1.1 R2717) $operationBodyStyle = $this->operationBodyStyle; if ($this->bindingStyle['style'] == 'rpc' && !isset($operationBodyStyle['namespace'])) { - $operationBodyStyle['namespace'] = '' . $uri; + $operationBodyStyle['namespace'] = '' . $targetNamespace; } // Add the binding operation @@ -563,7 +572,8 @@ protected function addFunctionToWsdl($function, $wsdl, $port, $binding) } else { $operation = $wsdl->addBindingOperation($binding, $functionName, $operationBodyStyle); } - $wsdl->addSoapOperation($operation, $uri . '#' . $functionName); + + $wsdl->addSoapOperation($operation, $targetNamespace . '#' . $functionName); } /** @@ -618,4 +628,40 @@ public function handle() header('Content-Type: text/xml'); echo $this->toXml(); } + + /** + * Set targetNamespace {@see https://www.w3.org/TR/wsdl#_document-n}. + * + * @param Uri\Uri|string $uri + * @return self + * @throws Exception\InvalidArgumentException + */ + public function setTargetNamespace($uri) + { + if (!is_string($uri) && !($uri instanceof Uri\Uri)) { + throw new Exception\InvalidArgumentException( + 'Argument to \Zend\Soap\AutoDiscover::setTargetNamespace should be string or \Zend\Uri\Uri instance.' + ); + } + + $uri = htmlspecialchars(trim($uri), ENT_QUOTES, 'UTF-8', false); + + if (empty($uri)) { + throw new Exception\InvalidArgumentException('targetNamespace is empty'); + } + + $this->targetNamespace = Uri\UriFactory::factory($uri); + + return $this; + } + + /** + * Return the current targetNamespace {@see https://www.w3.org/TR/wsdl#_document-n}. + * + * @return Uri\Uri + */ + public function getTargetNamespace() + { + return ($this->targetNamespace) ? $this->targetNamespace : $this->getUri(); + } } diff --git a/src/Wsdl.php b/src/Wsdl.php index 5d716813..43129103 100644 --- a/src/Wsdl.php +++ b/src/Wsdl.php @@ -77,6 +77,12 @@ class Wsdl */ protected $wsdl; + /** + * Custom targetNamespace. + * @var string + */ + protected $targetNamespace; + /** * @param string $name Name of the Web Service being Described * @param string|Uri $uri URI where the WSDL will be available @@ -88,7 +94,8 @@ public function __construct( $name, $uri, ComplexTypeStrategy $strategy = null, - array $classMap = [] + array $classMap = [], + $targetNamespace = null ) { if ($uri instanceof Uri) { $uri = $uri->toString(); @@ -96,8 +103,14 @@ public function __construct( $this->setUri($uri); + if (!$targetNamespace) { + $targetNamespace = $uri; + } + + $this->setTargetNamespace($targetNamespace); + $this->classMap = $classMap; - $this->dom = $this->getDOMDocument($name, $this->getUri()); + $this->dom = $this->getDOMDocument($name, $this->getUri(), $this->getTargetNamespace()); $this->wsdl = $this->dom->documentElement; $this->setComplexTypeStrategy($strategy ?: new Wsdl\ComplexTypeStrategy\DefaultComplexType); @@ -106,11 +119,12 @@ public function __construct( /** * Get the wsdl XML document with all namespaces and required attributes * - * @param string $uri * @param string $name + * @param string $uri + * @param string $targetNamespace * @return DOMDocument */ - protected function getDOMDocument($name, $uri = null) + protected function getDOMDocument($name, $uri = null, $targetNamespace = null) { $dom = new DOMDocument(); @@ -126,10 +140,12 @@ protected function getDOMDocument($name, $uri = null) $uri = $this->sanitizeUri($uri); $this->setAttributeWithSanitization($definitions, 'name', $name); - $this->setAttributeWithSanitization($definitions, 'targetNamespace', $uri); + + $targetNamespace = ($this->targetNamespace) ? $this->sanitizeUri($this->targetNamespace) : $uri; + $this->setAttributeWithSanitization($definitions, 'targetNamespace', $targetNamespace); $definitions->setAttributeNS(self::XML_NS_URI, 'xmlns:'. self::WSDL_NS, self::WSDL_NS_URI); - $definitions->setAttributeNS(self::XML_NS_URI, 'xmlns:'. self::TYPES_NS, $uri); + $definitions->setAttributeNS(self::XML_NS_URI, 'xmlns:'. self::TYPES_NS, $targetNamespace); $definitions->setAttributeNS(self::XML_NS_URI, 'xmlns:'. self::SOAP_11_NS, self::SOAP_11_NS_URI); $definitions->setAttributeNS(self::XML_NS_URI, 'xmlns:'. self::XSD_NS, self::XSD_NS_URI); $definitions->setAttributeNS(self::XML_NS_URI, 'xmlns:'. self::SOAP_ENC_NS, self::SOAP_ENC_URI); @@ -145,11 +161,11 @@ protected function getDOMDocument($name, $uri = null) */ public function getTargetNamespace() { - $targetNamespace = null; if ($this->wsdl !== null) { - $targetNamespace = $this->wsdl->getAttribute('targetNamespace'); + $this->targetNamespace = $this->wsdl->getAttribute('targetNamespace'); } - return $targetNamespace; + + return $this->targetNamespace; } /** @@ -718,7 +734,8 @@ public function addSchemaTypeSection() $this->schema = $this->dom->createElementNS(WSDL::XSD_NS_URI, 'schema'); $types->appendChild($this->schema); - $this->setAttributeWithSanitization($this->schema, 'targetNamespace', $this->getUri()); + $targetNamespace = ($this->targetNamespace) ? $this->targetNamespace : $this->getUri(); + $this->setAttributeWithSanitization($this->schema, 'targetNamespace', $targetNamespace); } return $this; @@ -919,4 +936,26 @@ public function addElement($element) return self::TYPES_NS . ':' . $element['name']; } + + /** + * Set target namespace for WSDL. + * + * @param string|Uri $uri + * @return $this + */ + public function setTargetNamespace($uri) + { + if ($uri instanceof Uri) { + $uri = $uri->toString(); + } + + $this->targetNamespace = $this->sanitizeUri($uri); + + if ($this->dom instanceof DOMDocument) { + $definitions = $this->dom->firstChild; + $this->setAttributeWithSanitization($definitions, 'targetNamespace', $this->targetNamespace); + } + + return $this; + } } diff --git a/test/AutoDiscoverTest.php b/test/AutoDiscoverTest.php index 1c33c96c..191982c1 100644 --- a/test/AutoDiscoverTest.php +++ b/test/AutoDiscoverTest.php @@ -1537,4 +1537,27 @@ public function assertAttributesOfNodes($attributes, $nodeList) } } } + + /** + * @dataProvider dataProviderValidUris + */ + public function testChangeTargetNamespace($uri, $expectedUri) + { + $this->server->setTargetNamespace($uri); + $this->bindWsdl($this->server->generate()); + + $this->assertEquals( + $expectedUri, + $this->dom->documentElement->getAttribute('targetNamespace') + ); + + $this->assertNotEquals( + $this->defaultServiceUri, + $this->dom->documentElement->getAttribute('targetNamespace') + ); + + $this->assertValidWSDL($this->dom); + + $this->testDocumentNodes(); + } } diff --git a/test/WsdlTest.php b/test/WsdlTest.php index 488c67b8..b9e6aac5 100644 --- a/test/WsdlTest.php +++ b/test/WsdlTest.php @@ -863,4 +863,21 @@ public function testAddElement() $this->assertEquals(count($element['sequence']), $n); } + + /** + * @dataProvider dataProviderForURITesting + * + * @param string $uri + * @param string|Uri $expectedUri + */ + public function testSetCustomTargetNamespaceAttribute( + $uri, + $expectedUri + ) { + $this->wsdl->setTargetNamespace($uri); + $this->testDocumentNodes(); + + $this->assertEquals($expectedUri, $this->dom->documentElement->getAttribute('targetNamespace')); + $this->assertEquals($expectedUri, $this->wsdl->getTargetNamespace()); + } }