PHP-如何在XML请求正文中的同名节点下发送具有多个元素的SoapClient请求?

时间:2019-11-18 15:13:02

标签: php xml laravel soap soap-client

我尝试使用WSDL使用两个 SOAP端点。我已经能够成功实现第一个,但是由于XML请求主体格式的方式,第二个我现在遇到了问题-它在一个具有相同名称的节点下包含多个元素。我正在使用PHP数组/嵌套数组来构造有效负载。第一次运行良好,因为不存在父元素包含多个同名子元素的情况。

这是我的第二个XML请求的正文

<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>

我在entry下有transactionProperties次出现了 4次。我第一次使用的方法不适用于second request,因为PHP使用唯一的数组键(或者有一种绕过该键的方法)。我也尝试使用原始XML,但仍无法正常工作。我很高兴获得解决方案。谢谢!

这是我的代码的样子(使用Laravel / PHP框架):

<?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; 
  }

}

1 个答案:

答案 0 :(得分:2)

SoapClient和WSDL背后的思想是不处理原始XML。代替使用关联数组,而使用对象(类)。

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);