Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 31-07-2009 17:05:05

freeed
Nouveau membre
Date d'inscription: 31-07-2009
Messages: 3

[Résolu][Zend_Soap][1.8.4] Parametres par defaut d'une methode

Bonjour tout le monde.

Je suis en train de développer un service web SOAP grâce au ZendFramework et j'aurai besoin d'un petit peu d'aide. J'ai retourner tout google pour trouver une solution mais je ne trouve pas, donc je me tourne maintenant vers vous.

Mon problème est que si je ne précise pas les paramètres lors de l'appelle à distance d'une méthode, les paramètres par défaut de cette méthode ne sont pas pris en compte.

exemple:

methode de test coté serveur:

Code:

    
public function test($nom = 'toto')
{
    return $nom;
}

si avec le client soap je fait:

Code:

$soap_client->test();

Zend_soap_server ne renvoit pas 'toto'.

Y a t'il donc un moyen de prendre en compte ces parametres par defaut? (le meme comportement que Zend_Rest)

Merci pour votre aide!

--
Freeed

Dernière modification par freeed (01-08-2009 12:19:58)

Hors ligne

 

#2 31-07-2009 21:11:50

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: [Résolu][Zend_Soap][1.8.4] Parametres par defaut d'une methode

regarde le wsdl tu dois avoir un complextype test qui contient le paramètre nom
est il ne dois pas être marque comme optionnel
ton objet $soap_client lorsque tu invoque la méthode test passe donc bien une valeur (null ou '') au serveur qui va l'utiliser est donc ton $nom = 'toto' ne sert à rien dans ce cas.

A+JYT

Hors ligne

 

#3 31-07-2009 23:59:28

freeed
Nouveau membre
Date d'inscription: 31-07-2009
Messages: 3

Re: [Résolu][Zend_Soap][1.8.4] Parametres par defaut d'une methode

Bonsoir sekaijin et surtout merci de m'aider!

Alors je ne sais pas si j'ai bien compris ce que tu essayes de m'expliquer ou si je ne me suis pas bien exprimé dans mon premier post.

sekaijin a écrit:

ton objet $soap_client lorsque tu invoque la méthode test passe donc bien une valeur (null ou '') au serveur qui va l'utiliser est donc ton $nom = 'toto' ne sert à rien dans ce cas.

Justement il est bien la le problème! J'aimerai que le paramètre par défaut $nom = 'toto' soit bien pris en compte dans la méthode pour me renvoyer le bon résultat après traitement en fonction de ces paramètres.

Mon wsdl (provenance Zend_Soap_AutoDiscover) ressemble a ca:

Code:

<message name="testRequest">
<part name="nom" type="xsd:string"/>
</message>
−
<message name="testResponse">
<part name="return" type="xsd:string"/>
</message>

Il y a un truc que je n'ai manifestement pas encore bien capté.. Je demande qu'a apprendre smile

Merci!

Edit:  Oki il est tard, pardon. Si je comprend bien il faut que je trouve comment faire passer ces parametres comme Optionnels dans le wsdl c'est ca? Possible avec l'autodiscover? merci


--
Freeed

Dernière modification par freeed (01-08-2009 01:32:40)

Hors ligne

 

#4 01-08-2009 12:14:25

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: [Résolu][Zend_Soap][1.8.4] Parametres par defaut d'une methode

oui c'est ça les attribut que tu dois voir apparaitre dans ton wsdl son minOccurs=0 maxOccurs=1

Code:

<part name="nom" type="xsd:string" minOccurs=0 maxOccurs=1/>

je ne sais si c'est possible avec autodiscover
il faut peut être en passer par une construction moins automatique

A+JYT

Hors ligne

 

#5 01-08-2009 12:19:34

freeed
Nouveau membre
Date d'inscription: 31-07-2009
Messages: 3

Re: [Résolu][Zend_Soap][1.8.4] Parametres par defaut d'une methode

Merci merci merci merci merci!!!!!!!!!

Je vais fouiller voir si on peut le faire avec l'autodiscover, mais au moins le problème est identifié et résolu.

Encore merci!

