web-dev-qa-db-fra.com

Comment faire un PHP SOAP appel en utilisant la classe SoapClient

J'ai l'habitude d'écrire du code PHP, mais je n'utilise pas souvent le codage orienté objet. J'ai maintenant besoin d'interagir avec SOAP (en tant que client) et je ne parviens pas à obtenir la syntaxe correcte. J'ai un fichier WSDL qui me permet de configurer correctement une nouvelle connexion à l'aide de la classe SoapClient. Cependant, je suis incapable de faire le bon appel et de récupérer les données. J'ai besoin d'envoyer les données suivantes (simplifiées):

  • ID de contact
  • Nom du contact
  • Description générale
  • Montant

Il existe deux fonctions définies dans le document WSDL, mais je n’en ai besoin que d’une seule ("FirstFunction" ci-dessous). Voici le script que je lance pour obtenir des informations sur les types et les fonctions disponibles:

$client = new SoapClient("http://example.com/webservices?wsdl");
var_dump($client->__getFunctions()); 
var_dump($client->__getTypes()); 

Et voici le résultat qu'il génère:

array(
  [0] => "FirstFunction Function1(FirstFunction $parameters)",
  [1] => "SecondFunction Function2(SecondFunction $parameters)",
);

array(
  [0] => struct Contact {
    id id;
    name name;
  }
  [1] => string "string description"
  [2] => string "int amount"
}

Dites que je veux faire un appel à la FirstFunction avec les données: 

  • Identifiant du contact: 100
  • Nom du contact: John
  • Description générale: baril de pétrole
  • Montant: 500

Quelle serait la bonne syntaxe? J'ai essayé toutes sortes d'options, mais il semble que la structure du savon soit assez flexible et qu'il existe de très nombreuses façons de le faire. Impossible de comprendre le manuel non plus ... 


UPDATE 1: échantillon essayé de MMK:

$client = new SoapClient("http://example.com/webservices?wsdl");

$params = array(
  "id" => 100,
  "name" => "John",
  "description" => "Barrel of Oil",
  "amount" => 500,
);
$response = $client->__soapCall("Function1", array($params));

Mais je reçois cette réponse: Object has no 'Contact' property. Comme vous pouvez le constater dans la sortie de getTypes(), il existe une struct appelée Contact. Je suppose donc que je dois en quelque sorte préciser que mes paramètres incluent les données de contact, mais la question est de savoir comment? 

UPDATE 2: J'ai aussi essayé ces structures, même erreur.

$params = array(
  array(
    "id" => 100,
    "name" => "John",
  ),
  "Barrel of Oil",
  500,
);

Aussi bien que:

$params = array(
  "Contact" => array(
    "id" => 100,
    "name" => "John",
  ),
  "description" => "Barrel of Oil",
  "amount" => 500,
);

Erreur dans les deux cas: l'objet n'a pas de propriété 'Contact'

104
user1305445

C'est ce que vous devez faire.

Juste pour savoir, j'ai essayé de recréer votre situation ...


  • Pour cet exemple, j'ai créé un exemple de service Web .NET avec une WebMethod appelée Function1 et voici les paramètres: 

Function1 (Contact Contact, description de la chaîne, montant en int)

  • Dans lequel Contact est simplement un haricot class qui a des accesseurs et des calculateurs pour id et name comme dans votre cas.

  • Vous pouvez télécharger cet exemple de service Web .NET à l'adresse:

https://www.dropbox.com/s/6pz1w94a52o5xah/11593623.Zip


Le code.

Voici ce que vous devez faire du côté PHP:

(Testé et fonctionnel)

<?php
/* Create a class for your webservice structure, in this case: Contact */
class Contact {
    public function __construct($id, $name) 
    {
        $this->id = $id;
        $this->name = $name;
    }
}

/* Initialize webservice with your WSDL */
$client = new SoapClient("http://localhost:10139/Service1.asmx?wsdl");

/* Fill your Contact Object */
$contact = new Contact(100, "John");

