Quick links: Content - sections - sub sections
EN FR
Jelix 1.3.9

Section: SOAP

« XML-RPC ^ Web services
Switch to language: FR

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 create a specific entry poin, and to follow a specific syntax in comments in your soap controllers.

Create a specific entry point

Since a SOAP http request is not as usual, you cannot use the "classic" request object. You should create a specific entry point in the www/ directory, soap.php for example. This entry point should use jSOAPRequest instead of jClassicRequest, and a specific coordinator: jSoapCoordinator. The type of the request and of the entry point is then "soap".

The entry point should then content:


require_once ('../application.init.php');

require_once (JELIX_LIB_CORE_PATH.'jSoapCoordinator.class.php');

require_once (JELIX_LIB_CORE_PATH.'request/jSoapRequest.class.php');

ini_set("soap.wsdl_cache_enabled", "0"); // disabling PHP's WSDL cache

$config_file = 'soap/config.ini.php';

$jelix = new JSoapCoordinator($config_file);
$jelix->request = new JSoapRequest();
$jelix->request->initService();
$jelix->processSoap();

Don't forget to add this entry point in urls engine configuration section. If you have selected the "simple" url engine, in section simple_urlengine_entrypoints configuration file, just add:


soap = "@soap"

soap étant le nom du point d'entrée, et @soap indiquant le type de point d'entrée.

If you have selected the significant url engine, add:


<entrypoint type="soap" name="soap" default="true" />

Independently of url engines, you retrieve an url for a soap action like this:


  $url = jUrl::get("module~action@soap");

Finally, create a configuration file in var/config/soap/config.ini.php.

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
     * @param 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 xswl 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 "@param" tags and a "@return" tag. Ex:


    @param 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 []:


    @param string[] $array_of_string

If it is an associative array, use [=>]:


    @param 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
     * @param 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 propertie
 */
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.

Jelix provides a module, jWSDL. 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/jWSDL/WSDL/wsdl?service=aModule~aController

or with the "simple" url engine:

   http://mysite.com/index.php?module=jWSDL&action=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.

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/jWSDL/WSDL?service=aModule~aController

Don't forget to install the module jWSDL (see the chapter about installing a module)


  php.exe cmd.php installmodule jWSDL

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/jWSDL/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().