I ran into an bothersome problem with PHP’s SoapServer class this week.
Here’s what I wanted as output from the server:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<locationCollection>
<Location>
<name>AME s438</name>
<id>452</id>
<latitude>32.236322</latitude>
<longitude>-110.951614</longitude>
</Location>
<Location>
<name>ECE 229</name>
<id>45</id>
<latitude>32.235069</latitude>
<longitude>-110.953417</longitude>
</Location>
</locationCollection>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
However what I was getting instead was:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<locationCollection>
<SOAP-ENC:Struct>
<name>AME s438</name>
<id>452</id>
<latitude>32.236322</latitude>
<longitude>-110.951614</longitude>
</SOAP-ENC:Struct>
<SOAP-ENC:Struct>
<name>ECE 229</name>
<id>45</id>
<latitude>32.235069</latitude>
<longitude>-110.953417</longitude>
</SOAP-ENC:Struct>
</locationCollection>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Here was my original code for the server:
<?php
$wsdl = 'http://example.com/locations_service.wsdl';
$service = new SoapServer($wsdl);
$service->addFunction('getComputerLabs');
$service->handle();
function getComputerLabs($input) {
$all_locations = resource::get_all(FALSE, 'location');
$return_array = array();
foreach ($all_locations as $l) {
// Build a basic return object.
$new_loc = new Location();
$new_loc->name = $l->name;
$new_loc->id = $l->resource_id;
$new_loc->latitude = $l->getProperty('Latitude');
$new_loc->longitude = $l->getProperty('Longitude');
$return_array[] = $new_loc;
}
return $return_array;
}
class Location {
public $name;
public $id;
public $description;
public $url;
public $buildingName;
public $roomNumber;
public $openStatus;
public $latitude;
public $longitude;
}
?>
Apparently the SOAP library really prefers that everything is an object. In php 5 they added an ArrayObject class. This coupled with a SoapVar call fixed my output for me.
<?php
function getComputerLabs($input) {
$all_locations = resource::get_all(FALSE, 'location');
/**
* Use an ArrayObject instead of a plain array.
*/
$return_array = new ArrayObject();
foreach ($all_locations as $l) {
// Build a basic return object.
$new_loc = new Location();
$new_loc->name = $l->name;
$new_loc->id = $l->resource_id;
$new_loc->latitude = $l->getProperty('Latitude');
$new_loc->longitude = $l->getProperty('Longitude');
/**
* Encode each array element with SoapVar. Parameter 5 is the name of the
* XML element you want to use. This only seems to work within
* an ArrayObject.
*/
$new_loc = new SoapVar($new_loc, SOAP_ENC_OBJECT, null, null, 'Location');
$return_array->append($new_loc);
}
return $return_array;
}
?>
Note that with only the ArrayObject part, and before I figured out the SoapVar wrapper, I was getting this interesting BOGUS tag:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<locationCollection>
<BOGUS>
<name>AME s438</name>
<id>452</id>
<latitude>32.236322</latitude>
<longitude>-110.951614</longitude>
</BOGUS>
<BOGUS>
<name>ECE 229</name>
<id>45</id>
<latitude>32.235069</latitude>
<longitude>-110.953417</longitude>
</BOGUS>
</locationCollection>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Share this post
Twitter
Facebook
LinkedIn
Email