Using complex structure with SOAP - php

The problem is that I cannot succeed to send an array of class through SOAP to a specific web service that I cannot change his structure.
Here below you'll see the schema of the Soap function:
http://www.elyotech.com/share/yoni/forum/developpeznet-soap.jpg
Here you'll find the code I'm corresponding to it:
$s = new soapclient($URL_WEBSERVICE,array('wsdl'=>true,"trace"=>true));
$params = new stdClass();
$params->loginInfo = new stdClass();
$params->loginInfo->UserName = 'username';
$params->loginInfo->Password = 'password';
$params->loginInfo->LanguageCode = 'en';
$params->reservation = new stdClass();
$params->reservation->EmailRecipient2 = 'yonia#yopmail.com';
$params->reservation->EmailRecipient3 = 'yonia2#yopmail.com';
$params->reservation->FirstName = 'Yoni'
foreach($extras as $id=>$extra)
{
$params->Extras[$id]= new stdClass();
$params->Extras[$id]->SelectedExtra = new stdClass();
$params->Extras[$id]->ExtensionData = new stdClass();
$params->Extras[$id]->SelectedExtra->Amount = 1;
$params->Extras[$id]->SelectedExtra->ID = $extra;
}
Here is the SOAP request that is sent:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/">
<SOAP-ENV:Body>
<ns1:CreateReservation>
<ns1:loginInfo>
<ns1:UserName>monusername</ns1:UserName>
<ns1:Password>monpass</ns1:Password>
<ns1:LanguageCode>en</ns1:LanguageCode>
</ns1:loginInfo>
<ns1:reservation>
<ns1:EmailRecipient2>yonia#yopmail.com</ns1:EmailRecipient2>
<ns1:EmailRecipient3>yonia2#yopmail.com</ns1:EmailRecipient3>
<ns1:FirstName>Yoni</ns1:FirstName>
</ns1:reservation>
</ns1:CreateReservation>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
In this Soap request, I cannot find the Extras array of objects.
Do you have any idea of how I should create my object in order to send it correctly?

Related

PHP Soap complex params with repeated keys

I need to generate the following XML
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://services.bloomberg.com/datalicense/dlws/ps/20071001">
<SOAP-ENV:Body>
<ns1:submitGetHistoryRequest>
<ns1:headers>
<ns1:daterange>
<ns1:period>
<ns1:start>2018-05-08</ns1:start>
<ns1:end>2018-05-08</ns1:end>
</ns1:period>
</ns1:daterange>
</ns1:headers>
<ns1:fields>
<ns1:field>PX_LAST</ns1:field>
</ns1:fields>
<ns1:instruments>
<ns1:instrument>
<ns1:id>US0000000002</ns1:id>
<ns1:yellowkey>Equity</ns1:yellowkey>
<ns1:type>ISIN</ns1:type>
</ns1:instrument>
<ns1:instrument>
<ns1:id>US0000000001</ns1:id>
<ns1:yellowkey>Equity</ns1:yellowkey>
<ns1:type>ISIN</ns1:type>
</ns1:instrument>
</ns1:instruments>
</ns1:submitGetHistoryRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I use PHP 7.1.17 and SoapClient.
I can not pass options to SoapClient, as the instrument key is repeated and PHP's associated array can not have same key twice. I tried constructing object and setting instrument properties as SoapVar, but it generates incorrect XML. Here is code and result:
$options = new \stdClass();
$options->headers = new \stdClass();
$options->headers->daterange = new \stdClass();
$options->headers->daterange->period = new \stdClass();
$options->headers->daterange->period->start = '2018-05-08';
$options->headers->daterange->period->end = '2018-05-08';
$options->fields = new \stdClass();
$options->fields->field = 'PX_LAST';
//first instrument
$instrument = new \stdClass();
$instrument->id = 'US0000000002';
$instrument->type = 'ISIN';
$instrument->yellowkey = 'Equity';
$options->instruments[] = new \SoapVar(
$instrument,
SOAP_ENC_OBJECT,
'stdClass',
"http://soapinterop.org/xsd",
"instrument"
);
//second instrument
$instrument = new \stdClass();
$instrument->id = 'US0000000001';
$instrument->type = 'ISIN';
$instrument->yellowkey = 'Equity';
$options->instruments[] = new \SoapVar(
$instrument,
SOAP_ENC_OBJECT,
'stdClass',
"http://soapinterop.org/xsd",
"instrument"
);
<ns1:instruments/> remains empty in resulting XML:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://services.bloomberg.com/datalicense/dlws/ps/20071001">
<SOAP-ENV:Body>
<ns1:submitGetHistoryRequest>
<ns1:headers>
<ns1:daterange>
<ns1:period>
<ns1:start>2018-05-08</ns1:start>
<ns1:end>2018-05-08</ns1:end>
</ns1:period>
</ns1:daterange>
</ns1:headers>
<ns1:fields>
<ns1:field>PX_LAST</ns1:field>
</ns1:fields>
<ns1:instruments/>
</ns1:submitGetHistoryRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
How can I pass options to SoapClient, to generate XML with repeated instrument keys?
I solved this. Turns out when you pass an ordered array (not associative one) as object's property, as many XML nodes are generated using that property's name, as number of elements in the array. So instead of building SoapVar objects and putting them into instruments[] array, I just assigned array of instruments to instruments as instrument property:
$options->instruments = new \stdClass();
//first instrument
$instrument = new \stdClass();
$instrument->id = 'US0000000002';
$instrument->type = 'ISIN';
$instrument->yellowkey = 'Equity';
$options->instruments->instrument[] = $instrument;
//second instrument
$instrument = new \stdClass();
$instrument->id = 'US0000000001';
$instrument->type = 'ISIN';
$instrument->yellowkey = 'Equity';
$options->instruments->instrument[] = $instrument;
I build instruments in a foreach loop. Btw converting array to object instead of building stdClass also works fine:
$options->instruments->instrument[] = (object)[
'id' => 'US0000000001',
'type' => 'ISIN',
'yellowkey' => 'Equity'
]

