Como fazer uma chamada de PHP SOAP usando a classe SoapClient
estou habituado a escrever código PHP, mas não costumo usar códigos orientados a objectos. Eu agora preciso interagir com o SOAP (como um cliente) e não sou capaz de obter a sintaxe certa. Eu tenho um arquivo WSDL que me permite configurar corretamente uma nova conexão usando a classe SoapClient. No entanto, sou incapaz de fazer a chamada certa e obter dados devolvidos. Preciso enviar os seguintes dados (simplificados):
- ID de contacto
- Nome De Contacto
- geral Descrição
- montante
Existem duas funções definidas no documento WSDL, mas eu só preciso de uma ("primeira função" abaixo). Aqui está o script que corro para obter informações sobre as funções e tipos disponíveis:
$client = new SoapClient("http://example.com/webservices?wsdl");
var_dump($client->__getFunctions());
var_dump($client->__getTypes());
e aqui está a saída que gera:
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"
}
Digamos que quero fazer uma chamada para a primeira função com os dados:
- ID de contacto: 100
- Nome De Contacto: John
- Descrição Geral: barril de Óleo
- montante: 500
actualização 1: amostra testada 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));
mas eu tenho esta resposta: Object has no 'Contact' property
. Como você pode ver na saída de getTypes()
, há um struct
chamado Contact
, Então eu acho que de alguma forma preciso deixar claro meus parâmetros incluem os dados de contato, mas a questão é: como?
actualização 2: também tentei estas estruturas, mesmo erro.
$params = array(
array(
"id" => 100,
"name" => "John",
),
"Barrel of Oil",
500,
);
assim como:
$params = array(
"Contact" => array(
"id" => 100,
"name" => "John",
),
"description" => "Barrel of Oil",
"amount" => 500,
);
erro em ambos os casos: o objecto não tem propriedade' contacto '
11 answers
- para este exemplo, fiz um servidor de amostras. net com um
WebMethod
ChamadoFunction1
e estes são os parâmetros:
Function1 (contacto, descrição do texto, int montante)
Em que
Contact
é apenas um feijãoclass
que tem getters e setters paraid
ename
como no teu caso.Podes. obtém este serviço web de amostras. NET em:
Https://www.dropbox.com/s/6pz1w94a52o5xah/11593623.zip
O código.
Isto é o que você precisa fazer no lado do PHP:
(ensaio e funcionamento)
<?php
/* Create a class for your webservice structure, in this case: Contact */
class Contact {
function Contact($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);
?>
Como sei que isto está a funcionar?
- Se o fizer {[7] } irá ver esta saída, como o seu serviço web espera:
Matriz ([contacto] = > objecto de contacto ([id] = > 100 [nome] => John ] [descrição] => barril de Petróleo [Quantidade] => 500 )
- Quando depurei o serviço web sample. net consegui isto:
(Como você pode ver, Contact
objeto não é nulo e também os outros parâmetros, isso significa que seu pedido foi feito com sucesso do lado PHP).
- a resposta do serviço web da amostra. net era a esperada e mostrada do lado do PHP:
Objecto (stdClass)[3] público "Function1Result" = > string " Detailed informação do seu pedido! id: 100, nome: John, descrição: barril de óleo, Quantidade: 500' (comprimento=98)
Espero que isto ajude.
Também pode usar os Serviços de sabão desta forma:
<?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);
Este é um exemplo com um serviço real, e funciona.
Espero que isto ajude.
Inicializar os webservices pela primeira vez:
$client = new SoapClient("http://example.com/webservices?wsdl");
Em seguida, definir e passar os parâmetros:
$params = array (
"arg0" => $contactid,
"arg1" => $desc,
"arg2" => $contactname
);
$response = $client->__soapCall('methodname', array($params));
Note que o nome do método está disponível no WSDL como nome da operação, por exemplo:
<operation name="methodname">
Eu não sei porque meu serviço web tem a mesma estrutura com você, mas ele não precisa de classe para parâmetro, apenas é array.
Por exemplo: - O meu 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>
I var_dump:
var_dump($client->getFunctions());
var_dump($client->getTypes());
Aqui está o resultado:
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)
Então, no meu código:
$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);
Mas com sucesso!
Primeiro, use SoapUI para criar o seu projecto soap a partir do wsdl. Tente enviar um pedido para jogar com as operações do wsdl. Observe como o pedido xml compõe seus campos de dados.
E então, se você está tendo problemas para obter os atos de SoapClient como você quer, aqui está como eu o depuro. Defina a opção trace para que a função __getLastRequest() esteja disponível para utilização.
$soapClient = new SoapClient('http://yourwdsdlurl.com?wsdl', ['trace' => true]);
$params = ['user' => 'Hey', 'account' => '12345'];
$response = $soapClient->__soapCall('<operation>', $params);
$xml = $soapClient->__getLastRequest();
Então a variável $xml contém o xml que o SoapClient compõe a seu pedido. Compare este xml com o gerado no SoapUI.
Para mim, o SoapClient parece ignorar as chaves do array associativo $params e interpretá-lo como um array indexado, causando dados de parâmetros errados no xml. Isto é, se eu Reordenar os dados em $params, a resposta $ é completamente diferente:
$params = ['account' => '12345', 'user' => 'Hey'];
$response = $soapClient->__soapCall('<operation>', $params);
Se criar o objecto do SoapParam, isto irá resolver o seu problema. Crie uma classe e mapeie-a com o tipo de objeto dado pelo WebService, inicialize os valores e envie o pedido. Ver a amostra abaixo.
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);
Leia isto; -
Http://php.net/manual/en/soapclient.call.php
Ou
Este é um bom exemplo, para a função SOAP "__call". No entanto, é depreciado.
<?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>";
?>
Tens de declarar o contrato da classe
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,
);
Depois
$response = $client->__soapCall("Function1", array("FirstFunction" => $params));
Ou
$response = $client->__soapCall("Function1", $params);
Se precisar de um array multidimensional, pode tentar o seguinte:
$params = array(
array(
"id" => 100,
"name" => "John",
),
"Barrel of Oil",
500
);
Em PHP um array é uma estrutura e é muito flexível. Normalmente com as chamadas soap eu uso uma embalagem XML tão inseguro se ele vai funcionar.
Editar:
O que você pode querer tentar é criar uma consulta json para enviar ou usar isso para criar um tipo de compra xml de seguir o que está nesta página: http://onwebdev.blogspot.com/2011/08/php-converting-rss-to-json.html
Existe uma opção para gerar objectos php5 com a classe WsdlInterpreter. Veja mais aqui: https://github.com/gkwelding/WSDLInterpreter
Por exemplo:
require_once 'WSDLInterpreter-v1.0.0/WSDLInterpreter.php';
$wsdlLocation = '<your wsdl url>?wsdl';
$wsdlInterpreter = new WSDLInterpreter($wsdlLocation);
$wsdlInterpreter->savePHP('.');
$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 )));
Usando esta função:
print_r($this->client->__getLastRequest());
Pode ver o XML do pedido, quer esteja a mudar ou não, dependendo dos seus argumentos.
Usar [ trace = 1, exceptions = 0 ] nas opções de SoapClient.