/* Set your parameters for the request */
$params = array(
  "Contact" => $contact,
  "description" => "Barrel of Oil",
  "amount" => 500,
);

/* Invoke webservice method with your parameters, in this case: Function1 */
$response = $client->__soapCall("Function1", array($params));

/* Print webservice response */
var_dump($response);

?>

Comment je sais que ça marche?

  • Si vous faites print_r($params);, vous verrez cette sortie, comme le prévoit votre service Web:

Tableau ([Contact] => Objet de contact ([id] => 100 [nom] => John) [Description] => baril de pétrole [quantité] => 500)

  • Lorsque j'ai débogué l'exemple de service Web .NET, j'ai obtenu ceci:

enter image description here

(Comme vous pouvez le constater, l'objet Contact n'est pas null et les autres paramètres également, cela signifie que votre demande a été effectuée avec succès du côté PHP).

  • La réponse de l'exemple de service Web .NET était celle attendue et affichée à côté de PHP:

object (stdClass) [3] public 'Function1Result' => string 'Detailed informations de votre demande! id: 100, nom: John, description: Barrel d'huile, montant: 500 '(longueur = 98)


J'espère que cela t'aides :-)

155
Oscar Jara

Vous pouvez également utiliser les services SOAP de cette façon:

<?php 
//Create the client object
$soapclient = new SoapClient('http://www.webservicex.net/globalweather.asmx?WSDL');

//Use the functions of the client, the params of the function are in 
//the associative array
$params = array('CountryName' => 'Spain', 'CityName' => 'Alicante');
$response = $soapclient->getWeather($params);

var_dump($response);

// Get the Cities By Country
$param = array('CountryName' => 'Spain');
$response = $soapclient->getCitiesByCountry($param);

var_dump($response);

Ceci est un exemple avec un vrai service, et ça marche.

J'espère que cela t'aides.

64
Salvador P.

Commencez par initialiser les webservices:

$client = new SoapClient("http://example.com/webservices?wsdl");

Puis définissez et transmettez les paramètres:

$params = array (
    "arg0" => $contactid,
    "arg1" => $desc,
    "arg2" => $contactname
);

$response = $client->__soapCall('methodname', array($params));

Notez que le nom de la méthode est disponible dans WSDL en tant que nom de l'opération, par exemple:

<operation name="methodname">
26
MMK

Je ne sais pas pourquoi mon service Web a la même structure que vous mais il n’a pas besoin de Class pour paramètre, c’est simplement un tableau.

Par exemple: - Mon WSDL:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:ns="http://www.kiala.com/schemas/psws/1.0">
    <soapenv:Header/>
    <soapenv:Body>
        <ns:createOrder reference="260778">
            <identification>
                <sender>5390a7006cee11e0ae3e0800200c9a66</sender>
                <hash>831f8c1ad25e1dc89cf2d8f23d2af...fa85155f5c67627</hash>
                <originator>VITS-STAELENS</originator>
            </identification>
            <delivery>
                <from country="ES" node=””/>
                <to country="ES" node="0299"/>
            </delivery>
            <parcel>
                <description>Zoethout thee</description>
                <weight>0.100</weight>
                <orderNumber>10K24</orderNumber>
                <orderDate>2012-12-31</orderDate>
            </parcel>
            <receiver>
                <firstName>Gladys</firstName>
                <surname>Roldan de Moras</surname>
                <address>
                    <line1>Calle General Oraá 26</line1>
                    <line2>(4º izda)</line2>
                    <postalCode>28006</postalCode>
                    <city>Madrid</city>
                    <country>ES</country>
                </address>
                <email>[email protected]</email>
                <language>es</language>
            </receiver>
        </ns:createOrder>
    </soapenv:Body>
</soapenv:Envelope>

Je var_dump:

var_dump($client->getFunctions());
var_dump($client->getTypes());

Voici le résultat:

array
  0 => string 'OrderConfirmation createOrder(OrderRequest $createOrder)' (length=56)

