CONSUMING A SOAP WEB SERVICE HAVING COMPLEX TYPES IN PHP USING WSDL2PHPGENERATOR TOOL

PLEASE SHARE

This article describes how to develop a SOAP Web Service Client in PHP that will handle complex types. Consuming a web service is supposed to be an easy and straightforward task but still, can pose some challenges and nitty-gritty whenever a developer is trying to integrate with a new web service. 

So, this article will explain a standard way to consume a SOAP Web Service by utilizing a  free tool called “wsdl2phpgenerator”.

PREREQUISITES

1) Any Web Server supporting PHP language (Like Apache, IIS). I am using XAMPP v3.2.2 on Windows 10. (Assume the document root directory is “C:\xampp\htdocs”)

2) PHP is available on the system path. Go to command prompt and enter “php –version” command, make sure its printing version information.

3) Download “wsdl2phpgenerator-2.3.0.phar” file from the URL “https://github.com/wsdl2phpgenerator/wsdl2phpgenerator/releases/download/2.3.0/wsdl2phpgenerator-2.3.0.phar”. Save this file under “C:\wsdl2phpgenerator”directory.

4) For the demo purpose, we are going to consume the following web service available online,

https://thedeveloperfriend.com/stock_soap_ws/GetStockService.php?wsdl

5) Make sure the php.ini file (C:\xampp\php\php.ini) is having the following configuration. If not create the same,

extension=php_soap.dll

ABOUT THE DEMO SOAP SERVICE

The demo SOAP service ( https://thedeveloperfriend.com/stock_soap_ws/GetStockService.php?wsdl ) we are going to consume is a simple stock information service. It will take a stock symbol as an input and provides information about that stock which includes the following,

Open, High, Low, and Close values.

CEO information such as Name, Salary, and Age.

Last Three-year financials such as Gross Revenue and Net Revenue.

The request and response of this SOAP service are complex types. Here are the sample request and response,

SAMPLE 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/">
   <soapenv:Header/>
   <soapenv:Body>
      <getStock soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <symbol xsi:type="get:StockInfoRequest" xmlns:get="https://thedeveloperfriend.com/stock_soap_ws/GetStockService.php?WSDL">
            <symbol xsi:type="xsd:string">MSFT</symbol>
            <tradingDate xsi:type="xsd:string">12/12/2019</tradingDate>
         </symbol>
      </getStock>
   </soapenv:Body>
</soapenv:Envelope>

SAMPLE RESPONSE

<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 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:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="https://thedeveloperfriend.com/stock_soap_ws/GetStockService.php?WSDL">
   <SOAP-ENV:Body>
      <ns1:getStockResponse xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/">
         <return xsi:type="tns:Stock">
            <stockId xsi:type="xsd:int">1</stockId>
            <symbol xsi:type="xsd:string">MSFT</symbol>
            <open xsi:type="xsd:decimal">179.5</open>
            <high xsi:type="xsd:decimal">180</high>
            <low xsi:type="xsd:decimal">177</low>
            <close xsi:type="xsd:decimal">178.68</close>
            <ceo xsi:type="tns:CEO">
               <ceoId xsi:type="xsd:int">1</ceoId>
               <name xsi:type="xsd:string">Satya Nadella</name>
               <salary xsi:type="xsd:decimal">13.24</salary>
               <age xsi:type="xsd:int">50</age>
            </ceo>
            <lastThreeYearFinancial xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType=":[3]">
               <item xsi:type="xsd:">
                  <year xsi:type="xsd:int">2019</year>
                  <grossRevenue xsi:type="xsd:float">5.5</grossRevenue>
                  <netRevenue xsi:type="xsd:float">4.4</netRevenue>
               </item>
               <item xsi:type="xsd:">
                  <year xsi:type="xsd:int">2018</year>
                  <grossRevenue xsi:type="xsd:float">6.5</grossRevenue>
                  <netRevenue xsi:type="xsd:float">5</netRevenue>
               </item>
               <item xsi:type="xsd:">
                  <year xsi:type="xsd:int">2017</year>
                  <grossRevenue xsi:type="xsd:float">5</grossRevenue>
                  <netRevenue xsi:type="xsd:float">4</netRevenue>
               </item>
            </lastThreeYearFinancial>
         </return>
      </ns1:getStockResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

CREATING NEW WEB APPLICATION

1) Create a directory “stock_info_ws_client” under “C:\xampp\htdocs”,

cd C:\xampp\htdocs

mkdir stock_info_ws_client

2) Create a directory “ws_classes” under “C:\xampp\htdocs\stock_info_ws_client”

cd C:\xampp\htdocs\stock_info_ws_client

mkdir ws_classes

This “ws_classes” directory will hold all the PHP files generated by the “wsdl2phpgenerator” tool. These files will be used by the web application to communicate with the web service.

GENERATING PHP FILES FROM WSDL

1) Go to the tool directory and execute the following command,

cd C:\wsdl2phpgenerator

php wsdl2phpgenerator-2.3.0.phar -i https://thedeveloperfriend.com/stock_soap_ws/GetStockService.php?wsdl -o  C:\xampp\htdocs\stock_info_ws_client\ws_classes