PHP SoapClient : What is NS2

I'm New to webservices i'm trying to call webservice with soapClient() and it's generating Request XML which is not in expected format
Below is expected format of request XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns2:EndUserRequest xmlns:ns2="http://www.example.net/EndUserRequest">
<ns2:companyCode>MD</ns2:companyCode>
<ns2:customerBranch>60</ns2:customerBranch>
<ns2:customerNumber>112946</ns2:customerNumber>
<ns2:endUserName>Some Name</ns2:endUserName>
<ns2:ContactName />
<ns2:address />
<ns2:city />
<ns2:state />
<ns2:postalCode />
<ns2:email />
<ns2:phoneNumber />
<ns2:countryCode>US</ns2:countryCode>
</ns2:EndUserRequest>
</soapenv:Body>
</soapenv:Envelope>
Below is XML Request generating by my code
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.emaple.com/EndUserRequest">
<SOAP-ENV:Body>
<ns1:EndUserRequest xmlns:ns1="http://www.example.net/EndUserRequest">
<companyCode>MD</companyCode>
<customerBranchNumber>360</customerBranchNumber>
<customerNumber>53494711</customerNumber>
<endUserName>ABCED</endUserName>
<ContactName></ContactName>
<address></address>
<city></city>
<state></state>
<postalCode></postalCode>
<email></email>
<phoneNumber></phoneNumber>
<countryCode>US</countryCode>
</ns1:EndUserRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Below is my code
$client = new SoapClient('https://api-beta.example.com:443/enduser/v1/enduserlist?wsdl', array(
"trace" => 1,
"stream_context" => stream_context_create($streamContext),
'cache_wsdl' => WSDL_CACHE_NONE
));
$endUserRequest = new stdClass;
$endUserRequest->companyCode = 'MD';
$endUserRequest->customerBranchNumber = '560';
$endUserRequest->customerNumber = '59471321';
$endUserRequest->endUserName = 'Somename';
$endUserRequest->ContactName = '';
$endUserRequest->address = '';
$endUserRequest->city = '';
$endUserRequest->state = '';
$endUserRequest->postalCode = '';
$endUserRequest->email = '';
$endUserRequest->phoneNumber = '';
$endUserRequest->countryCode = 'US';
$requestSoapVar = new SoapVar($endUserRequest, SOAP_ENC_OBJECT,null,null,'EndUserRequest','http://www.example.com/EndUserRequest');
$res = $client->GetEndUsers($requestSoapVar);
echo '<textarea style="width:600px;height:500px">';
echo "\n-------Request Header------\n";
echo $client->__getLastRequestHeaders();
echo "\n-------Request------\n";
echo $client->__getLastRequest();
echo "\n-------Response Header------\n";
echo $client->__getLastResponseHeaders();
echo "\n-------Response------\n";
echo $client->__getLastResponse();
echo '</textarea>';
echo '<textarea style="width:600px;height:500px">';
print_r($res);
echo '</textarea>';
Every member of your object must be a SoapVar object because there is a namespace for them. Just encode your object as the follwing example shows.
$oEndUserRequest = new StdClass();
$oEndUserRequest->companyCode = new SoapVar(
'MD',
XSD_STRING,
null,
null,
'companyCode',
'http://www.example.com/EndUserRequest'
);
Just do it for everey class member and you 'll get the expected result.
For advanced reason here 's an example how to change the prefix of the namespace. You have to know, that the PHP SoapClient object nor the SoapVar object have a way to manually set a namespace prefix. In a normal case it is unnecessary to set a prefix for a namespace.
The PHP SoapClient object has a __doRequest method, in which you can edit the XML. You have to Code your own SoapClient extending the PHP SoapClient.
class MySoapClient extends SoapClient {
public function __doRequest($sRequest, $sLocation, $sAction, $iVersion, $iOneWay = 0) {
$sRequest = str_replace('ns1', 'ns2', $sRequest);
$this->__last_request = $sRequest;
return parent::__doRequest(ltrim($sRequest), $sLocation, $sAction, $iVersion, $iOneWay);
}
}
In my eyes it is not neccessary to change the namepace prefix. If so, just use the __doRequest method for your purpose.

