Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to structure complex nested soap parameters

Tags:

php

soap

Alright, this problem is driving me up the wall. I'm unsuccessfully trying to connect to a web service using PHP and SOAP. I can't figure out what's wrong, and what's more this is a brand new service and their "documentation" is POOR. So I have no idea if the problem isn't actually on their end, but I don't have enough experience with SOAP to be able to know that for sure. I pray someone can help me.

I have been able to connect to the service by putting the XML directly into SOAP UI, but whenever I try to use the SoapClient it breaks down. The XML structure I am looking to send looks like

<Envelope xmlns:ns1="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://a.uri" xmlns:ns3="http://tempuri.org/">
 <Body>
    <GetAuthorization>
        <ns1:registrationObj ns1:type="ns2:RegistrationAuthorization">
            <ns2:Company>####</ns2:Company>
            <ns2:Computer>####</ns2:Computer>
            <ns2:Facility>####</ns2:Facility>
        </ns1:registrationObj> 
    </GetAuthorization>
</Body>
</Envelope>

I have tried approaches too numerous to list. Using __soapCall, and $client->method(), SoapVar, and SoapParam. On the whole I find the documentation for PHP's SoapClient to be a bit sparse. But I can't even get the structure of the call to match what I want it to (dumped via __getLastRequest())

One thing I have noticed is the client keeps dropping the first element of my array (on those instances when I try to pass the parameters in as a plain array. So:

$params = array("Company" => "abc",
                "Computer" => "def",
                "Facility" => "ghi");
$result = $soap_client->__soapCall('GetAuthorization',$params);

returns

<env:Body>
    <ns1:GetAuthorization/>
    <param1>def</param1>
    <param2>ghi</param2>
</env:Body>

note how in this instance the GetAuthorization self closed AND dropped the first array element. I have experienced both separately as well (and it is worth noting that I have gotten the paramaters to be named correctly also. I have gone through so many iterations I can't remember what attempts yield which results. Nonetheless, SOAP is NOT behaving like I would expect it to. It fails to encapsulate data properly and/or drops random elements.

$parameters = 
array("ra" => new SoapVar(array(
    "CompanyId" => new SoapVar("####", SOAP_ENC_OBJECT, 'guid', 'http://schemas.microsoft.com/2003/10/Serialization/', 'CompanyId', 'http://schemas.datacontract.org/x/y/z.xx'),
    "ComputerId" => new SoapVar("{####}", SOAP_ENC_OBJECT, 'string', 'http://www.w3.org/2001/XMLSchema', 'ComputerId', 'http://schemas.datacontract.org/x/y/z.xx'),
    "FacilityId" => new SoapVar("####", SOAP_ENC_OBJECT, 'guid', 'http://schemas.microsoft.com/2003/10/Serialization/', 'FacilityId', 'http://schemas.datacontract.org/x/y/z.xx')
), SOAP_ENC_OBJECT, 'RegistrationAuthorization', 'http://schemas.datacontract.org/x/y/z.xx', 'ra', "http://schemas.datacontract.org/x/y/z.xx"

)));

$result = $auth_client->GetAuthorization($parameters);

Is the structure I was trying to push through originally (before I simplified it to try to figure out what was wrong), figuring that since I need so much control over the namespacing of the parameters I would need to. BUT that just makes the request with a self-closed element.

Can someone PLEASE tell me how to structure the call to yield the appropriate XML structure? Is it possible this is on the Service's end and there is something wrong with the WSDL? (I'm not sure exactly what the WSDL is responsible for on the back end.)

I do apologize for the vagueness of the question, but I feel so lost I'm not even sure of the right one to ask. :-(

like image 215
dgeare Avatar asked Jan 15 '14 23:01

dgeare


1 Answers

It should work:

<?php
$client = new \SoapClient(null, array(
    'uri'           => 'http://localhost/stack/21150482/',
    'location'      => 'http://localhost/stack/21150482/server.php',
    'trace'         => true
));
try {

    $company         = new \SoapVar('XXXXX', XSD_STRING, null, null, 'Company', 'http://a.uri');
    $computer        = new \SoapVar('XXXXX', XSD_STRING, null, null, 'Computer', 'http://a.uri');
    $facility        = new \SoapVar('XXXXX', XSD_STRING, null, null, 'Facility', 'http://a.uri');

    $registrationObj = new \SoapVar(
        array($company,$computer,$facility),
        SOAP_ENC_OBJECT,
        'RegistrationAuthorization',
        'http://a.uri',
        'registrationObj',
        'http://www.w3.org/2001/XMLSchema-instance'
    );

    $client->GetAuthorization($registrationObj);

} catch (\Exception $e) {
    var_dump($e->getMessage());
}

$dom = new DOMDocument();
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($client->__getLastRequest());

print '<pre>';
print htmlspecialchars($dom->saveXML());

My result is:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://localhost/stack/21150482/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://a.uri" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:GetAuthorization>
      <xsi:registrationObj xsi:type="ns2:RegistrationAuthorization">
        <ns2:Company xsi:type="xsd:string">XXXXX</ns2:Company>
        <ns2:Computer xsi:type="xsd:string">XXXXX</ns2:Computer>
        <ns2:Facility xsi:type="xsd:string">XXXXX</ns2:Facility>
      </xsi:registrationObj>
    </ns1:GetAuthorization>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
like image 86
Greg Avatar answered Nov 15 '22 00:11

Greg