Reputation: 902
There are two SOAP endpoints I am trying to consume using WSDL. I have been able to successfully implement the first, I'm currently having issues with the second because of the way the XML request body format is - it contains multiple elements under a node having the same name. I'm using PHP array/nested arrays to construct the payload. It worked fine for the first because there was no occurrence of a parent element having multiple child elements with same name.
This is the body of my second XML request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ext="http://xxx.xxx.xxx.xxx.com/">
<soapenv:Header/>
<soapenv:Body>
<ext:requestPurchase>
<context>
<channel>xxx</channel>
<prepareOnly>xxxx</prepareOnly>
<clientReference>12q31a1a456677881</clientReference>
<clientRequestTimeout>500</clientRequestTimeout>
<initiatorPrincipalId>
<id>xxxx</id>
<type>xxxx</type>
<userId>xxxx</userId>
</initiatorPrincipalId>
<password>xxxxx</password>
<transactionProperties>
<entry>
<key>preferredLanguage</key>
<value>en</value>
</entry>
<entry>
<key>productSKU</key>
<value>xxx</value>
</entry>
<entry>
<key>currency</key>
<value>NGN</value>
</entry>
<entry>
<key>purchaseAmount</key>
<value>3</value>
</entry>
</transactionProperties>
</context>
<!--- other elements --->
</ext:requestPurchase>
</soapenv:Body>
</soapenv:Envelope>
I have entry
under transactionProperties
occurring 4 times. The method I used for the first can't work for the second request
because PHP works with unique array keys (or is there a way to by-pass this). I also tried using raw XML, but it's still not working. I'd be really glad to get a solution. Thanks!
This is how my code looks like (Using Laravel/PHP Framework):
<?php
namespace App\Engine;
use Illuminate\Http\Request;
use SoapClient;
use SoapVar;
use Log;
use Exception;
class Transaction
{
public function handle($data)
{
// Setup Host,WSDL location, Soap Client options
$uri = "http://xxxx.xxxx.xx.xxx.com/";
$wsdl = "http://host IP/xxxx/service?wsdl";
$soapclientOptions = array();
$soapclientOptions['trace'] = TRUE;
$soapclientOptions['exceptions'] = 1;
$soapclientOptions['use'] = 'SOAP_LITERAL';
$soapclientOptions['uri'] = $uri;
// $soapclientOptions['connection_timeout'] = 15;
// $soapclient_options['location'] = $host;
$soapclientOptions['cache_wsdl'] = WSDL_CACHE_NONE;
$e = '';
try
{
$client = new SoapClient($wsdl, $soapclientOptions);
}
catch(Exception $e)
{
Log::error("Error occurred on attempt to open Soap Connection. Error details: ".json_encode($e));
return response()->failure(null, 'Error occurred on attempt to open Soap Connection. Check log for error details', 400);
}
try
{
$handleRequest = $this->formPayloadAndProcessRequest($client, $data);
if(!$payload[0]) return response()->failure(null, $payload[1], 400);
dd($handleRequest);
}
catch (Exception $e)
{
Log::error("Error occurred on attempt to process Soap Method. Error details: ".json_encode($e));
return response()->failure(null, 'Error occurred on attempt to process Soap Connection. Check log for error details', 400);
}
}
private function formPayloadAndProcessRequest($client,$data)
{
switch($data->product_type)
{
case('product1'): // this is for my first request
$payload = array("key1" => array("keyA"=>"value","keyB"=>$data->amount),
"key2" => array("keyX"=>$data->msisdn,"keyY"=>"xxxx","keyZ"=>"xxxx"),
'key3' => "xxxxx"
);
$result = $client->functionName1($payload); // call function 1
return [true, $result];
break;
case('product2'): // my second request
$payload = $this->getVodRawXml($data->request_id,'xxx',$data->product_count);
//$xmlVar = new SoapVar($payload,XSD_ANYXML);
//dd($xmlVar);
try
{
$result = $client->requestPurchase($payload); // call function 2
dd($result);
}
catch(Exception $e)
{
dd($e);
}
break;
// other product cases
default:
return [false, "Invalid product or service type supplied"];
break;
}
}
private function getVodRawXml($requestId,$productId,$productCount)
{
$rawXml = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ext="http://xxx.xxx.xxx.xxx.com/">
<soapenv:Header/>
<soapenv:Body>
<ext:requestPurchase>
<context>
<channel>xxx</channel>
<prepareOnly>xxxx</prepareOnly>
<clientReference>12q31a1a456677881</clientReference>
<clientRequestTimeout>500</clientRequestTimeout>
<initiatorPrincipalId>
<id>xxxx</id>
<type>xxxx</type>
<userId>xxxx</userId>
</initiatorPrincipalId>
<password>xxxxx</password>
<transactionProperties>
<entry>
<key>preferredLanguage</key>
<value>en</value>
</entry>
<entry>
<key>productSKU</key>
<value>xxx</value>
</entry>
<entry>
<key>currency</key>
<value>NGN</value>
</entry>
<entry>
<key>purchaseAmount</key>
<value>3</value>
</entry>
</transactionProperties>
</context>
// other elements
</ext:requestPurchase>
</soapenv:Body>
</soapenv:Envelope>';
return $rawXml;
}
}
Upvotes: 0
Views: 1612
Reputation: 554
The idea behind SoapClient and WSDL is not to deal with raw XML. Instead of using an associative array, use an object (class).
class requestPurchase
{
public context;
}
class entry
{
public key;
public value;
}
class context
{
public channel;
public prepareOnly;
public clientReference;
public transactionProperties = array();
}
$entry1 = new entry;
$entry2 = new entry;
$entry3 = new entry;
$context = new context;
$context->transactionProperties[] = $entry1;
$context->transactionProperties[] = $entry2;
$context->transactionProperties[] = $entry3;
$requestPurchase = new requestPurchase;
$requestPurchase->context = $context;
$client = new SoapClient($wsdl, array('classmap' =>
array('requestPurchase' => requestPurchase::class)));
$response = $client->requestPurchase($requestPurchase);
Upvotes: 2