Introduction
Obviously, documentation is missing here. Unfortunately, $soapClient->__getTypes()
doesn't tell much. It only shows available complex types supported by a web service, but it doesn't show us the relationship among them. Even if You have a list of all available operations with their input and output types returned by $soapClient->__getFunctions()
, there is no guarantee You can proceed without knowing the exact nature of the complex types or without having any kind of documentation. But fortunately, this is a SOAP-based web service that provides a WSDL document. The WSDL document describes all the supported operations and complex types, as well as their relationships. So, we can figure out how to use the service by only examining the WSDL document.
There are two ways of examining the WSDL document:
- generate artifacts (client classes) from the WSDL document and examine the artifacts
- look through the WSDL document and the XML Schema documents.
1. Artifacts
The artifacts can be generated by tools provided by the strong typed languages like Java or C#. The https://qa-api.ukmail.com/Services/UKMAuthenticationServices/ page suggests to use the svcutil.exe
tool to generate the artifacts for the C# programming language, or You can also use the wsimport
tool to generate the artifacts for the Java programming language. I doubt that there can be any good tool for generating the artifacts for the PHP programming language.
2. WSDL document and XML Schemas
If You're not familiar with C# or Java, You can always examine the WSDL document by looking through it and the XML Schemas. The XML Schemas can be included in the WSDL document or imported from an external file. While the WSDL document describes the operations that can be performed on the web service, the XML Schemas describe the complex types and their relationships.
Action
I wrote the Introduction part so that You know how to do it on Your own. Below I want to show an example of it. For the purpose of examining the WSDL document I used both ways. First I generated the artifacts using the wsimport
tool, then I read a lot of XML.
The WSDL document for this service is divided into several files using import
statements. So, in order to find all the operations and complex types You have to follow the import
statements.
Authentication
If We look at the Authentication Service's WSDL document (location), We can see that it imports another WSDL document:
<wsdl:import namespace="http://tempuri.org/" location="https://qa-api.ukmail.com/Services/UKMAuthenticationServices/UKMAuthenticationService.svc?wsdl=wsdl1"/>
The latter (location), in its turn, imports another one:
<wsdl:import namespace="http://www.UKMail.com/Services/Contracts/ServiceContracts" location="https://qa-api.ukmail.com/Services/UKMAuthenticationServices/UKMAuthenticationService.svc?wsdl=wsdl0"/>
The final one (location), imports all the related XML Schemas:
<wsdl:types>
<xsd:schema targetNamespace="http://www.UKMail.com/Services/Contracts/ServiceContracts/Imports">
<xsd:import schemaLocation="https://qa-api.ukmail.com/Services/UKMAuthenticationServices/UKMAuthenticationService.svc?xsd=xsd0" namespace="http://www.UKMail.com/Services/Contracts/ServiceContracts"/>
<xsd:import schemaLocation="https://qa-api.ukmail.com/Services/UKMAuthenticationServices/UKMAuthenticationService.svc?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/"/>
<xsd:import schemaLocation="https://qa-api.ukmail.com/Services/UKMAuthenticationServices/UKMAuthenticationService.svc?xsd=xsd2" namespace="http://www.UKMail.com/Services/Contracts/DataContracts"/>
<xsd:import schemaLocation="https://qa-api.ukmail.com/Services/UKMAuthenticationServices/UKMAuthenticationService.svc?xsd=xsd3" namespace="http://schemas.datacontract.org/2004/07/UKMWebAPICommon.WebResponses"/>
</xsd:schema>
</wsdl:types>
It also describes the operations which can also be viewed by calling $soapClient->__getFunctions()
:
Array
(
[0] => LoginResponse Login(Login $parameters)
[1] => LogoutResponse Logout(Logout $parameters)
)
Here, We see that the Login()
operation accepts $parameters
of type Login
as its argument and returns a response of type LoginResponse
. This is how it looks in the WSDL document:
<wsdl:operation name="Login">
<wsdl:input wsaw:Action="http://www.UKMail.com/Services/IUKMAuthenticationService/Login" message="tns:IUKMAuthenticationService_Login_InputMessage"/>
<wsdl:output wsaw:Action="http://www.UKMail.com/Services/Contracts/ServiceContracts/IUKMAuthenticationService/LoginResponse" message="tns:IUKMAuthenticationService_Login_OutputMessage"/>
</wsdl:operation>
Login
is a complex type, this can be seen in one of the imported XML Schema documents (schemaLocation):
<xs:element name="Login">
<xs:complexType>
<xs:sequence>
<xs:element xmlns:q1="http://www.UKMail.com/Services/Contracts/DataContracts" minOccurs="0" name="loginWebRequest" nillable="true" type="q1:LoginWebRequest"/>
</xs:sequence>
</xs:complexType>
</xs:element>
It has an element named loginWebRequest
which is also a complex type called LoginWebRequest
which is described in another imported XML Schema:
<xs:complexType name="LoginWebRequest">
<xs:sequence>
<xs:element name="Password" nillable="true" type="xs:string"/>
<xs:element name="Username" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
LoginWebRequest
is simpler. It has two simple types Username
and Password
of type String
.
In PHP complex types are represented by objects of stdClass
. So, in order to call the Login()
operation, We have to create two objects Login
and LoginWebRequest
:
$LoginWebRequest = new stdClass();
$LoginWebRequest->Username = 'Username';
$LoginWebRequest->Password = 'p@$$w0rd';
$Login = new stdClass();
$Login->loginWebRequest = $LoginWebRequest;
$soapClient = new SoapClient('https://qa-api.ukmail.com/Services/UKMAuthenticationServices/UKMAuthenticationService.svc?wsdl');
$LoginResponse = $soapClient->Login($Login);
This gives us a result of type LoginResponse
:
<xs:element name="LoginResponse">
<xs:complexType>
<xs:sequence>
<xs:element xmlns:q2="http://www.UKMail.com/Services/Contracts/DataContracts" minOccurs="0" name="LoginResult" nillable="true" type="q2:UKMLoginResponse"/>
</xs:sequence>
</xs:complexType>
</xs:element>
, which contains an element named LoginResult
which has a type of UKMLoginResponse
:
<xs:complexType name="UKMLoginResponse">
<xs:complexContent mixed="false">
<xs:extension base="tns:UKMWebResponse">
<xs:sequence>
<xs:element minOccurs="0" name="Accounts" nillable="true" type="tns:ArrayOfAccountWebModel"/>
<xs:element name="AuthenticationToken" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
UKMLoginResponse
has two elements of its own Accounts
of type ArrayOfAccountWebModel
and AuthenticationToken
of type String
and three more elements inhereted from UKMWebResponse
(note the extension
statement) Errors
of type ArrayOfUKMWebError
, Warnings
of type ArrayOfUKMWebWarning
and Result
of type UKMResultState
:
<xs:complexType name="UKMWebResponse">
<xs:sequence>
<xs:element minOccurs="0" name="Errors" nillable="true" type="tns:ArrayOfUKMWebError"/>
<xs:element xmlns:q1="http://schemas.datacontract.org/2004/07/UKMWebAPICommon.WebResponses" name="Result" type="q1:UKMResultState"/>
<xs:element minOccurs="0" name="Warnings" nillable="true" type="tns:ArrayOfUKMWebWarning"/>
</xs:sequence>
</xs:complexType>
In the artifacts generated by the wsimport
tool it looks like this:
public class UKMLoginResponse extends UKMWebResponse { ... }
So, in order to get the authentication token from the LoginResponse
, we do the following:
$LoginResponse = $soapClient->Login($Login);
$AuthenticationToken = $LoginResponse->LoginResult->AuthenticationToken;
Calling a method
I won't be very specific here, because it's very similar to what we did above.
As an example, let's call a AddDomesticConsignment()
method. According to the WSDL document of the Consignment Service and the result returned by $soapClient->__getFunctions()
the AddDomesticConsignment()
method takes one $parameters
argument of type AddDomesticConsignment
and returns a result of type AddDomesticConsignmentResponse
. By analyzing the AddDomesticConsignment
complex type, we see that it has an element named request
of type AddDomesticConsignmentWebRequest
which extends AddConsignmentWebRequest
which itself extends WebRequest
. Following is the list of all of the elements of the AddDomesticConsignmentWebRequest
type:
// AddDomesticConsignmentWebRequest's own elements
boolean BookIn
decimal CODAmount
string ConfirmationEmail
string ConfirmationTelephone
boolean ExchangeOnDelivery
int ExtendedCover
boolean LongLength
PreDeliveryNotificationType PreDeliveryNotification
string SecureLocation1
string SecureLocation2
boolean SignatureOptional
// elements inhereted from AddConsignmentWebRequest
string AccountNumber
AddressWebModel Address
string AlternativeRef
string BusinessName
string CollectionJobNumber
boolean ConfirmationOfDelivery
string ContactName
string CustomersRef
string Email
int Items
int ServiceKey
string SpecialInstructions1
string SpecialInstructions2
string Telephone
decimal Weight
// elements inhereted from WebRequest
string Username
string AuthenticationToken
Note that not all of the elements are required. Those which are optional have the