array
  0 => string 'struct OrderRequest {
 Identification identification;
 Delivery delivery;
 Parcel parcel;
 Receiver receiver;
 string reference;
}' (length=130)
  1 => string 'struct Identification {
 string sender;
 string hash;
 string originator;
}' (length=75)
  2 => string 'struct Delivery {
 Node from;
 Node to;
}' (length=41)
  3 => string 'struct Node {
 string country;
 string node;
}' (length=46)
  4 => string 'struct Parcel {
 string description;
 decimal weight;
 string orderNumber;
 date orderDate;
}' (length=93)
  5 => string 'struct Receiver {
 string firstName;
 string surname;
 Address address;
 string email;
 string language;
}' (length=106)
  6 => string 'struct Address {
 string line1;
 string line2;
 string postalCode;
 string city;
 string country;
}' (length=99)
  7 => string 'struct OrderConfirmation {
 string trackingNumber;
 string reference;
}' (length=71)
  8 => string 'struct OrderServiceException {
 string code;
 OrderServiceException faultInfo;
 string message;
}' (length=97)

Donc dans mon code:

    $client  = new SoapClient('http://packandship-ws.kiala.com/psws/order?wsdl');

    $params = array(
        'reference' => $orderId,
        'identification' => array(
            'sender' => param('kiala', 'sender_id'),
            'hash' => hash('sha512', $orderId . param('kiala', 'sender_id') . param('kiala', 'password')),
            'originator' => null,
        ),
        'delivery' => array(
            'from' => array(
                'country' => 'es',
                'node' => '',
            ),
            'to' => array(
                'country' => 'es',
                'node' => '0299'
            ),
        ),
        'parcel' => array(
            'description' => 'Description',
            'weight' => 0.200,
            'orderNumber' => $orderId,
            'orderDate' => date('Y-m-d')
        ),
        'receiver' => array(
            'firstName' => 'Customer First Name',
            'surname' => 'Customer Sur Name',
            'address' => array(
                'line1' => 'Line 1 Adress',
                'line2' => 'Line 2 Adress',
                'postalCode' => 28006,
                'city' => 'Madrid',
                'country' => 'es',
                ),
            'email' => '[email protected]',
            'language' => 'es'
        )
    );
    $result = $client->createOrder($params);
    var_dump($result);

mais c'est avec succès!

21
Tín Phạm

Tout d’abord, utilisez SoapUI pour créer votre projet soap à partir du WSDL. Essayez d'envoyer une demande pour jouer avec les opérations de wsdl. Observez comment la requête XML compose vos champs de données.

Et puis, si vous rencontrez des problèmes pour obtenir SoapClient agissant comme vous le souhaitez, voici comment le déboguer. Définissez l'option trace de sorte que la fonction __getLastRequest () soit disponible.

$soapClient = new SoapClient('http://yourwdsdlurl.com?wsdl', ['trace' => true]);
$params = ['user' => 'Hey', 'account' => '12345'];
$response = $soapClient->__soapCall('<operation>', $params);
$xml = $soapClient->__getLastRequest();

Ensuite, la variable $ xml contient le code XML que SoapClient compose pour votre demande. Comparez ce xml avec celui généré dans SoapUI. 

Pour moi, SoapClient semble ignorer les clés du tableau associatif $ params et l’interpréter comme un tableau indexé, ce qui provoque des données de paramètre incorrectes dans le xml. Autrement dit, si je réorganise les données dans $ params, la réponse $ est complètement différente:

$params = ['account' => '12345', 'user' => 'Hey'];
$response = $soapClient->__soapCall('<operation>', $params);
3
Sang Nguyen

Si vous créez l'objet de SoapParam, cela résoudra votre problème. Créez une classe et mappez-la avec le type d'objet spécifié par WebService, initialisez les valeurs et envoyez la demande. Voir l'exemple ci-dessous. 

struct Contact {

    function Contact ($pid, $pname)
    {
      id = $pid;
      name = $pname;
  }
}

$struct = new Contact(100,"John");

$soapstruct = new SoapVar($struct, SOAP_ENC_OBJECT, "Contact","http://soapinterop.org/xsd");