(je rajouterai par la suite si je trouve un moyen de générer ces paramètres optionnels avec l'autodiscover)

--
Freeed

Dernière modification par freeed (01-08-2009 12:20:43)

Hors ligne

 

#6 14-07-2010 14:53:13

Moosh
Membre
Lieu: Neufvilles/Hainaut/Belgique
Date d'inscription: 04-03-2009
Messages: 18
Site web

Re: [Résolu][Zend_Soap][1.8.4] Parametres par defaut d'une methode

Je cherche aussi à le rendre détectable par l'auto discover. Avez vous trouvé une solution depuis ?


--
Moosh // phpFrance // Christophe Gesché // Claroline
Testez mes expériences ZF
http://svn.xp-dev.com/svn/ZF_experiences/ Plus d'info ici http://xp-dev.com/trac/ZF_Experiences/wiki

Hors ligne

 

#7 08-11-2010 14:05:16

jboffel
Nouveau membre
Date d'inscription: 03-11-2010
Messages: 6

Re: [Résolu][Zend_Soap][1.8.4] Parametres par defaut d'une methode

Oui c'est faisable, mais ce n'est pas triviale. Enfin tout dépend de la complexité du WSDL et du schéma associé.
Si on veut utiliser du minOccurs et du maxOccurs sur autre chose qu'un élément faisant référence à un type simple (string, int...) ou sur des 'sequence' il faut faire des modifications conséquentes dans la manière de Zend de généré un WSDL ainsi qu'ajouter des nouvelles balises dans les commentaires. J'ai réalisé un POC mais qui n'a rien de finalisé et qui doit être amélioré avant toutes utilisations dans du code de prod.

L'idée est d'implémenter notre propre class d'ajout de type complexe en réécrivant celle fournie dans le Zend Framework.
En effet Zend_Soap_Wsdl_Strategy_DefaultComplex étend Zend_Soap_Wsdl_Strategy_Abstract et il nous est donc tout à fait possible de définir notre propre class à condition de respecter notre interface. On bind la nouvelle classe à l'auto discovery en utilisant ensuite :

Code:

     $autodiscover->setComplexTypeStrategy('Zend_Soap_Wsdl_Strategy_DefaultComplexTypeImproved');

L'idée est d'ajouter certaines balises lors de la définition de class faisant référence à des types complexes dans le WSDL. (Optionnel) Il faut aussi passer l'autodiscover en binding style 'document' et le body style en literal :

Code:

     $autodiscover->setOperationBodyStyle(array('use' => 'literal'));
     $autodiscover->setBindingStyle(array('style' => 'document'));

Imaginons que je veuille générer un morceau de WSDL ressemblant à ça :

Code:

<xsd:element name="SOMELIST">
     <xsd:complexType>
          <xsd:sequence>
               <xsd:element ref="tns:LISTELEMENT" minOccurs="0" maxOccurs="unbounded"/>
          </xsd:sequence>
     </xsd:complexType>
</xsd:element>

<xsd:complexType name="METHODRESULTTYPE">
     <xsd:sequence>
          <xsd:sequence>
               <xsd:element name="CODE_ERR" type="xsd:int"/>
               <xsd:element name="MSG_ERR" type="xsd:string"/>
          </xsd:sequence>
          <xsd:sequence minOccurs="0">
               <xsd:element name="SID" type="xsd:string"/>
               <xsd:element name="STATUS" type="xsd:boolean"/>
               <xsd:element ref="tns:SOMELIST"/>
          </xsd:sequence>
     </xsd:sequence>
</xsd:complexType>

Le code que je devrais saisir serait :

Code:

/**
 * @sequence
 */
class SOMELIST
{
    /**
     * @var LISTELEMENT 0 unbounded
     */
    public $LISTELEMENT;

     ...
    
}

/**
 * @sequence
 * @type
 */
class METHODRESULTTYPE
{
     /**
     * @sequence start
     * @var integer
     */
    public $CODE_ERR;
     /**
     * @var string
     * @sequence end
     */
    public $MSG_ERR;
     /**
     * @sequence start 0
     * @var string
     */
    public $SID;
     /**
     * @var bool
     */
    public $STATUS;
     /**
     * @var SOMELIST
     * @sequence end
     */
    public $SOMELIST;
    
     ...
}

Voici la class "améliorée" :

Code:

/**
 * Zend_Soap_Wsdl_Strategy_DefaultComplexTypeImproved
 *
 * @category   Zend
 * @package    Zend_Soap
 * @subpackage Wsdl
 * @license    GPLv2
 */
class Zend_Soap_Wsdl_Strategy_DefaultComplexTypeImproved extends Zend_Soap_Wsdl_Strategy_Abstract
{
    /**
     * Add a complex type by recursivly using all the class properties fetched via Reflection.
     *
     * @param  string $type Name of the class to be specified
     * @return string XSD Type for the given PHP type
     */
    public function addComplexType($type)
    {
        if(!class_exists($type)) {
            require_once "Zend/Soap/Wsdl/Exception.php";
            throw new Zend_Soap_Wsdl_Exception(sprintf(
                "Cannot add a complex type %s that is not an object or where ".
                "class could not be found in 'DefaultComplexType' strategy.", $type
            ));
        }

        $dom = $this->getContext()->toDomDocument();
        $class = new ReflectionClass($type);

        $wantType=false;
        if (preg_match_all('/@type/m', $class->getDocComment(), $matches)) {
            $wantType=true;
        }
        
        if($wantType) {
            $complexType = $dom->createElement('xsd:complexType');
            $complexType->setAttribute('name', $type);
            $rootTypeElement = $complexType;
        } else {
            $rootTypeElement = $dom->createElement('xsd:element');
            $rootTypeElement->setAttribute('name', $type);
            $complexType = $dom->createElement('xsd:complexType');
        }

        if (preg_match_all('/@sequence/m', $class->getDocComment(), $matches)) {
            $all = $dom->createElement('xsd:sequence');
        } else {
            $all = $dom->createElement('xsd:all');
        }

        $oldAll=null;
        foreach ($class->getProperties() as $property) {
            if($property->isPublic() && preg_match_all('/@sequence\s+([^\s]+)(.*)/m', $property->getDocComment(), $matches)) {
                if($matches[1][0]=="start") {
                    $oldAll=$all;
                    $all=$dom->createElement('xsd:sequence');
                    if($matches[2][0]!=='') {
                        $cardinalities = explode(" ", substr($matches[2][0], 0, -1));
                        if(is_numeric($cardinalities[1]) && !is_float($cardinalities[1])) {
                            $all->setAttribute('minOccurs', $cardinalities[1]);
                        }
                        if(is_numeric($cardinalities[2]) && !is_float($cardinalities[2])) {
                            $all->setAttribute('maxOccurs', $cardinalities[2]);
                        } else if($cardinalities[2]==="unbounded") {
                            $all->setAttribute('maxOccurs', "unbounded");
                        }
                    }
                }
            }
            if ($property->isPublic() && preg_match_all('/@var\s+([^\s]+)(.*)/m', $property->getDocComment(), $matches)) {

                /**
                 * @todo check if 'xsd:element' must be used here (it may not be compatible with using 'complexType'
                 * node for describing other classes used as attribute types for current class
                 */
                $element = $dom->createElement('xsd:element');
                if(class_exists(trim($matches[1][0]))) {
                    $element->setAttribute('ref', $this->getContext()->getType(trim($matches[1][0])));
                } else {
                    $element->setAttribute('name', $property->getName());
                    $element->setAttribute('type', $this->getContext()->getType(trim($matches[1][0])));
                }
                if($matches[2][0]!=='') {
                    $cardinalities = explode(" ", substr($matches[2][0], 0, -1));
                    if(is_numeric($cardinalities[1]) && !is_float($cardinalities[1])) {
                        $element->setAttribute('minOccurs', $cardinalities[1]);
                    }
                    if(is_numeric($cardinalities[2]) && !is_float($cardinalities[2])) {
                        $element->setAttribute('maxOccurs', $cardinalities[2]);
                    } else if($cardinalities[2]==="unbounded") {
                        $element->setAttribute('maxOccurs', "unbounded");
                    }
                }
                $all->appendChild($element);
            }
            if($property->isPublic() && preg_match_all('/@sequence\s+([^\s]+)/m', $property->getDocComment(), $matches)) {
                if($matches[1][0]=="end") {
                    $oldAll->appendChild($all);
                    $all=$oldAll;
                }
            }
        }

        if($wantType) {
             $complexType->appendChild($all);
        } else {
            $complexType->appendChild($all);
            $rootTypeElement->appendChild($complexType);
        }
        
        $this->getContext()->getSchema()->appendChild($rootTypeElement);
        $this->getContext()->addType($type);
        
        return "tns:$type";
    }
}

On voit donc que par défaut, la class va créer un élément pour chaque type complexe, sauf si on spécifie de force @type, obligatoire pour la class qui définit le type de retour, par rapport à la manière dont Zend génère le WSDL. J'ai ajouté la possibilité de faire des sequence comme "englobeur" au lieu de "all" qui ne permet pas de faire de minOccurs et maxOccurs sur des types complexes. Il suffit pour ça de faire un @sequence sur la class.
Pour faire des sous séquences sur un groupe d'élément d'un type complexe c'est possible aussi en faisant des "@sequence start" et "@sequence end" aux endroits appropriés.
Autre point, lorsque l'on fait appel à un élément dans un type complexe, on y fait appel via une référence maintenant.

Dernière modification par jboffel (08-11-2010 14:34:53)

Hors ligne

 

#8 12-11-2010 10:10:17

jboffel
Nouveau membre
Date d'inscription: 03-11-2010
Messages: 6

Re: [Résolu][Zend_Soap][1.8.4] Parametres par defaut d'une methode

J'ai finalement décidé de pousser le principe, me disant que cela pourrait être intéressant pour faire du middleware un peu plus sérieusement avec PHP.
J'ai donc posté mon code ici : http://framework.zend.com/wiki/display/ … nie+BOFFEL

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr

Graphisme réalisé par l'agence Rodolphe Eveilleau
Développement par Kitpages