Raccourcis : Contenu - rubriques - sous rubriques
EN FR
Jelix 1.6.14

Section: SOAP

« XML-RPC ^ Services web
Changer de langue : EN

Jelix propose la prise en charge de SOAP, qui est un protocole de service web normalisé par le W3C. Jelix utilise l'API SOAP incluse dans php, donc vous devez vous assurer qu'elle est bien activée sur votre serveur (vérifiez par un phpinfo() par exemple).

Cependant, l'avantage d'utiliser Jelix pour faire du soap, est que vous n'avez nullement besoin d'apprendre l'API SOAP, ni de manipuler le contenu XML des messages SOAP : les paramètres soap sont interprétés et disponibles via la méthode param() de vos contrôleurs, et pour renvoyer vos données, vous avez juste à indiquer une valeur PHP à l'objet réponse SOAP de jelix.

Jelix s'occupe aussi de générer le contenu WSDL automatiquement.

Il va vous falloir tout de même créer un point d'entrée spécifique, et de suivre une syntaxe assez précise (mais trés simple) dans les commentaires de chaque méthode de vos contrôleurs SOAP.

Point d'entrée spécifique

Une requête SOAP est spécifique, et pour y répondre, on ne peut pas utiliser l'objet request "classic". Il vous faut créer un point d'entrée spécifique dans le répertoire www/, soap.php par exemple, qui utilise jSOAPRequest plutôt que jClassicRequest, et un objet coordinateur jSoapCoordinator. Le type de requête et du point d'entrée est donc "soap".

Le point d'entrée devra contenir ceci :


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

checkAppOpened();

jApp::loadConfig('soap/config.ini.php');
ini_set("soap.wsdl_cache_enabled", "0");

jClasses::inc('jsoap~jSoapCoordinator');
jClasses::inc('jsoap~jSoapRequest');

$jelix = new jSoapCoordinator();
jApp::setCoord($jelix);
$jelix->request = new jSoapRequest();
$jelix->request->initService();
$jelix->processSoap();

Il ne faut pas oublier de déclarer ce point d'entrée au niveau de la configuration des moteurs d'urls simple ou significant. Si vous utilisez le moteur d'url simple, vous devez mettre dans la section simple_urlengine_entrypoints de la configuration de jelix la déclaration suivante :


soap = "@soap"

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

Si vous utilisez le moteur d'url significant, vous devez ajouter la balise suivante :


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

Dans un cas comme dans l'autre, vous pouvez alors récupérer l'url d'une action pour soap comme ceci :


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

Enfin, créez un fichier de configuration dans var/config/soap/config.ini.php.

Activation du module jsoap

Comme vous le remarquez dans le point d'entrée, des classes du module jsoap sont utilisées. Vous devez donc l'activer.


  php.exe cmd.php installmodule jsoap

(pour plus d'information : Installer un module)

Ce module inclus également tout ce qu'il faut pour faire du WSDL (voir plus bas).

Contrôleur

Comme on a affaire à un type de requête particulier, le nom du fichier du contrôleur doit avoir le suffixe ".soap.php". Par exemple, un contrôleur "default" : default.soap.php. (Vous pouvez bien sûr avoir un autre contrôleur "default" pour d'autres types de requêtes, "default.classic.php" par exemple).

Méthode d'un contrôleur

Ensuite, le contenu du contrôleur est similaire à ce que vous avez l'habitude de faire, à la seule différence que vous utiliserez jResponseSoap, qui a pour alias "soap", pour répondre aux requêtes Soap :


class defaultCtrl extends jController {

    /** 
     * Test with a simple parameter
     * @param string $name
     * @return string
     */
    function hello() {
        $rep = $this->getResponse('soap');
        $rep->data = "Hello ".$this->param('name');
        return $rep;
    }

}

Chaque action du contrôleur, donc chaque méthode du contrôleur, sera une méthode SOAP qu'il faudra indiquer au niveau des clients SOAP (voir section suivante).

Déclarer les types des paramètres et de la valeur de retour

Une méthode "SOAP" a des paramètres et reçoit une valeur en retour. Il faut indiquer leur type à Jelix afin que les messages SOAP et WSDL soient générés correctement.

Pour cela, vous devez ajouter un commentaire "à la phpdoc", pour indiquer les types de paramètres soap et le type de la donnée soap en retour, afin que SOAP puisse fonctionner. C'est la seule "originalité" par rapport aux autres types de contrôleurs.

Pour indiquer les paramètres SOAP auxquels s'attend la méthode, il faut ajouter des tags "@param", avec lesquels on indique le type de paramètre, et le nom du paramètre. Pour indiquer le type de la valeur de retour, il faut utiliser le mot clé "@return" suivit du type.

Les types par défaut que l'on peut indiquer sont les suivants : string, integer, int, boolean, float.

Si on veut utiliser un tableau, on ajoutera [] :


    @param string[] $tableau_de_chaine

S'l s'agit d'un tableau associatif, on utilisera [=>]:


    @param string[=>] $tableau_de_chaine_associatif

On peut faire ça avec tous les types.

Types personnalisés

Vous pouvez aussi utiliser vos propres types, c'est à dire vos propres objets (faire l'équivalent des complextype en XMLSchema). La déclaration de vos classes doit être incluse dans le fichier du contrôleur, soit directement, soit via un include.

Imaginons notre propre type MyTestStruct :


/**
 * Struct used for tests
 */
class MyTestStruct{
    /**
     * @var string
     */
    public $name = 'Dupont';

    /**
     * @var string
     */
    public $firstName = 'Bertrand';

    /**
     * @var string
     */
    public $city = 'Paris';
}

Notez l'usage du mot clé @var pour indiquer le type de chaque propriété. Chaque propriété devrait être commentée de cette manière.

Ensuite, au niveau du contrôleur, on n'oublie pas d'indiquer MyTestStruct pour les paramètres et/ou la valeur de retour qui sont de ce type :


    /** 
     * on reçoit un objet et on retourne un objet
     * @param MyTestStruct $input
     * @return MyTestStruct
     */
    function receiveObject() {
        $rep = $this->getResponse('soap');
        $input = $this->param('input');
        $input->name = 'Name updated';
        $rep->data = $input;
        return $rep;
    }

Bien sûr, MyTestStruct peut avoir des propriétés qui sont elles aussi des objets, du moment qu'on indique leur 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();
    }

}

