I have an associative array:
$params = [ 'trid' => null, 'merchantCode' => null, 'paymentMethod' => null, 'returnUrl' => site_url(null), 'notificationUrl' => site_url(null), 'language' => 'null', 'currency' => 'null', 'isTestMode' => false, 'productsXml' => null, 'needInvoice' => true,
(Nulls hold actual values in reality)
When I check __getLastRequest I completly lose the keys in the generated XML.
SoapClient,
$soap = new SoapClient(null, $options); $soap->__soapCall('Request', $params); $request = $soap->__getLastRequest();
Please note that I have a NON WSDL connection to the endpoint.
The generated XML will have a field value of <param[keyNum] xsi:type="xsd:typeOfVariable">
instead of having the actual key value from the associative array, <trid>
for example.
<SOAP-ENV:Body><ns1:Request><param0 xsi:type="xsd:string">null</param0><param1 xsi:type="xsd:string">null</param1></Request>
Advertisement
Answer
Contrary to what the PHP manual says, it seems arguments
is never interpreted as an associative array.
If we try this simple test:
<?php $options = ['location'=>'http://localhost/unknown', 'uri'=>'test', 'trace'=>true]; $soap = new SoapClient(null, $options); try { $soap->__soapCall('Request', ['foo'=>1, 'bar'=>2]); } catch(SoapFault $e) { header('Content-type: text/xml'); echo $soap->__getLastRequest(); } ?>
we get:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <ns1:Request> <param0 xsi:type="xsd:int">1</param0> <param1 xsi:type="xsd:int">2</param1> </ns1:Request> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
We see that the parameter names are ignored.
Now if we try what the other answer suggests (wrap the array in another array):
<?php $options = ['location'=>'http://localhost/unknown', 'uri'=>'test', 'trace'=>true]; $soap = new SoapClient(null, $options); try { $soap->__soapCall('Request', [['foo'=>1, 'bar'=>2]]); } catch(SoapFault $e) { header('Content-type: text/xml'); echo $soap->__getLastRequest(); } ?>
we get:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <ns1:Request> <param0 xsi:type="ns2:Map"> <item> <key xsi:type="xsd:string">foo</key> <value xsi:type="xsd:int">1</value> </item> <item> <key xsi:type="xsd:string">bar</key> <value xsi:type="xsd:int">2</value> </item> </param0> </ns1:Request> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
We see that there is a single parameter whose type is Map
. That’s not what we want.
The solution is to use the SoapParam
class:
<?php $options = ['location'=>'http://localhost/unknown', 'uri'=>'test', 'trace'=>true]; $soap = new SoapClient(null, $options); try { $soap->__soapCall('Request', [new SoapParam(1, 'foo'), new SoapParam(2, 'bar')]); } catch(SoapFault $e) { header('Content-type: text/xml'); echo $soap->__getLastRequest(); } ?>
Now we get what we wanted:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <ns1:Request> <foo xsi:type="xsd:int">1</foo> <bar xsi:type="xsd:int">2</bar> </ns1:Request> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Note that you can easily convert an associative array to SOAP parameters like this:
function getSoapParams($params) { $a = []; foreach($params as $name=>$value) $a[] = new SoapParam($value, $name); return $a; }