PHP SOAP complex types

I have a working XML request body, which I'm trying to send via PHP to a SOAP server:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="urn:servicewsdl" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<mns:getQuote xmlns:mns="urn:getquoteswsdl" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<authorisation xsi:type="tns:Authorisation">
<username xsi:type="xsd:string">****</username>
<password xsi:type="xsd:string">****</password>
</authorisation>
<symbol xsi:type="xsd:string">****</symbol>
</mns:getQuote>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I tried passing the params in an array like so:
$result = $client->getQuote(array('username' => '****', 'password' => '****'), array('symbol' => '****'));
but it returns me an error:
SOAP-ERROR: Encoding: object has no 'username' property
you probably need to put the username/password array inside authorisation like:
$result = $client->getQuote(array('authorisation'=>array('username' => '****', 'password' => '****')), array('symbol' => '****'));
or, maybe you should send it an object instead:
$params = new stdClass();
$params->authorisation = new stdClass();
$params->authorisation->username = '****';
$params->authorisation->password = '****';
$params->symbol = '****';
$result = $client->getQuote($params);
EDIT: From the comments, in the end, getQuote was accessed via PHP in this method:
$auth = new stdClass();
$auth->username = '****';
$auth->password = '****';
$symbol = '****';
$result = $client->getQuote($auth, $symbol);
I had a heck of a time working with PHP and SOAP as well. I seem to recall a similar situation where I used the standard PHP class (new stdClass()) to help build the object with params. Here's the questions/answer page.
How can I add Attributes to a PHP SoapVar Object?
I hope it helps.

Problems Calling SOAP Web Service Using PHP