Mettre en place un service WSDL

Bien entendu, qui dit SOAP, dit un service WSDL qui va permettre aux clients SOAP d'être renseignés sur les services web SOAP disponibles dans votre application. Pour cela, le module jsoap inclus tout ce qu'il faut. Il contient un contrôleur nommé WSDL et possède une méthode wsdl(). Aussi, pour interroger le WSDL, il suffit d'indiquer à votre client SOAP une URL du genre

   http://monsite.com/index.php/jsoap/WSDL/wsdl?service=unModule~unControleur

ou avec le moteur d'url simple:

   http://monsite.com/index.php?module=jsoap&action=WSDL:wsdl&service=unModule~unControleur

Notez qu'il faut donner un paramètre de nom "service", dans lequel on met le nom du module et le nom du contrôleur qui implémente les services SOAP (on n'indique pas de nom de méthode, juste le nom du contrôleur). En retour, un fichier WSDL est fourni, expliquant l'API proposé par ce contrôleur. Vous pouvez bien sûr avoir plusieurs contrôleurs SOAP dans votre application. Cependant, il n'y a pas de moyen pour renvoyer automatiquement un fichier WSDL qui déclarerait les services SOAP de toute votre application.

Remarque : ce type d'url est disgracieux, et vous pouvez parfaitement configurer les urls significatives pour avoir des choses plus simple comme

   http://monsite.com/index/jsoap/unModule/unControleur

Notez que vous pouvez afficher une version HTML de la liste des services SOAP, en appelant la méthode "index" du contrôleur WSDL.

  http://monsite.com/index.php/jsoap/WSDL?service=unModule~unControleur

Appel depuis un client SOAP

Qui dit SOAP, dit une partie cliente qui envoie une requête en SOAP. Cela peut être un script JS qui le fait, mais aussi une autre application PHP. Voici un exemple en PHP utilisant l'extension SOAP :


        ini_set('soap.wsdl_cache_enabled', 0);

        // Client utilisant l'extension soap pour faire appel au serveur soap Jelix

        // Chargement du WSDL
        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());
        }

Appeller un service SOAP avec Jelix

Si votre application Jelix a besoin d'appeler un serveur soap, vous pouvez utiliser jSoapClient. C'est une classe qui renvoi un objet SoapClient préconfiguré avec les paramètres stockés dans un profil de connexion, donc dans var/config/profiles.ini.php, comme pour jDb.

Pour l'utiliser, ajouter une section [jsoapclient] contenant les alias de profils, et autant de section [jsoapclient:xxx] que vous avez de services SOAP à appeler (une par WSDL en fait). "xxx" étant le nom d'un profile que vous donnerez librement. L'alias default indiquant le profile par défaut.

Un profil doit contenir au moins une option wsdl, contenant l'URL d'un fichier WSDL. Vous pouvez ajouter d'autres paramètres correspondant à des options pour la classe SoapClient.


[jsoapclient]

[jsoapclient:default]
wsdl= "http://example.com/books.wsdl"
soap_version = SOAP_1_1

Et dans votre code :


        $client = jSoapClient::get(); // indiquer un nom de profile si ce n'est pas celui par défaut
        $result = $client->hello('Sylvain');
        // ou
        $result =  $client->__soapCall('hello', array('Sylvain'));

Vous pouvez indiquer une option classmap dans le profil, pour mapper des classes sur des types soap. Vous devez utiliser le format json pour indiquer ce mapping.


[jsoapclient:default]
wsdl= "http://example.com/books.wsdl"
soap_version = SOAP_1_1
classmap = '{"soaptype":"myclass", "soaptype2":"myclass2"}'

Les classes que vous indiquez doivent être déjà chargée avec l'appel à jSoapClient::get().

Une alternative fournie depuis Jelix 1.5, est de déclarer ce mapping dans un fichier ini séparé, et d'indiquer ce fichier dans une propriété classmap_file.


[jsoapclient:default]
wsdl= "http://example.com/books.wsdl"
soap_version = SOAP_1_1
classmap_file = soap_classmap.ini.php

Et dans ce fichier ini, il y a autant de sections que de profils jsoapclient, avec les mêmes noms (sans le prefixe "jsoapclient:"). À l'intérieur des sections, il y a une liste de "cle=valeur". Les clés sont les noms des types soap, et les valeurs les noms des classes PHP.


[default]
soaptype=myclass
soaptype2=myclass2

Vous pouvez aussi avoir une section __common__ qui déclare un mapping pour tous les profils.

Le mapping pour un profil donné, contiendra le mapping de __common__, celui de la section correspondante dans le fichier de mapping, et éventuellement celui déclaré dans la propriété classmap du profil.