Un lecteur (Emmanuel) m'a écrit pour me demander si je pouvais l'aider à faire fonctionner son service web PHP SOAP réalisé avec les composants du Zend Framework. En effectuant des recherches pour sa solution, il a trouvé mon article qui explique comment créer un WSDL facilement. Il a tenté de transposer mon exemple sur son projet mais mis à part faire apparaître le WSDL (serveur.php?wsdl), il n'arrivait pas à se connecter au service avec un client.
J'ai accepté de lui donner un coup de pouce mais au risque de me répéter, je lui ai d'abord demandé s'il avait lu la suite de mon article qui donnait quelques précisions sur l'article original : commentaire sur la création de WSDL en PHP.
En effet, il l'avait consulté et m'a expliqué, à l'aide d'un exemple concret, la nature du problème. Essentiellement, sa fonction appelée depuis le service web retourne un objet nommé Response et qu'il n'arrive pas à le récupérer côté client. La classe peut être définie sommairement comme suit :
class Response{En retournant l'objet, impossible de le récupérer côté client. Pourtant, tout est 100% fonctionnel s'il retourne un simple int, string, float, etc. Son intuition : définir dans le WSDL un type complexe qui correspondrait à l'objet retourné. J'avoue ne pas y avoir pensé et ne pas avoir expérimenté. Mais j'avais un doute que ce soit possible car l'objet possède des fonctions qui ne seraient pas prises en charge au moment du retour. Peut-être que je me trompe et que c'est possible ? À ma connaissance, le but d'un service web est d'offrir une interface standard pour être appelée à partir de n'importe quel langage de programmation. Ce qui sous-entend qu'on recevra des valeurs et non pas des objets.
/** @var bool */
private $returnValue;
/** @var string */
private $errCode;
/** @var string */
private $errMessage;
/* plusieurs fonctions */
}
Ma recommandation a été de lui suggérer de contourner le problème en utilisant une valeur de retour de type "array" associatif. Ainsi, sa classe Response offrirait une fonction pour récupérer les valeurs :
class Response{Dans la classe qui sera inspectée par AutoDiscover, j'ajoute une fonction :
/** @var bool */
private $returnValue;
/** @var string */
private $errCode;
/** @var string */
private $errMessage;
public function __construct(){
// à titre d'exemple...
$this->returnValue = true;
$this->errCode = 404;
$this->errMessage = 'Page not found';
}
public function getValues(){
$arrToReturn =
array(
'returnValue' => $this->returnValue,
'errCode' => $this->errCode,
'errMessage' => $this->errMessage
);
return $arrToReturn;
}
}
/**Alors que du côté client, je peux récupérer les valeurs selon les clés :
* Return array structure
* @return array
*/
public function getResponseStructure(){
$obj = new Response();
return $obj->getValues();
}
$client = new Zend_Soap_Client('http://wsdl.localhost/service.php?wsdl');En sortie de print_r() :
$response = $client->getResponseStructure();
print_r($response);
/*
echo $response['returnValue'] . "\n";
echo $response['errCode'] . "\n";
echo $response['errMessage'] . "\n";
*/
(Ceci devrait suffire pour obtenir les valeurs correctement. Si quelqu'un sait s'il est possible de retourner réellement un objet, je serais preneur pour la solution.
[returnValue] => 1
[errCode] => 404
[errMessage] => Page not found
)
Bonjour,
C'est possible de retourner, mais il faut procéder de la manière suivante :
- création de l'objet correspondant dans le WSDL (Eclipse fourni une très belle interface pour faire cela).
- utiliser l'API SOAP fourni en standard avec php 5 (la version est stable au moins en 5.2.13) et c'est parti.
Je n'ai pas d'exemple sous le coude, ça peut s'arranger si il y a du monde d'intéressé :-)
Oui, un court exemple serait pertinent à publier.
Je serais d'autant plus intéressé à savoir si le composant Zend Framework est compatible avec le retour d'objet ou s'il est limité.
Il est possible d'utiliser des types complexes comme paramètre ou retour de méthode avec Zend_Soap_AutoDiscover.
En changeant la stratégie de type complexe il est même possible d'utiliser des Array de type complexe.
Le tout est de bien documenter les méthodes. Exemple:
```
class Response {
/** @var bool */
private $returnValue;
/** @var string */
private $errCode;
/** @var string */
private $errMessage;
/* plusieurs fonctions */
}
/**
* Return array structure
* @return Response
*/
public function getResponseStructure(){
return new Response();
}
/* Et si on utilise la stratégie :
$server->setComplexStrategy('Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex');
*/
// on peut faire des trucs genre
/**
* Return array structure
* @return Response[]
*/
public function getArrayResponseStructure(){
return array(new Response(), new Response());
}
```
Pour véritablement récupérer une instance de la classe Response coté client (sauf erreur le comportement par défaut et d'utiliser stdClass) il faut configurer le client en définissant l'option 'classmap':
```
$client = new SoapClient($wsdl, array(
'classmap' => array(
'Response' => 'Response'
)
));
```
Il faut bien entendu que la classe Response existe aussi coté client.
Cordialement,
Gilles
PS: Les codes ci-dessus n'ont pas été testé et son juste à titre indicatif.