It will print “Generation Completed” if the operation is successful.

The above command will scan the WSDL URL and auto-generate the PHP files under the web application subdirectory. These are files required to communicate with web service.

2) Go to “C:\xampp\htdocs\stock_info_ws_client\ws_classes” directory and make sure the files are generated,

UNDERSTANDING WSDL AND THE PHP FILES GENERATED

Let’s have a look at the PHP files generated along with WSDL to have a better understanding of how to call any SOAP web service. In particular, we need to identify the method we need to call and it’s input and output parameters.

1) Open the WSDL URL “https://thedeveloperfriend.com/stock_soap_ws/GetStockService.php?wsdl” in the browser.

2) Look for the service element in WSDL.

<service name="GetStockService">
  	<port name="GetStockServicePort" binding="tns:GetStockServiceBinding">
    		<soap:address location="https://thedeveloperfriend.com:443/stock_soap_ws/GetStockService.php"/>
  	</port>
</service>

From the above element, we can see the service name is GetStockService.

We have a corresponding PHP file generated “GetStockService.php”. This is the main file through which we will call the operations (aka methods) of this web service.

Copy the binding attribute value “GetStockServiceBinding” as highlighted.

3) Search for the binding element having the name as “GetStockServiceBinding” copied in the above step,

<binding name="GetStockServiceBinding" type="tns:GetStockServicePortType">
  	<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
  	<operation name="getStock">
    		<soap:operation soapAction="https://thedeveloperfriend.com/stock_soap_ws/GetStockService.php/getStock" style="rpc"/>
    		<input><soap:body use="encoded" namespace="" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
    		<output><soap:body use="encoded" namespace="" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
  	</operation>
</binding>

Copy the type attribute value “GetStockServicePortType” as highlighted.

4) Search for the portType element having the name “GetStockServicePortType” copied in the above step.

<portType name="GetStockServicePortType">
  	<operation name="getStock">
    		<input message="tns:getStockRequest"/>
    		<output message="tns:getStockResponse"/>
  	</operation>
</portType>

From the above element, we can see there’s an operation (aka method) called “getStock” that we would like to call. Please note the input and output messages highlighted above.

5) Search for the message elements having the names we have identified in the above step (getStockRequest & getStockResponse)

<message name="getStockRequest">
  	<part name="symbol" type="tns:StockInfoRequest" />
</message>
<message name="getStockResponse">
  	<part name="return" type="tns:Stock" />
</message>

From the above elements, we can see the request and response data types for the operation “getStock”. As highlighted above, the request data type is “StockInfoRequest” and response data type is “Stock”

6) Search for the complexType element for the request data type “StockInfoRequest” identified in the above step,

<xsd:complexType name="StockInfoRequest">
  	<xsd:all>
   		<xsd:element name="symbol" type="xsd:string"/>
   		<xsd:element name="tradingDate" type="xsd:string"/>
  	</xsd:all>
</xsd:complexType>

We have a corresponding PHP file generated “StockInfoRequest.php”. This file is representing the above complexType element.

7) Search for the complexType element for the response data type “Stock” identified in step number 5,

<xsd:complexType name="Stock">
  	<xsd:all>
   		<xsd:element name="stockId" type="xsd:int"/>
   		<xsd:element name="symbol" type="xsd:string"/>
   		<xsd:element name="open" type="xsd:decimal"/>
   		<xsd:element name="high" type="xsd:decimal"/>
   		<xsd:element name="low" type="xsd:decimal"/>
   		<xsd:element name="close" type="xsd:decimal"/>
   		<xsd:element name="ceo" type="tns:CEO"/>
   		<xsd:element name="lastThreeYearFinancial" type="tns:ArrayOfYearlyFinancial"/>
  	</xsd:all>
 </xsd:complexType>

We have a corresponding PHP file generated “Stock.php”. This file is representing the above complexType element.

Also please note, this Stock complex type is having references for other 2 complex types CEO & ArrayOfYearlyFinancial as highlighted above.

8) Let’s have look at the CEO complex type which is referenced by Stock complex type,

<xsd:complexType name="CEO">
  	<xsd:all>
   		<xsd:element name="ceoId" type="xsd:int"/>
   		<xsd:element name="name" type="xsd:string"/>
   		<xsd:element name="salary" type="xsd:decimal"/>
   		<xsd:element name="age" type="xsd:int"/>
  	</xsd:all>
 </xsd:complexType>

We have a corresponding PHP file generated “CEO.php”. This file is representing the above complexType element.

9) Let’s have look at the ArrayOfYearlyFinancial complex type which is referenced by Stock complex type,

<xsd:complexType name="ArrayOfYearlyFinancial">
  	<xsd:complexContent>
   		<xsd:restriction base="SOAP-ENC:Array">
    			<xsd:attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="tns:YearlyFinancial[]"/>
   		</xsd:restriction>
  	</xsd:complexContent>
 </xsd:complexType>

As highlighted above this complex type is representing an array of another complex type called “YearlyFinancial”. Let’s lookup for the same,

