Published on WSO2 Oxygen Tank (http://wso2.org)

PHP Web Services with WSDL

By dimuthuc
Created 2008-03-20 06:32

In this introductory tutorial, Dimuthu Gamage explains how you can use the contract first model, which is also called WSDL mode, to write your Web services and clients using WSO2 WSF/PHP.

 

Applies To

WSO2 WSF/PHP [1] 1.2.0 or higher [2]
Environment Windows or Linux

 

Introduction

In writing a Web service, you can choose from one of the two available approaches to developing them. They are,

  1. code-first approach
  2. contract-first approach.

In the code first approach,  you will initially code the interface you hope to publish as a Web Service. Then you generate the WSDL that becomes the contract (at least the major part of the contract), based on the written code. In contract-first approach, you start with the WSDL and then generate the code using a programming language. From the given approaches you need to selectively choose the one that best suits your problem environment. You can find discussions on these topics in these articles[1] [3].

In writing Web services in PHP, WSO2 WSF/PHP (Web Services Framework for PHP) helps you, regardless of the approach you choose to follow. If you choose the contract-first approach, the framework is able to provide you with a PHP friendly interface for the development of the WSDL.

i.e.

 

In this tutorial, I will illustrate how you can develop a very simple Web service and a client using the Contract-first approach.

The following are the steps to follow:

 

Table of Contents

 

Axis2 Java2WSDL[2] [4] or WSF/PHP [5] itself. For the service mentioned above, the WSDL should look like the following..

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:ns1="http://org.apache.axis2/xsd"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:ns0="http://HighSchool.edu"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
targetNamespace="http://HighSchool.edu"> <wsdl:types> <xs:schema xmlns:ns="http://HighSchool.edu" xmlns:ns1="http://HighSchool.edu/xsd" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://HighSchool.edu"> <xs:element name="ExamResult"> <xs:complexType> <xs:sequence> <xs:element name="studentName" type="xs:string"/> <xs:element name="subject" type="xs:string"/> <xs:element name="year" type="xs:int"/> <xs:element name="semester" type="xs:int"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="ExamResultResponse"> <xs:complexType> <xs:sequence> <xs:element name="result" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> </wsdl:types> <wsdl:message name="ExamResultRequest"> <wsdl:part name="parameters" element="ns0:ExamResult"/> </wsdl:message> <wsdl:message name="ExamResultResponse"> <wsdl:part name="parameters" element="ns0:ExamResultResponse"/> </wsdl:message> <wsdl:portType name="ExamResultPortType"> <wsdl:operation name="ExamResult"> <wsdl:input message="ns0:ExamResultRequest" wsaw:Action="urn:ExamResult"/> <wsdl:output message="ns0:ExamResultResponse" wsaw:Action="urn:ExamResultResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="ExamResultSOAP12Binding" type="ns0:ExamResultPortType"> <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/> <wsdl:operation name="ExamResult"> <soap12:operation soapAction="urn:ExamResult" style="document"/> <wsdl:input> <soap12:body use="literal"/> </wsdl:input> <wsdl:output> <soap12:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="ExamResult"> <wsdl:port name="ExamResultSOAP12port_http" binding="ns0:ExamResultSOAP12Binding"> <soap12:address location="http://localhost:8080/axis2/services/ExamResult"/> </wsdl:port> </wsdl:service> </wsdl:definitions>

 

 

 

array [6]( "Maths" => array [7]("Hiro" => "A+", "Clair" => "A+", "Peter" => "A+", "Mohinder" => "A+", "Ando" => "A", "Niki" => "B", "Sylar" => "F"), "Science" => array [8]("Hiro" => "B+", "Clair" => "B+", "Peter" => "B+", "Mohinder" => "B+", "Ando" => "B", "Niki" => "C", "Sylar" => "-")); /* This is the default result */ $result = "-"; if($year != 2007 && $semester != 2) { $result = "-"; } else if($exam_results[$subject] != NULL && is_array [9]($exam_results[$subject])) { $result = $exam_results[$subject][$studentName]; } /* Remember in the response we had 'result' element */ return array [10]("result"=> $result); } /* Map of the service operation "ExamResult" to php function "ExamResult" */ $operations = array [11]("ExamResult" => "ExamResult"); /* just tell your function parameters should be in mixed format,
that is here parameter will be the string with the name in it*/ $opParams = array [12]("ExamResult" => "MIXED"); /* Created the WSService */ $svr = new WSService(array [13]("wsdl" => "ExamResult.wsdl", "operations" => $operations, "opParams" => $opParams)); /* Reply the client */ $svr->reply();  ?>

Here, the ExamResult function is where you put your operational logic. It gives you the variables $studentName, $subject, $year and $semester filled with the values sent by the client. Since this code is written for the purpose of the tutorial, I'm keeping all results in an array. But in a more practical environment, results will be most probably held in a database, where you query results using the given parameters. Right at the end, I have assigned the result to the $result variable. Note how I return the result:

