Complex Calls With Soap Client
I've just started using the SOAP Client module in Drupal to handle SOAP requests. It's a great little tool. If you set it to use the nuSOAP PHP libraries (instead of core) it even handles Microsoft datasets, which some Microsoft-based web services will return.
There is one small problem. Documentation is approximately zero! The only assistance offered is "look at the code of the admin test form", which is great for simple name/value pairs of data, but doesn't tackle complex types.
SOAP Client works much like the XML-RPC client which is core to Drupal. You build an array of parameters and pass them to a function which wraps them in a SOAP envelope and passes them on to the web service, then handles the returned result. But what happens if you have a structure like this?
<requiredMortgageRateTypes>
<MortgageRateTypeEnum>Variable</MortgageRateTypeEnum>
<MortgageRateTypeEnum>Fixed</MortgageRateTypeEnum>
</requiredMortgageRateTypes>Of course arrays cannot have duplicate keys. We would have to pass the following in PHP to send these parameters:
<?php
array(
'requiredMortgageRateTypes' => array(
'MortgageRateTypeEnum' => 'Variable',
'MortgageRateTypeEnum' => 'Fixed',
),
);
?>Which is illegal, so we can't. The answer is the code below. This is how you deal with multiple values in the same XML tag using Drupal SOAP Client:
<?php
array(
'requiredMortgageRateTypes' => array(
'MortgageRateTypeEnum' => array(
'Variable',
'Fixed',
),
),
);
?>

