Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP5's namespaces lead to an incorrect WSDL type name while implementing a webservice

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!

like image 486
Mehran Avatar asked Aug 24 '13 13:08

Mehran


2 Answers

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.

like image 87
hakre Avatar answered Nov 14 '22 07:11

hakre


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.

like image 1
pilsetnieks Avatar answered Nov 14 '22 07:11

pilsetnieks