Array problems with X-Fire, SOAP and PHP


I’ve been working with X-fire / ageis services in SOAP now for a while, and there’s been only one issue I’ve not been able to solve. Arrays.

When the back-end send an array with item count > 1 everything works fine. The problems start when there is only one item in the array. The array is collapsed and instead there is a object that is the only item. At first I thought this was the java back-end that screwed up, but after inspecting the SOAP messages from NGREP I found out that it’s PHP that screws up.

I’ve prepared a short example called lookupPerson which takes a username and returns a Person with his related cars.

Consider the first sample, where the person has three cars:

SOAP request:
<pre line="1" lang="xml">
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://api.service.com/temp/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="urn:Service">
<SOAP-ENV:Header>
<ns2:RemoteAddress xsi:type="SOAP-ENC:string">127.0.0.1</ns2:RemoteAddress>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:lookupPerson>
<ns1:in0>john</ns1:in0>
</ns1:lookupPerson>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

</pre>

SOAP response:
<pre line="1" lang="xml">

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<lookupPersonResponse xmlns="http://api.service.com/temp/">
<out xmlns="http://api.service.com/temp/">
<username xmlns="http://users.model.service.com">john</username>
<cars xmlns="http://users.model.service.com">
<Car>
<car>HUMMER</car>
</Car>
<Car>
<car>BMW</car>
</Car>
</cars>
</out>
</lookupPersonResponse>
</soap:Body>
</soap:Envelope>

</pre>

Now that looks pretty much right. Lets take a look at a var_dump of the returned object:

object(lookupPersonResponse)#571 (1) {
["out"]=> object(Person)#570 (2) {
["username"]=> string(11) "john"
["cars"]=> object(stdClass)#573 (1) {
["Car"]=> array(2) {
[0]=> object(Car)#572 (1) {
["car"]=> string(17) "BMW"
}
[1]=> object(Car)#574 (1) {
["car"]=> string(19) "HUMMER"
}
}
}
}
}

Yep. Everything is correct. The class map works as intended. Now, lets get over to the bad stuff. The following output is the same call, but this time John has lost his Hummer.

SOAP response:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<lookupPersonResponse xmlns="http://api.service.com/temp/">
<out xmlns="http://api.service.com/temp/">
<username xmlns="http://users.model.service.com">john</username>
<cars xmlns="http://users.model.service.com">
<Car>
<car>BMW</car>
</Car>
</cars>
</out>
</lookupPersonResponse>
</soap:Body>
</soap:Envelope>

Well, the SOAP response is pretty much like the first one.

PHP object:

object(lookupPersonResponse)#571 (1) {
["out"]=> object(Person)#570 (2) {
["username"]=> string(11) "john"
["cars"]=> object(stdClass)#573 (1) {
["Car"]=> object(Car)#572 (1) {
["car"]=> string(17) "BMW"
}
}
}
}

Do you see the difference here? Car is pointing to the car object instance instead of an array. This lays the path for some ass logic work for everything that returns an array.

Lets take a look at the relevant parts of the WSDL:

<xsd:complexType name="Person">
<xsd:sequence>
<xsd:element minOccurs="0" name="username" nillable="true" type="xsd:string"/>
<xsd:element minOccurs="0" name="cars" nillable="true" type="ns1:ArrayOfCar"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ArrayOfCar">
<xsd:sequence>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="Car" nillable="true" type="ns1:Car"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Car">
<xsd:sequence>
<xsd:element minOccurs="0" name="car" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="lookupPersonResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="out" nillable="true" type="ns1:Person"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>

According to WSDL standard this is legal and should work, but I dont think PHP is too happy about it. I’ve tried doing similar stuff with a service that describes arrays as :


<complexType name="ArrayOf_soapenc_string">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType" wsdl:arrayType="soapenc:string[]"/>
</restriction>
</complexContent>
</complexType>

This way seems to work just fine, so I fear that the problem has something to do with X-Fire and ageis. I’m very interested in some hints on how to get this running properly.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • description
  • Live
  • Slashdot
  1. #1 by Idetrorce - December 15th, 2007 at 14:23

    very interesting, but I don’t agree with you
    Idetrorce

  2. #2 by eirikhoem - December 16th, 2007 at 12:49

    Can you please elaborate a bit? :)

  3. #3 by cmm - February 21st, 2008 at 12:35

    We run into the same problem, and found the following:

    http://bugs.php.net/bug.php?id=36226

  4. #4 by eirikhoem - March 13th, 2008 at 08:15

(will not be published)