Door
Johnny Cash
op 17-01-2019 17:44
gewijzigd op 17-01-2019 17:50
7.048 views
Beste programmeurs,
Als basic programmeur ben ik al 2 dagen bezig om een groot probleem op te lossen die waarschijnlijk heel simpel is voor de programmeur experts onder ons. Het volgende is er aan de hand.
Via onderstaand stukje script roep ik de status op van een bepaalde zending:
$WebserviceClient = new SoapClient("http://xxx/App_Services/xxx.asmx?wsdl");
$parameters= array("Username"=>$username, "Password"=>$password, "Zending"=>$zending, "Postcode"=>$postocde, "Referentie"=>$referentie);
$WebmethodResult = $WebserviceClient->GetShipmentStatus($parameters) or die('FOUT!');
Als ik vervolgens via PRINT_R het resultaat in $WebmethodResult op het scherm toon krijg ik een response terug die begint met stdClass Object en daarna alle informatie over die bepaalde zending.
Als ik de BRONCODE van de code op het scherm bekijk zie ik veel code staan zoals
<MovementID>225362222</MovementID><ShipmentID>18815421</ShipmentID><CompanyID>985</CompanyID><MovementType>Afgeleverd</MovementType>
Mijn vraag is hoe ik met PHP de response ($WebmethodResult) uit de SOAP request kan benaderen zodat ik het MovementType element kan declareren in een variable waarna ik een if/else constructie kan maken zoals:
In wezen doe je met $client->getShipmentStatus($parameters) een aanroep van __soapCall().
Hier staat (onder Return Values):
On error, if the SoapClient object was constructed with the exceptions option set to FALSE, a SoapFault object will be returned.
Ik weet niet of dit de default is, maar ik denk wel dat je er verstandig aan doet om ofwel een try-catch mechanisme te gebruiken, ofwel te controleren of er fouten optreden middels is_soap_fault(), afhankelijk van wat je instelt via de exceptions optie. Ook lijkt het mij handig en verstandig zoveel mogelijk expliciet te configureren, zodat je ook zeker weet dat de code ook op een voorgeschreven manier werkt want defaults zijn immers niet altijd de default.
Vervolgens geeft getShipmentStatus() iets terug. De documentatie van soapCall zegt hierover:
SOAP functions may return one, or multiple values. If only one value is returned by the SOAP function, the return value of __soapCall will be a simple value (e.g. an integer, a string, etc). If multiple values are returned, __soapCall will return an associative array of named output parameters.
Dus ik zou in eerste instantie een array verwachten. Maar jij zegt dat het een object is of zelfs XML. Wat is het nu? :p Heeft deze webservice ook een documentatie, staat daar in beschreven wat je terug kunt verwachten?
Maar het lijkt er dus op dat alles min of meer goed verloopt (foutafhandeling en configuratie daar gelaten) en je dus enkel een waarde ergens uit moet peuteren (een object? een lap XML? iets anders?), maar dat staat verder los van dit hele SOAP gebeuren lijkt mij.
Voor de toepassing die ik wil maken wil ik graag het element "MovementType" gaan uitlezen, omdat daarin een status wordt gegeven. Daarom moet ik dus op een correcte manier de variabele $WebmethodResult uitlezen in PHP.
Mja, maar daar zit dus blijkbaar geserialiseerde XML in, deze zou je dus apart moeten uitpakken. Dit ziet er een beetje onorthodox uit (misschien? heb hier verder weinig ervaring mee). Heb je documentatie die hier beweegredenen voor geeft of uitlegt hoe je hier data uit kunt peuteren?
Anyhow, het volgende lijkt ongeveer te doen wat jij wilt, bij wijze van proof of concept. Iets soortgelijks zou voor bovenstaande SOAP-response ook moeten werken:
<?php
// zorg dat output goed geencodeerd is
header('Content-Type: text/html; charset=UTF-8');
// voor het melden+weergeven van foutmeldingen voor debugging
error_reporting(E_ALL);
ini_set('display_startup_errors', true);
ini_set('display_errors', 'stdout');
// hulpfunctie voor het (veilig) dumpen van data
function dump($in) {
if (is_array($in)) {
$in = print_r($in, true);
}
echo '<pre>'.escape($in).'</pre>';
}
// hulpfunctie voor het escapen van output
function escape($in) {
return htmlspecialchars($in, ENT_QUOTES, 'UTF-8');
}
// Test case, bouw een soortgelijk genest object met hierin een XML-string
$wrapper = new StdClass();
$subObj = new StdClass();
$subObj->xml = '<root><data>hoi</data></root>';
$wrapper->sub = $subObj;
// zet objecten om naar (geneste) arrays
$response = json_decode(json_encode($wrapper), true);
// inspecteer output
dump($response);
// selecteer de XML-string
$xml = $response['sub']['xml'];
// creeer hiermee een SimpleXMLElement object
$data = simplexml_load_string($xml);
// converteer dit wederom naar (geneste) arrays
$dataArray = json_decode(json_encode($data), true);
// And Bob's your uncle
dump($dataArray);
?>[end]
EDIT: als dat XML-ding onhandig in elkaar zit (met attributen enzo) dan zul je deze misschien wat verder uit elkaar moeten trekken m.b.v. SimpleXML, maar als je eenmaal het XML-deel bij zijn kladden hebt zou dat niet ingewikkeld moeten zijn.