− Table of content
Jelix supports the SOAP protocol, which is a standard protocol for web services specified by W3C. Jelix use the PHP SOAP API, so you have to configure your web server to include this extension (verify with phpinfo() for example).
The advantage to use Jelix to do SOAP is that you don't have to learn details of
the protocol, nor to manipulate XML content of soap message, and it is well
integrated into jelix: soap parameters are interpreted and available in
controllers through the classical param()
method, and to return data for
the response, you do like for all other response type.
Jelix also generates automatically WSDL content.
However, you have to install and configure the jsoap module, and have to follow a specific syntax in comments in your soap controllers.
Install and Activate the jsoap module ¶
As you probably saw in the entry point, some classes are used from a "jsoap" module. You should install it and then activate it.
So add in your composer.json the dependency jelix/soap-server-module
:
composer require "jelix/soap-server-module"
Then configure the module and launch the installer:
php dev.php module:configure jsoap
php install/installer.php
(see the chapter about installing a module)
This module includes also all what you need to generate WSDL content. (see below)
Since a SOAP http request is not as usual, you cannot use the "classic"
request object. So the module creates a specific entry
point in the www/
directory, soap.php
. This entry point
is using jSOAPRequest
instead of jClassicRequest
, and a specific
coordinator: jSoapCoordinator
. The type of the request and of the entry
point is then "soap".
Controller ¶
Since it is a specific type of request, a controller filename must be suffixed
by ".soap.php". For example, for a "default" controller: default.soap.php
.
(it can co-exists with a “default” classic controller such as
“default.classic.php”).
Method of a soap controller ¶
The content of a controller is similar of a classical controller, with few
differences. You will retrieve a jResponseSoap
object for the response,
which have the alias: "soap".
class defaultCtrl extends jController {
/**
* Test with a simple parameter
* @exernalparam string $name
* @return string
*/
function hello() {
$resp = $this->getResponse('soap');
$resp->data = "Hello ".$this->param('name');
return $resp;
}
}
Each action of a controller will be in fact a "soap method".
Declaring the type of parameters and the return value ¶
A "soap method" have parameters and should receive a value. You should indicate their type so Jelix could generate correctly SOAP and WSDL messages.
To do it, just add "doc comments" (like for phpdoc), and indicates the type of parameters and of the return value, by using some "@exernalparam" tags and a "@return" tag. Ex:
@exernalparam string $myparameter
Here it indicates that the soap parameter "$myparameter" is a string. Other possible types are "integer", "int", "boolean", "float".
If you want to indicate an array, add the type name followed by []
:
@exernalparam string[] $array_of_string
If it is an associative array, use [=>]
:
@exernalparam string[=>] $array_of_string
Complex types ¶
If you want to use complex type, like your own objects for parameters or return
values. The classes of this objects should be include in the file of the
controller (with an include
).
Here an exemple of an object use for a parameter MyTestStruct
:
/**
* Struct used for tests
*/
class MyTestStruct{
/**
* @var string
*/
public $name = 'Dupont';
/**
* @var string
*/
public $firstName = 'Bertrand';
/**
* @var string
*/
public $city = 'Paris';
}
Note the use of the required "@var" keyword to indicate the type of each properties.
Then in your controller, don't forget to indicate MyTestStruct
for
parameters or returned values:
/**
* for this method, we receive a MyTestStruct and return a MyTestStruct object
* @exernalparam MyTestStruct $input
* @return MyTestStruct
*/
function receiveObject() {
$resp = $this->getResponse('soap');
$input = $this->param('input');
$input->name = 'Name updated';
$resp->data = $input;
return $resp;
}
Of course, MyTestStruct
can have some properties with complex type:
/**
* An other struct used for test, this one have an other object as member property
*/
class MyTestStructBis {
/**
* @var MyTestStruct
*/
public $test;
/**
* @var string
*/
public $msg = 'hello';
function __construct(){
$this->test = new MyTestStruct();
}
}
Using the WSDL service ¶
When you use the SOAP protocol, you should provide some WSDL files, which allows SOAP clients to know what are available SOAP methods, and how to validate parameters and return values.
The jsoap module provides features to generate WSDL. It contains a controller
named "WSDL" with a wsdl()
method. So, just indicate the url of this
action to your soap client:
http://mysite.com/index.php/jsoap/WSDL/wsdl?service=aModule~aController
Note that you should give a "service" parameter indicating the controller which contains the web services. You can have more than one soap controller, but there is no way to return automatically a WSDL file for all soap web services implemented in your application.
Note also that the URL is note really beautiful. You can configure the url mapping to have :
http://mysite.com/index/jsoap/aModule/aController
You can display a HTML version of the list of SOAP services, by calling the
index()
method of the WSDL controller:
http://mysite.com/index.php/jsoap/WSDL?service=aModule~aController
Calling a SOAP service with a client ¶
The application which calls your SOAP web services can be a PHP client, a javascript client etc.. Here is an example of a call with a PHP script.
ini_set('soap.wsdl_cache_enabled', 0);
// load the WSDL content
try {
$wsdlURI = "http://monsite.com/index.php/jsoap/WSDL/wsdl?service=myapp~default";
$client = new SoapClient($wsdlURI, array('trace' => 1, 'soap_version' => SOAP_1_1));
} catch (SoapFault $fault) {
throw new Exception($fault->getMessage());
}
try {
$result = $client->__soapCall('hello', array('Sylvain'));
//...
$result = $client->__soapCall('returnObjects', array());
//...
$result = $client->__soapCall('returnObjectBis', array());
// ...
} catch (SoapFault $fault) {
print_r($fault);
throw new Exception($fault->getMessage());
}
Calling a SOAP service with Jelix ¶
If your jelix application needs to call soap servers, you can use
jSoapClient
. It is a class to retrieve a native SoapClient
object,
automatically configured with some parameters stored in a
var/config/profiles.ini.php
, like for jDb.
To use it, add sections in var/config/profiles.ini.php
. Sections are
profiles for connections. options in [jsoapclient]
are aliases for profiles.
Profiles are stored in section named [jsoapclient:myname]
where myname
is a name you choose freely. default
name indicate the default profile. A
profile should contain at least a wsdl
option, containing the URL to a WSDL
file. You can add other options, corresponding to parameters for the native
class SoapClient of PHP.
[jsoapclient]
[jsoapclient:default]
wsdl= "http://example.com/books.wsdl"
soap_version = SOAP_1_1
And then, in your code:
$client = jSoapClient::get(); // give a profile name if different from 'default'
$result = $client->hello('Sylvain');
// or
$result = $client->__soapCall('hello', array('Sylvain'));
You can indicate the option classmap in the profile, to map some classes on soap types. You have to use the json format to indicate the mapping.
[jsoapclient:default]
wsdl= "http://example.com/books.wsdl"
soap_version = SOAP_1_1
classmap = '{"soaptype":"myclass", "soaptype2":"myclass2"}'
The classes you indicate should be loaded before calling jSoapClient::get()
.
You can also declare this mapping into a separate ini file. You should
indicate this file into a classmap_file
property in the profile. This file
should be into yourapp/app/system/
.
[jsoapclient:default]
wsdl= "http://example.com/books.wsdl"
soap_version = SOAP_1_1
classmap_file = soap_classmap.ini.php
In the ini file, you should have section corresponding with declared profiles, with the same name (without the "jsoapclient:" prefix). In these sections, you have list of "key=value". Keys are soap types, values are class names.
[default]
soaptype=myclass
soaptype2=myclass2
You can also declare a __common__
section, containing mapping applicable for all
jsoapclient profiles.
So, the classmap of a profile, contains the classmap of __common__
, the classmap
of the section corresponding to the profile, and the classmap declared into the
profile in the "classmap" property.
Other configuration options:
trace=on
: to activate debugging. In a log file of type "soap", you'll have all SOAP requests and responses. You should configure the logger correctly. Example:
[logger]
soap=file
[fileLogger]
soap=soap.log
Since Jelix 1.6.16, you can also use the soapfile
logger instead of file
.
This logger stores xml content of requests and responses in separate files
to ease debugging.
exceptions
: it's a boolean indicating if SOAP error should generate SoapFault exceptions.connection_timeout
: time in secondes to wait after a response, before generating an errorssl_self_signed
(since 1.6.15) : if "on", there will not error when the SSL certificat of the SOAP server cannot be verified. You should not activate it on distant SOAP servers.