$ContactParam = new SoapParam($soapstruct, "Contact")

$response = $client->Function1($ContactParam);
2
Umesh Chavan

lis ça;-

http://php.net/manual/en/soapclient.call.php

Ou

Ceci est un bon exemple, pour la fonction SOAP "__call" . Cependant, elle est obsolète.

<?php
    $wsdl = "http://webservices.tekever.eu/ctt/?wsdl";
    $int_zona = 5;
    $int_peso = 1001;
    $cliente = new SoapClient($wsdl);
    print "<p>Envio Internacional: ";
    $vem = $cliente->__call('CustoEMSInternacional',array($int_zona, $int_peso));
    print $vem;
    print "</p>";
?>
1
Abid Hussain

Vous devez déclarer la classe Contrat

class Contract {
  public $id;
  public $name;
}

$contract = new Contract();
$contract->id = 100;
$contract->name = "John";

$params = array(
  "Contact" => $contract,
  "description" => "Barrel of Oil",
  "amount" => 500,
);

ou

$params = array(
  $contract,
  "description" => "Barrel of Oil",
  "amount" => 500,
);

Ensuite

$response = $client->__soapCall("Function1", array("FirstFunction" => $params));

ou

$response = $client->__soapCall("Function1", $params);
0
Ramil Amerzyanov

getLastRequest ():

Cette méthode ne fonctionne que si l'objet SoapClient a été créé avec l'option de trace définie sur TRUE.

TRUE dans ce cas est représenté par 1

$wsdl = storage_path('app/mywsdl.wsdl');
try{

  $options = array(
               // 'soap_version'=>SOAP_1_1,
               'trace'=>1,
               'exceptions'=>1,

                'cache_wsdl'=>WSDL_CACHE_NONE,
             //   'stream_context' => stream_context_create($arrContextOptions)
        );
           // $client = new \SoapClient($wsdl, array('cache_wsdl' => WSDL_CACHE_NONE) );
        $client = new \SoapClient($wsdl, array('cache_wsdl' => WSDL_CACHE_NONE));
        $client     = new \SoapClient($wsdl,$options); 

a travaillé pour moi.

0
CollinsKe

Il existe une option pour générer des objets php5 avec la classe WsdlInterpreter. Voir plus ici: https://github.com/gkwelding/WSDLInterpreter

par exemple:

require_once 'WSDLInterpreter-v1.0.0/WSDLInterpreter.php';
$wsdlLocation = '<your wsdl url>?wsdl';
$wsdlInterpreter = new WSDLInterpreter($wsdlLocation);
$wsdlInterpreter->savePHP('.');
0
István Döbrentei

Vous avez besoin d'un tableau multi-dimensionnel, vous pouvez essayer les solutions suivantes:

$params = array(
   array(
      "id" => 100,
      "name" => "John",
   ),
   "Barrel of Oil",
   500
);

dans PHP, un tableau est une structure et est très flexible. Normalement, avec des appels soap, j'utilise un wrapper XML, donc je ne sais pas si cela fonctionnera.

MODIFIER:

Ce que vous voudrez peut-être essayer, c’est de créer une requête JSON à envoyer ou de l’utiliser pour créer un achat xml en suivant ce qui est présenté sur cette page: http://onwebdev.blogspot.com/2011/08/php-converting- rss-to-json.html

0
James Williams

J'ai eu le même problème, mais je viens de résumer les arguments comme celui-ci et cela fonctionne maintenant.

    $args = array();
    $args['Header'] = array(
        'CustomerCode' => 'dsadsad',
        'Language' => 'fdsfasdf'
    );
    $args['RequestObject'] = $whatever;

    // this was the catch, double array with "Request"
    $response = $this->client->__soapCall($name, array(array( 'Request' => $args )));

En utilisant cette fonction:

 print_r($this->client->__getLastRequest());

Vous pouvez voir le XML de la demande, qu'il change ou non, en fonction de vos arguments.

Utilisez [trace = 1, exceptions = 0] dans les options SoapClient.

0
Martin Zvarík