I'm trying to implement a SOAP server using Zend_Soap_Server
class in PHP.
Here's the webservice.php
file which is the entry point of request:
<?php
require_once 'library.php';
require_once 'Zend/Loader/Autoloader.php';
$autoloader = \Zend_Loader_Autoloader::getInstance();
class Math
{
/**
* This method takes ...
*
* @param integer $inputParam
* @return \Library\IncrementedInt
*/
public function increment($inputParam)
{
return new \Library\IncrementedInt($inputParam);
}
}
$options = array('uri' => 'http://localhost' . $_SERVER['REQUEST_URI']);
if (isset($_GET['wsdl'])){
$server = new Zend_Soap_AutoDiscover();
$server->setClass('Math');
}
else {
$server = new Zend_Soap_Server(null, $options);
$server->setClass('Math');
$server->setObject(new Math());
}
$server->handle();
And I've got library.php
file like this:
<?php
namespace Library;
class IncrementedInt
{
public $original;
public $incremented;
public function __construct($num)
{
$this->original = $num;
$this->incremented = ++$num;
}
}
A call to http://localhost/webservice.php?wsdl
will output:
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://localhost/webservice.php" 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/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" name="Math" targetNamespace="http://localhost/webservice.php">
<script/>
<types>
<xsd:schema targetNamespace="http://localhost/webservice.php">
<xsd:complexType name="\Library\IncrementedInt">
<xsd:all/>
</xsd:complexType>
</xsd:schema>
</types>
<portType name="MathPort">
<operation name="increment">
<documentation>This method takes ...</documentation>
<input message="tns:incrementIn"/>
<output message="tns:incrementOut"/>
</operation>
</portType>
<binding name="MathBinding" type="tns:MathPort">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="increment">
<soap:operation soapAction="http://localhost/webservice.php#increment"/>
<input>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/webservice.php"/>
</input>
<output>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/webservice.php"/>
</output>
</operation>
</binding>
<service name="MathService">
<port name="MathPort" binding="tns:MathBinding">
<soap:address location="http://localhost/webservice.php"/>
</port>
</service>
<message name="incrementIn">
<part name="inputParam" type="xsd:int"/>
</message>
<message name="incrementOut">
<part name="return" type="tns:\Library\IncrementedInt"/>
</message>
</definitions>
Now to test the functionality I use soapUI 4.5.1
which is a Java application that implements a SOAP Client. Giving it the URI http://localhost/webservice.php?wsdl
should lead to function increment
extracted but it won't. Instead it prompts an error: The Value '\Library\IncrementInt' is an invalid name
. It seems to me that it's having a problem accepting \
as a part of a type name. On the other hand PHP can not do without them.
To make sure that everything else is OK, I tested the exact same files without the namespace and it works smoothly.
Has anyone faced a similar problem and more importantly, does anyone know how to overcome this problem?
[UPDATE]
I managed to test the same scenario with ZF2 and it works. Perhaps I have to give up on ZF1!
The XSD object type \Library\IncrementedInt
is not a PHP class within a PHP namespace like you outline:
<?php
namespace Library;
class IncrementedInt
{
...
The prefixed type actualy is:
tns:\Library\IncrementedInt
And mind the tns:
in front which is the prefix. You could not express is in PHP which becomes even more clear when you expand it to it's namespace URI:
{http://localhost/webservice.php}\Library\IncrementedInt
Also Zend SOAP comes from a time before PHP Namespaces (PHP 5.2), therefore it needs to take a different strategy to alias this type to a PHP type (classname). It takes the local-name of the type:
\Library\IncrementedInt
And replaces each "invalid" character in that type-name with an underscore:
_Library_IncrementedInt
You therefore need to name the class that way:
<?php
class _Library_IncrementedInt
{
...
If you want to have it working out of the box.
You then asked via comments for clarification:
So what you are saying is that, there's nothing I can do to have a namespaced class as a type name, right?
Well, as far as for the default behavior most likely not, however as the term Strategy is involved, I'd say there is some mechanism to extend Zend Soap for that operation and inject a different one which for example does allow namespaced classes (classes by their FQCN), see the Strategy Pattern.
And if this is only a single class you can do some cheap trick in the meanwhile and extend your namespaced class as the short name or alias it with class_alias
.
Zend_Soap_AutoDiscover
takes the type name from the phpdoc block, i.e., from this comment line:
* @return \Library\IncrementedInt
You could just change that type to, for example, IncrementedInt
, without a namespace and slashes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With