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',
    ),
  ),
);
?>

7 comments

by Anonymous on Thu, 10/12/2009 - 13:58

and for attribute of items?

<requiredMortgageRateTypes <b>attribute="someValue"</b>>
  <MortgageRateTypeEnum>Variable</MortgageRateTypeEnum>
  <MortgageRateTypeEnum>Fixed</MortgageRateTypeEnum>
</requiredMortgageRateTypes>

thanks

by bg1 on Thu, 17/12/2009 - 06:02

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

by greg.harvey on Thu, 17/12/2009 - 12:07

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! =/

by greg.harvey on Mon, 01/03/2010 - 20:26

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','<a href="http://calculators.internaltest.co.uk/calculators/mortgages/V2_1/Mortgages.asmx?WSDL'">http://calculators.internaltest.co.uk/calculators/mortgages/V2_1/Mortgag...</a>);

 
$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'];

    }

  }

}
?>

by Anonymous on Fri, 19/02/2010 - 14:45

Bill, I've been piecing together SOAP today and I found the following page also helpful:

http://www.lokad.com/WsPhpTutorial.ashx

by Anonymous on Fri, 03/09/2010 - 19:55

Do you have any idea on how to use the drupal soapclient with basic http authentication? I am getting permission denied when trying to connect to a soap server using http basic authentication.

by K. Kaland on Sat, 19/02/2011 - 07:57

Rather late to respond to Anonymous now, but if anyone else is wondering this, my guess would be that you have to put the authentication parameters in the URL itself...this is how it usually goes when programmatically accessing a URL in this way.

Post new comment

© 2010 Greg Harvey. Drupal theme by Kiwi Themes.