− Table des matières
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.