More on Zend_Soap_Autodiscover, PHP SOAP and encoding arrays of objects

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">

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:

<?php
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:

<?php
$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.

photo

EXCELENT!

EXCELENT!

photo

thanks

thank you very much succesfull article

photo

thx man

thanks! very helpful!!! u almost made my day :)

photo

it 's very helpful

it 's very helpful

photo

Setting the right error

Setting the right error reporting level will save you hours.
radiators

photo

Thank you very much for the

Thank you very much for the excellent and useful subject.

photo

thanks

thanks for this information. really easy to follow and understand

jen x

photo

RE: multiple classes within single soap server

I'm not entirely sure what the commenter is asking. I can come up with three likely interpretations though:

  1. How can you expose methods of more than one class in a single SOAP server object?
    I don't think this is possible, since Zend_Soap_Server is basically just a wrapper for PHP's SoapServer class. I think this is a nice design choice, though, because one would typically want to expose functionality by way of a facade, which would typically be implemented as a single class. If you really want to use methods from multiple classes then maybe the addFunction() method might work, but I wouldn't recommend it.
  2. How can you expose methods of more than one class in a single server?
    I really don't think this is what the commenter was asking, but the answer is to expose different functionality on different URLs and (most likely) have one class per URL. How you do this depends on the structure of your application.
  3. How can you use multiple classes as data types that will be exchanged by the Web Services?
    You can either use the classmap option of the Zend_Soap_Server constructor or set the type strategy to Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex, as above. In order for either method to work you need to make sure you have included the PHP files that contain the definitions of the classes you want to use.
photo

RE: undefined constant error

Yep, the argument to Zend_Soap_AutoDiscover() should either be a boolean, a string or some object that implements the Zend_Soap_Wsdl_Strategy_Interface. My code worked only because PHP helpfully converted the undefined constant into a string for me. Thanks for pointing that out.

error_reporting( E_ALL | E_STRICT );

My (not so new) friend. :-)

photo

$auto = new

$auto = new Zend_Soap_AutoDiscover(Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex);
throws an error:
use of undefined constant Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex
assumed 'Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex'

photo

how are you able to make use

how are you able to make use of multiple classes within a single soap server?

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <pre>
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.
By submitting this form, you accept the Mollom privacy policy.