Bill, I've been piecing
Bill, I've been piecing together SOAP today and I found the following page also helpful:
http://www.lokad.com/WsPhpTutorial.ashx
Great Definition of Problem - any Advice?
Greg,
It is great to have idetified someoen who says they have actually used web services as a client in Drupal.
I am a total Drupal newbie and also a PHP newbie, but an experienced developer who has developed in many programming languages over the years (but mostly Microsoft) and am a very experience database developer.
Could you point me to any hello world like examples of a module using SOAP Client? Something like a module that calls a web service and gets some value and displays those values. That would help us get started.
Also, is there any group in Drupal that is focused more on integrating Drupal with remote applications or databases? Frameworks, code generators and the like have sort of been a hobby of mine for many years and I would like to get more involved with others with similar interests.
Thanks in advance for any information.
Bill Graham
Example
Ok, so I get too many requests for this now. Here's the submit function from the module I usually send to people who ask for an example. There's loads of irrelevant crap in there, but if you look past all that, the guts of working with a SOAP web service are there:
<?php
/**
* Submit function for processing the mortgage calculator data.
*
* This is where our web service actually gets called.
*/
function mortgage_calculator_submit(&$form,&$form_state) {
// get web service details
$wsdl = variable_get('defaqto_mortgages_calculator_url','http://calculators.internaltest.co.uk/calculators/mortgages/V2_1/Mortgages.asmx?WSDL');
$username = variable_get('defaqto_mortgages_calculator_username', '');
$pword = variable_get('defaqto_mortgages_calculator_password', '');
// initialise web service and get guid to use in request
$options = array();
$options['use'] = 'encoded';
$options['style'] = 'rpc';
$client = soapclient_init_client($wsdl, 1, $options);
// if cant establish connection, log error and exit.
if(!empty($client['#error'])){
drupal_set_message(t('Could not open connection to the webservice'));
watchdog('mortgages calculator', t('couldnt connect to webservice'), array(), WATCHDOG_ERROR);
return;
}
// get username pass in args and login to webservice
$login = array(
'username' => $username,
'password' => $pword,
);
//Call the login webmethod with the relevant parameters
$result = $client['#return']->call('Login', $login);
if( $result['#error'] !== FALSE ){
drupal_set_message(t('Error: Could not login to webservice'), 'error');
return;
}
// Form the parameters to be used in the FindBestMortgages webmethod
$guid = $result['#return']['LoginResult'];
$mortgageterm = $form_state['values']['mortgageterm'];
$calccostover = $form_state['values']['calccostover'];
$houseprice = $form_state['values']['houseprice'];
$mortgageamount = $form_state['values']['mortgageamount'];
$firstappincome = $form_state['values']['firstappincome'];
$secondappincome = $form_state['values']['secondappincome'];
$reason = $form_state['values']['reason'];
// note that there will only be one payment method (radio buttons), and one will be selected by default
$paymentmethod = array('MortgagePaymentMethodEnum' => $form_state['values']['paymentmethod']);
// Rate Types
$ratetype = array();
$mortgageRateTypeEnumArray = array();
foreach ($form_state['values']['ratetype'] as $key => $value)
{
if (!is_null($value) && $value<>"All")
{
array_push($mortgageRateTypeEnumArray,$value);
}
}
if(!empty($mortgageRateTypeEnumArray)){
$ratetype = array('MortgageRateTypeEnum' => $mortgageRateTypeEnumArray);
}
// Initial rate period
$initialrateperiod = $form_state['values']['initialrateperiod'];
// Product options
$productoptions = array();
$mortgageProductOptionsEnumArray = array();
foreach ($form_state['values']['productoptions'] as $key => $value)
{
if (!is_null($value) && $value<>"All")
{
array_push($mortgageProductOptionsEnumArray,$value);
}
}
if(!empty($mortgageProductOptionsEnumArray)){
$productoptions = array('MortgageProductOptionsEnum' => $mortgageProductOptionsEnumArray);
}
// Excluded providers
$excludedproviders = array(); //Exclude no providers
// Required Countries
$requiredcountries = array();
$countriesAvailableInEnumArray = array();
foreach ($form_state['values']['requiredcountries'] as $key => $value)
{
if ($value<>"All")
{
array_push($countriesAvailableInEnumArray,$value);
}
}
if(!empty($countriesAvailableInEnumArray)){
$requiredcountries = array('CountriesAvailableInEnum' => $countriesAvailableInEnumArray);
}
//Include regional products
$includeregionalproducts = 'true';
// Required dictribution channels
$requiredDistributionChannel = array();
$distributionChannelEnumArray = array();
foreach (array("Branch","Intermediary","Telephone","Internet") as $key => $value)
{
array_push($distributionChannelEnumArray,$value);
}
if(!empty($distributionChannelEnumArray)){
$requiredDistributionChannel = array('DistributionChannelEnum' => $distributionChannelEnumArray);
}
// Purchase Types to include
$purchaseTypesToInclude = array('PurchaseTypesToIncludeEnum' => array("SharedOwnershipOnly","RightToBuyOnly","SelfCertifiedOnly"));
// Results Options
$resultsOptions = array('ResultsOptionsEnum'=>"ShowERCColumn",);
// Calculation Options
$calculationOptions = array('CalculationOptionsEnum','IncludeERCInTrueCost',);
// Size of results set
$numberofproducts = "100";
// Sort field for results
//$sortby = $form_state['values']['sortby'];
$sortby = 'QuotedAPR';
// Refactor fields
$calccostover=$calccostover*12;
if (trim($firstappincome)=="")
{
$firstappincome="50000";
}
if (trim($secondappincome)=="")
{
$secondappincome="0";
}
if (empty($requiredcountries) OR !isset($requiredcountries) )
{
$requiredcountries = array('CountriesAvailableInEnum' => array('England','Wales','Scotland'),);
}
// Build the parameter array
$mortgageargs = array(
'userToken' => $guid,
'mortgageTerm' => $mortgageterm,
'noMonthsToCalculateCostOver' => $calccostover,// defaulting to 36
'housePrice' => $houseprice,
'mortgageAmount' => $mortgageamount,
'firstApplicantIncome' => $firstappincome,
'secondApplicantIncome' => $secondappincome,
'reasonForMortgage' => $reason,
'requiredPaymentMethods' => $paymentmethod,
'requiredMortgageRateTypes' => $ratetype,
'requiredInitialRateMonths' => $initialrateperiod, // defaulting to 36
'requiredMortgageProductOptions' => $productoptions,
'excludeProviderList' => $excludedproviders,
'requiredCountries' => $requiredcountries,
'includeRegionalProducts' => $includeregionalproducts,
'requiredDistributionChannel' => $requiredDistributionChannel,
'purchaseTypesToInclude' => $purchaseTypesToInclude,
'resultsOptions' => $resultsOptions,
'calculationOptions' => $calculationOptions,
'overridingProductCodes' => array(),
'numberOfProductsToReturn' => $numberofproducts,
'sortBy' => $sortby,
);
// Find the Best mortgages
$result = $client['#return']->call('FindBestMortgages', $mortgageargs);
// output results if error
if( $result['#error'] !== FALSE){
drupal_set_message('An error occurred');
}
else
{
// Empty the
if(empty($result['#return']['FindBestMortgagesResult']['diffgram'])){
drupal_set_message(t('Your search return no results, Please adjust your criteria and try again.'));
$form_state['redirect'] = FALSE;
}
else
{
//save results in storage, automatically rebuild the form.
$form_state['storage']['results'] = $result['#return']['FindBestMortgagesResult']['diffgram']['NewDataSet']['BestMortgages'];
}
}
}
?>
No
Edit: DON'T contact me about this! My example is RIGHT HERE already, on this very page!
But I do have an example I don't mind sharing. Contact me via the contact page on this site and I'll email you a sample module. At some point I'll clean it up and post it as an example, but that takes time and time I don't have! =/
and for attribute of
and for attribute of items?
<requiredMortgageRateTypes <b>attribute="someValue"</b>><MortgageRateTypeEnum>Variable</MortgageRateTypeEnum>
<MortgageRateTypeEnum>Fixed</MortgageRateTypeEnum>
</requiredMortgageRateTypes>
thanks
Post new comment