- Teaching an old PHP application to talk Spanish, Chinese & Hebrew
- Drupal 6 External Authentication - Sample Code
- Upgrading Billion Firmware on OS X
- More on Zend_Soap_Autodiscover, PHP SOAP and encoding arrays of objects
- Zend_Soap_Server / PHP SoapServer and the dreaded "objects within array encoded as SOAP-ENC:struct" problem: solved!
- Zend_Soap_Autodiscover and Importing the SOAP Namespace
- Zend_Soap_Server error/exception handling
- But What About FileVault?
- Time Machine Rules!
- The Case of the Missing Div... (or not)
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:
...should look more like this:
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:
{
/** @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:
With those things in place the resulting response XML becomes:
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.
Comments
EXCELENT!
thank you very much succesfull article
thanks! very helpful!!! u almost made my day :)
it 's very helpful
Setting the right error reporting level will save you hours.
radiators
Thank you very much for the excellent and useful subject.
thanks for this information. really easy to follow and understand
jen x
I'm not entirely sure what the commenter is asking. I can come up with three likely interpretations though:
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.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.
You can either use the
classmapoption of the Zend_Soap_Server constructor or set the type strategy toZend_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.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. :-)
$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'
how are you able to make use of multiple classes within a single soap server?
Post new comment