<xsd:complexType name="YearlyFinancial">
  	<xsd:all>
   		<xsd:element name="year" type="xsd:int"/>
   		<xsd:element name="grossRevenue" type="xsd:decimal"/>
   		<xsd:element name="netRevenue" type="xsd:decimal"/>
  	</xsd:all>
 </xsd:complexType>

We have a corresponding PHP file generated “YearlyFinancial.php”. This file is representing the above complexType element.

CLASS DIAGRAM OF REQUEST AND RESPONSE COMPLEX TYPES

Now that we have mapped the complex types available with the PHP file generated by the wsdl2phpgenerator tool, let’s have a look at the class diagrams for better understanding.

REQUEST COMPLEX TYPE

As we can see the “StockInfoRequest” is a simple class having 2 fields.

RESPONSE COMPLEX TYPE

The Stock class will be used for sending the web service response. The Stock class is having associations with CEO and YearlyFinancial classes. As per the diagram below, the stock class is having a one-to-one relationship with the CEO class. So we can say the CEO is nested inside Stock.

The Stock class is also having a one-on-many relationship with the YearlyFinancial class. So a Stock can have a reference to an array or list of YearlyFinancial classes.

CODING SOAP CLIENT

Let’s start coding a simple UI as shown below to call the web service. Users can enter a stock symbol & trading date and get the stock information using web service.

  1. Create a new file “get_stock_info.php” under the directory “C:\xampp\htdocs\stock_info_ws_client” and copy the following content, (Please read the comment lines to understand the logic)
<?php
//include the files generated by wsdl2phpgenerator tool
require_once 'ws_classes/CEO.php';
require_once 'ws_classes/Stock.php';
require_once 'ws_classes/StockInfoRequest.php';
require_once 'ws_classes/YearlyFinancial.php';
require_once 'ws_classes/GetStockService.php';

?>

<!DOCTYPE html>
<html>
  <head>
    <title>Stock Info SOAP Client</title>
	<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100;400&display=swap" rel="stylesheet">
	<style>
		body{
			font-family: 'Roboto', sans-serif;
		}
	</style>
  </head>
  <body>
    <h2>Stock Info SOAP Client</h2>
    
    <form action="/stock_info_ws_client/get_stock_info.php">
 	 Enter Stock Symbol:
 	 <input type="text" name="symbol" >
	 Enter Trading Date:
	 <input type="text" name="tradingDate" >
 	 <input type="submit" value="GET STOCK INFO">
    </form>
    <BR>
<?php
//Make sure user entered value
if (!empty($_GET["symbol"])) {

  //Create service object
  $service = new GetStockService();

  //Create request object
  $request = new StockInfoRequest($_GET["symbol"], $_GET["tradingDate"]);

  //Call Web Service and get response
  $stock = $service->getStock($request);
  
  //Get CEO nested object from Stock
  $ceo = $stock->ceo;
  
  //Get the array of YearlyFinancial from Stock
  $lastThreeYearFinancial = $stock->lastThreeYearFinancial;
  

  echo '<h3>Daily Price : </h3>';
  echo 'Stock ID =' . $stock->stockId . '<BR>';
  echo 'Stock Symbol =' . $stock->symbol . '<BR>';
  echo 'Open =' . $stock->open . '<BR>';
  echo 'High =' . $stock->high . '<BR>';
  echo 'Low =' . $stock->low . '<BR>';
  echo 'Close =' . $stock->close . '<BR>';
  
  echo '<h3>About CEO : </h3>';
  echo 'CEO ID =' . $ceo->ceoId . '<BR>';
  echo 'CEO Name =' . $ceo->name . '<BR>';
  echo 'CEO Salary =' . $ceo->salary . '<BR>';
  echo 'CEO Age =' . $ceo->age . '<BR>';
  
  echo '<h3>Last Three Year Financials : </h3>';
  echo '<ul>';
  
  foreach($lastThreeYearFinancial as $yearlyFinancial) {
	  echo '<li>';
	  echo 'Year : ' . $yearlyFinancial->year;
	  
	  echo '<ul>';
		echo '<li>Gross Revenue : ' . $yearlyFinancial->grossRevenue .'</li>';
		echo '<li>Net Revenue : ' . $yearlyFinancial->netRevenue .'</li>';
	  echo '</ul>';
	  
	  echo '</li>';
  }
  
  echo '</ul>';
  

}

?>
  </body>
</html>

TEST THE APPLICATION

  1. Test the SOAP client by visiting the URL,

http://localhost/stock_info_ws_client/get_stock_info.php

PROJECT ON GITHUB

This demo SOAP client project can be downloaded from this GitHub repository,

https://github.com/rajeshkumarraj82/consuming-soap-web-service-having-complex-types-in-php

HOW TO CREATE THE DEMO PHP SOAP SERVICE

If you are interested to know how to develop the demo SOAP service we consumed here, Please visit https://www.thedeveloperfriend.com/soap-web-services/create-php-soap-web-service/

Follow Me

Leave a Reply

Your email address will not be published. Required fields are marked *

77 + = 80