return array("result"=> $result);

Here, "result" is for the response XML element to wrap the actual result. (We have discussed this in an earlier section under the response schema).

When creating the WSService object, I have given three arguments within the constructor. They are,

"wsdl" location of the WSDL
"operations" this is a mapping of the service operation to the php function. for this example both are "ExamResult"
"opParams" This is to indicate that, in the php function which maps to the service operation (i.e. ExamResult function), arguments should be simple PHP types corresponding to the input message. if you do not explicitly set this, the argument to the function will be an object of WSMesssage.

In order to deploy the service, you may place the service script in the htdocs directory  in the Apache server. I have named my script 'service.php' and therefore my service endpoint is http://localhost/Service.php.

You don't need to restart the Apache server after you place this script.. Just go to the browser and type "http://localhost/Service.php". This will give you a list of services that are deployed already and their operations. Confirm your service listing.

 

array [14]( "wsdl" => "ExamResult.wsdl",
"to" => "http://localhost/Service.php")); /* we need to take the proxy object to call the wsdl operation */ $proxy = $wsclient->getProxy(); /* Right here I'm calling the ExamResult function with argument "Hiro"
Remeber in the WSDL we had "ExamResult" operation with name argument */ $ret_val = $proxy->ExamResult(array [15]("studentName" => "Hiro", "subject" => "Maths", "year" => 2007, "semester" => "2")); /* Retrive the response. Just to recall, response had the element 'return' */ echo [16] $ret_val["result"]."\n"; ?>

In the constructor for the WSClient, I have included both a WSDL location mapped to "wsdl" and a service endpoint mapped to "to". If your service endpoint is the same as the one in the WSDL, you can ignore the "to" setting. Check the location attribute in soap12:address element to check what the service endpoint defined in the WSDL is:

   <wsdl:service name="ExamResult">
        <wsdl:port name="ExamResultSOAP12port_http" binding="ns0:ExamResultSOAP12Binding">
            <soap12:address location="http://localhost:8080/axis2/services/ExamResult"/>
        </wsdl:port>
    </wsdl:service>

If you set "to" value in the WSClient constructor, this will override the service endpoint specified in the WSDL.

Then you access the proxy object from the $wsclient using getProxy() function. The $proxy is the object that allows you to invoke the service operation, just the same way you call a simple php function with the arguments that you provide to form the request message. The key "result" in the response Hash Map will return your final result.

This section demonstrated how you can write a simple client for a given WSDL. You used arrays to input request arguments and access response arguments, but, there is another way you can do the same thing. There, instead of arrays, you will be using php classes.

 

array [17]("ExamResult"=> "ExamResult", "ExamResultResponse"=> "ExamResultResponse"); /* create the WSClient with the given WSDL and my service endpoint
Note: Here im overwriting the endpoint declared in the WSDL */ $wsclient = new WSClient( array [18]( "classmap" => $class_map, "wsdl" => "ExamResult.wsdl",
"to" => "http://localhost/Service.php")); /* we need to take the proxy object to call the wsdl operation */ $proxy = $wsclient->getProxy(); /* prepare the input */ $input = new ExamResult(); $input->studentName = "Hiro"; $input->subject = "Maths"; $input->year= "2007"; $input->semester = "2"; /* Right here I'm calling the ExamResult function with argument as the ExamResult instance
Remeber in the WSDL we had "ExamResult" operation with name argument */ $ret_val = $proxy->ExamResult($input); /* Retrive the response. Just to recall, our response is an instance of ExamResultResponse */ echo [19] $ret_val->result."\n"; ?>

In order to tell WSF/PHP, that you are using class map API, you have to provide one more argument to the WSClient constructor. That is,

"classmap" Map of Schema Element to the PHP Class. (In this case the PHP Classes have to have the same names of the schema elements)

So, in contrast to the earlier case, you can see that you provide a class object filled with your request data to the function and that your output is  also a class object filled with response data. At a glance this may not seem like much of a difference with the earlier method, but, imagine you already have a class object filled data, then it would be really convenient to set that, as the input to the service - rather than explicitly converting that to a hash map. So class mapping gives you the flexibility to use PHP classess according to your very specific requirements.

 

Conclusion

This tutorial is a step by step guide to using WSO2 WSF/PHP API to build your services and consumers starting from a WSDL. (i.e. Contract-first approach). The tutorial introduces the WSDL mode API of the WSO2 Web Service Framework for PHP, and how to write your own Web services and clients with minimum effort using a given WSDL.

 

References

 

Author

Dimuthu Gamage is a Software Engineer at WSO2. He is a commiter of the Apache Web Services project and a developer of the WSF/PHP and WSF/Ruby projects. dimuthu at wso2 dot com.


Source URL:
http://wso2.org/library/3393