This is my SOAP request:
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:impl="http://impl.user">
<soapenv:Header/>
<soapenv:Body>
<impl:UserSessionDetails soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<in0 xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">requstXml</in0>
<in1 xsi:type="impl:UserInfo">
<password xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">pwd</password>
<userName xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">pwd</userName>
</in1>
</impl:UserSessionDetails>
</soapenv:Body>
</soapenv:Envelope>
I've tried the following PHP code:
$soapClient = new SoapClient("http://example.com/services/?WSDL");
$sh_param = array(
'userName' => 'user',
'Password' => 'pwd'
);
$headers = new SoapHeader('http://tempuri.org/', false);
$soapClient->__setSoapHeaders(array($headers));
$requestXML = '<request name= "UserSessionDetails"><UserDetails><user_name>username</user_name><from_date>fromdate</from_date><to_date>to_date</to_date><group></group></UserDetails></request>';
$result = $soapClient->UserSessionDetails(array('in0'=> $requestXML, 'in1'=> $sh_param));
$simple = $result->$simple = $result->UserSessionDetailsResponse;
$p = xml_parser_create();
xml_parse_into_struct($p, $simple, $vals, $index);
xml_parser_free($p);
echo "<pre>";
print_r($vals);
echo "</pre>"
But it returns nothing. Can anybody please tell me what the problem is?
Do not use raw xml in SoapClient requests. Use objects/arrays or SoapVar instead.
Basic example:
<?php
$client = new \SoapClient('http://example.com/services/?WSDL');
// Optionally your service endpoint
$client->__setLocation('http://example.com/services');
$userDetails = new stdClass();
$userDetails->user_name = 'username';
$userDetails->from_date = 'fromdate';
$userDetails->to_date = 'to_date';
$in0 = new stdClass();
$in0->UserDetails = $userDetails;
$in1 = new stdClass();
$in1->userName = 'pwd';
$in1->Password = 'pwd';
$request = new stdClass();
$request->in0 = $in0;
$request->in1 = $in1;
$result = $client->UserSessionDetails($request);
You can debug you SOAP services with any SOAP client like SOAPUI
P.S.
Have a look at Zend_Soap_Client and SoapVar examples

Change format of the output XML , generated from PHP SoapClient?

I am trying to create this :
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<AccessKey xmlns="http://eatright/membership" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Value>67a4ef47-9ddf-471f-b6d0-0000c28d57d1</Value>
</AccessKey>
</s:Header>
<s:Body>
<WebUserLogin xmlns="http://eatright/membership">
<loginOrEmail>1083790</loginOrEmail>
<password>thomas</password>
</WebUserLogin>
</s:Body>
</s:Envelope>
I created this PHP code
class ChannelAdvisorAuth
{
public $AccessKey ;
public function __construct($key)
{
$this->AccessKey = $key;
}
}
$AccessKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$url = "http://ws.eatright.org/service/service.svc?wsdl";
$client = new SoapClient($url, array("trace" => 1, "exception" => 0));
$auth = new ChannelAdvisorAuth($AccessKey);
$header = new SoapHeader("AccessKey", "Value", $AccessKey, false);
$client->__setSoapHeaders($header);
$result = $client->ValidateAccessKey();
echo "REQUEST:\n" . $client->__getLastRequest() . "\n";
The output of the above PHP code is :
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://eatright/membership" xmlns:ns2="AccessKey">
<SOAP-ENV:Header>
<ns2:Value>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</ns2:Value>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:ValidateAccessKey/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
How to change the PHP code to output the XML as requested by web service provider?
How to replace the "SOAP-ENV" to "S"?
Is there is a way to remove the NS1 and NS2? and also adjust the whole format of the XML to meet the requirements? thanks
You don't need to worry about SOAP-ENV, ns1 or ns2 - they are just prefixes referring to the namespaces. As long as the full namespaces are correct, it's going to be alright.
I think the SOAP header should be made like this:
$access_key = new stdClass();
$access_key->Value = 'XXX';
$hdr = new SoapHeader('http://eatright/membership', 'AccessKey', $access_key);
$client->__setSoapHeaders($hdr);
I don't see a purpose of xmlns:i in the first example - there are no elements having XSI attributes.
I'm not sure what to do with the body. In your first example, there is a call to the WebUserLogin operation, while in your PHP code you are trying to call ValidateAccessKey.
Have you tried reading the WSDL file which is pointed by $url
Ok I found the problem and I will add it here in case someone looking for same issue.
$access_key = new stdClass();
$access_key->Value = 'xxxxxxxxxxxxxxxxxxx';
// Create the SoapClient instance
$url = "http://ws.eatright.org/service/service.svc?wsdl";
$client = new SoapClient($url, array("trace" => 1, "exception" => 0));
$hdr = new SoapHeader('http://eatright/membership', 'AccessKey', $access_key);
$client->__setSoapHeaders($hdr);
$soapParameters = array('loginOrEmail ' => $username, 'password' => $password);
$login = new stdClass();
$login->loginOrEmail='LoginID';
$login->password='Password';
$result = $client->WebUserLogin($login);

Categories