More on Zend_Soap_Autodiscover, PHP SOAP and encoding arrays of object

Well, it turns out that my so-called solution to the Zend_Soap_Server / PHP SoapServer and the dreaded “objects within array encoded as SOAP-ENC:struct” problem was not 100% correct.

The issue is that this part of the response document:

<items enc:itemType="enc:Struct" enc:arraySize="2" xsi:type="enc:Array">

...should look more like this:

<items enc:arrayType="xsd:anyType[2]" xsi:type="enc:Array"$gt;

After six hours of wailing and gnashing of teeth (and a little bit of Googling!), I finally found a solution that should work in most situations.

The solution involves several important facets of Zend_Soap_Autodiscover, so some code snippets are necessary to demonstrate all the subtleties. The key element to this fix, which is making sure the array of objects is encoded correctly in the PHPDOC section, is applicable to regular PHP SOAP as well. See here for details.

Lets assume that these are the key classes used by our SOAP server:

class RespItem
{
    /** @var string */
    public $stuff;
}

class PingBack
{
    /** @var RespItem[] */
    public $items;
}

class Foo
{
    /**
     * @param string
     * @return PingBack
     */
    public function ping( $testData )
    {
        $response = new PingBack();
        // Populate $response object with data...
        return $response;
    }
}

The most important thing to note about the above is the way the array of RespItem objects is notated in the PingBack class. If you use the array key word then you get the enc:itemType="enc:Struct" behaviour described above. In addition to notating the array correctly, you also have to use the Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex discovery strategy when you instantiate the Zend_Soap_Autodiscover object:

$auto = new Zend_Soap_AutoDiscover(’Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex');

With those things in place the resulting response XML becomes:

<items enc:itemType="ns1:RespItem" enc:arraySize="2" xsi:type="ns1:ArrayOfRespItem">

Not exactly what we were after, but certainly better than the original solution.

Incidentally, this solution appears to not require the classmap option to be passed into the Zend_Soap_Server constructor. I’m guessing that whatever little issue the classmap option was overcoming, the change in complex type discovery strategy achieves the same thing and then some.

Yet Another Programming Blog

Where James Gordon rambles about PHP and web development in general.

Find me on Twitter Find me on Stack Exchange Find me on Github Subscribe