Users guide:Web Services

Abstract: A webservice is a modular application that publishes certain features called services on the internet. VCL for PHP provides a component to make easy the tasks to develop a web service.

Note: A sample can be found on <delphiforphp>/vcl/Web Service

    Creating the DataModule

Webservices are best suited to live on DataModules instead of Pages, because they don't provide visual output, to create a Data Module, if you are a Delphi for PHP user, just use the option File | New | Data Module and you will get it on the form designer, if you want to create one using only the library, inherit from DataModule:

 
<?php
        require_once("vcl/vcl.inc.php");
        //Includes
        use_unit("forms.inc.php");
        use_unit("extctrls.inc.php");
        use_unit("stdctrls.inc.php");
 
        //Class definition
        class SoapServer extends DataModule
        {
        }
 
        global $application;
 
        global $SoapServer;
 
        //Creates the form
        $SoapServer=new SoapServer($application);
 
        //Read from resource file
        $SoapServer->loadResource(__FILE__);
?>
 

You can also provide an .xml.php for the properties and objects inside or create the components to be inside the datamodule in runtime.

    Creating and configuring the component

To publish a webservice, you can use the Service component, drop it on your DataModule and change the default property values if needed. NameSpace and SchemaTargetNamespace must be setup with the URLs you plan to deploy your webservice to and ServiceName must be set to a value that identifies your webservice.

Finally, set the Active property to true, if this property is not set, the webservice won't work.

    Registering services

Now is time to register the services your webservice is going to publish to the world, to do that, generate the OnRegisterServices event and call the register() function of your webservice component, here are some samples:

 
function MyWebServiceRegisterServices($sender, $params)
{
  //Register the echo service
  $this->MyWebService->register(
  "serviceEcho",
  array('input'=>'xsd:string'),
  array('return'=>'xsd:string'),
  'http://localhost/'
  );
 
 
  //Register the conversion service
  $this->MyWebService->register(
  "StringArrayToIntArray",
  array('input'=>'tns:ArrayOfstring'),
  array('return'=>'tns:ArrayOfinteger'),
  'http://localhost/'
  );
}
 

This can be read as we want to publish a service called "serviceEcho", which has one input parameter of time string and returns a string. Also, we register another service called "StringArrayToIntArray" which gets an array of strings as input and outputs the same array, but converted to integers.

You should write the code for that functions in PHP code, here is the code for them:

 
/*
* Returns the input
*/
function serviceEcho($input)
{
  return($input);
}
 
/*
* Converts the input array, which are strings, to an array of integers
*/
function StringArrayToIntArray($inputarray)
{
  $result=array();
  reset($inputarray);
  while(list($key, $val)=each($inputarray))
  {
    $result[]=(int)$val;
  }
 
  return($result);
}
 

In the first function, it returns the input as an echo service and in the second one, returns an array of integers from the string array of the input.

    Adding Complex Types

The second function we have added used complex types, that is, types are not single or native ones for the language we are working on, so we need to specify how to handle them, both by the webservice and the client.

To do that, we have the OnAddComplexTypes event, in which we must call the addComplexType function of the webservice, now we are going to register the types, ArrayOfinteger and ArrayOfstring:

 
function MyWebServiceAddComplexTypes($sender, $params)
{
  //Add the complex type array of strings
  $this->MyWebService->addComplexType
  (
    'ArrayOfstring',
    'complexType',
    'array',
    '',
    'SOAP-ENC:Array',
    array(),
    array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]')),
    'xsd:string'
   );
 
   //Add the complex type array of integers
   $this->MyWebService->addComplexType
   (
     'ArrayOfinteger',
     'complexType',
     'array',
     '',
     'SOAP-ENC:Array',
     array(),
     array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'integer[]')),
     'xsd:integer'
   );
}
 

Basically we are setting the name of the type, the type class, usually "complexType", the PHP type, the last parameters are the WSDL type and the base type of the array, an integer or an string.

Note: When using a complex type registering services, you need to refer to qualify it as "tns:", not as "xsd:"

    Consuming the Web Service

The process of consuming the webservice it's made up of two parts:

  • Importing the webservice

In this step, you will import the web service description to create a unit in your client language that will allow you to call the service. We are going to use Delphi for Win32 as client, to import a webservice you can use the WSDL Importer Wizard, it will prompt you for an URL where to find the WSDL description, to get that URL, run you webservice and you will see an interface, with a link called WSDL, click it and you will get an XML file. The URL on the address bar of your browser is the right value to feed the Delphi for Win32 WebService Wizard, i.e.: http://localhost:3569/soapserver.php?wsdl

Once the wizard finishes, you will get a new unit in your project will all the code required to call your webservice.

  • Calling the webservice

The unit you just have added to your project defines a global function, named after your webservice name, in the sample, the function is called GetVCLWebServicePortType and provides an object of type VCLWebServicePortType, that is an object providing the two methods we registered. Once we get to that point, we can call the services as if they were functions defined in our program:

 
procedure TDelphiWebServiceClientSample.Button1Click(Sender: TObject);
begin
    //Set the label caption with the result of calling the "echo" service
    label1.caption:=GetVCLWebServicePortType.serviceEcho(edit1.text);
end;
 

Complex types are also defined on the imported unit, so we can used them:

 
procedure TDelphiWebServiceClientSample.Button2Click(Sender: TObject);
var
  input: ArrayOfstring;
  i: integer;
  result: ArrayOfinteger;
begin
  setlength(input,10);
  for i := 0 to 9 do begin
      input[i]:=inttostr(i);
  end;
 
  //Fills the listbox with the integers returned from the service
  result:=GetVCLWebServicePortType.StringArrayToIntArray(input);
 
    listbox1.clear;
  for i := 0 to high(result) do begin
    listbox1.items.add(inttostr(result[i]));
  end;
 
end;
 

Each time you change something on your webservice, for example, adding new services or changing parameters, you should run again the WSDL Importer to get this unit regenerated.