Reputation:
I'm used to writing PHP code, but do not often use Object-Oriented coding. I now need to interact with SOAP (as a client) and am not able to get the syntax right. I've got a WSDL file which allows me to properly set up a new connection using the SoapClient class. However, I'm unable to actually make the right call and get data returned. I need to send the following (simplified) data:
There are two functions defined in the WSDL document, but I only need one ("FirstFunction" below). Here is the script I run to get information on the available functions and types:
$client = new SoapClient("http://example.com/webservices?wsdl");
var_dump($client->__getFunctions());
var_dump($client->__getTypes());
And here is the output it generates:
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"
}
Say I want to make a call to the FirstFunction with the data:
What would be the right syntax? I've been trying all sorts of options but it appears the soap structure is quite flexible so there are very many ways of doing this. Couldn't figure it out from the manual either...
UPDATE 1: tried sample from 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));
But I get this response: Object has no 'Contact' property
. As you can see in the output of getTypes()
, there is a struct
called Contact
, so I guess I somehow need to make clear my parameters include the Contact data, but the question is: how?
UPDATE 2: I've also tried these structures, same error.
$params = array(
array(
"id" => 100,
"name" => "John",
),
"Barrel of Oil",
500,
);
As well as:
$params = array(
"Contact" => array(
"id" => 100,
"name" => "John",
),
"description" => "Barrel of Oil",
"amount" => 500,
);
Error in both cases: Object has no 'Contact' property`
Upvotes: 157
Views: 512498
Reputation: 1058
Call the method name directly on the SoapClient
, in order to pass arguments as an array.
$client = new SoapClient($wsdl);
-$response = $this->__soapCall('methodName', $parameters);
+$response = $client->methodName($parameters);
__soapCall()
expects parameters to be passed in an outer array – as also explained in https://www.php.net/manual/en/soapclient.call.php#114787 and https://www.php.net/manual/en/soapclient.soapcall.php#110390
I was facing the additional challenge that the WSDL defined method names, which are not valid PHP function names, such as: _-vendor_-kdbwsOa2UpdateGp001
Trying to call this directly as method name or variable method name…
$client->_-vendor_-kdbwsOa2UpdateGp001();
$method = '_-vendor_-kdbwsOa2UpdateGp001';
$client->$method();
…yielded PHP errors, such as:
Undefined constant "vendor_"
In case you also run into this, use the traditional call_user_func()
:
$client = new SoapClient($wsdl);
$method = '_-vendor_-kdbwsOa2UpdateGp001';
$parameters = [
'one' => '123',
'two' => (string) $id,
];
$response = call_user_func([$client, $method], $parameters);
Also make sure that your parameters are having the expected data types of the function parameters struct. To see the definitions of all structs for your WSDL:
$client = new SoapClient($wsdl);
var_dump($client->getTypes());
Upvotes: 0
Reputation: 516
Below code might be helpful
$wsdl ='My_WSDL_Service.wsdl";
$options = array(
'login' => 'user-name',
'password' => 'Password',
);
try {
$client = new SoapClient($wsdl, $options);
$params = array(
'para1' => $para1,
'para2' => $para2
);
$res = $client->My_WSDL_Service($params);
Upvotes: 0
Reputation: 87
getLastRequest():
This method works only if the SoapClient object was created with the trace option set to TRUE.
TRUE in this case is represented by 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);
Upvotes: 1
Reputation: 1489
You can use SOAP services this way too:
<?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);
This is an example with a real service, and it works when the url is up.
Just in case the http://www.webservicex.net is down.
Here is another example using the example web service from W3C XML Web Services example, you can find more information on the link.
<?php
//Create the client object
$soapclient = new SoapClient('https://www.w3schools.com/xml/tempconvert.asmx?WSDL');
//Use the functions of the client, the params of the function are in
//the associative array
$params = array('Celsius' => '25');
$response = $soapclient->CelsiusToFahrenheit($params);
var_dump($response);
// Get the Celsius degrees from the Farenheit
$param = array('Fahrenheit' => '25');
$response = $soapclient->FahrenheitToCelsius($param);
var_dump($response);
This is working and returning the converted temperature values.
Upvotes: 84
Reputation: 14187
I tried to recreate the situation...
WebMethod
called Function1
expecting the following params:Function1(Contact Contact, string description, int amount)
Where Contact
is just a model that has getters and setters for id
and name
like in your case.
You can download the .NET sample WS at:
https://www.dropbox.com/s/6pz1w94a52o5xah/11593623.zip
This is what you need to do at PHP side:
(Tested and working)
<?php
// Create Contact class
class Contact {
public function __construct($id, $name)
{
$this->id = $id;
$this->name = $name;
}
}
// Initialize WS with the WSDL
$client = new SoapClient("http://localhost:10139/Service1.asmx?wsdl");
// Create Contact obj
$contact = new Contact(100, "John");
// Set request params
$params = array(
"Contact" => $contact,
"description" => "Barrel of Oil",
"amount" => 500,
);
// Invoke WS method (Function1) with the request params
$response = $client->__soapCall("Function1", array($params));
// Print WS response
var_dump($response);
?>
print_r($params)
you will see the following output, as your WS would expect:Array ( [Contact] => Contact Object ( [id] => 100 [name] => John ) [description] => Barrel of Oil [amount] => 500 )
(As you can see, Contact
object is not null
nor the other params. That means your request was successfully done from PHP side)
object(stdClass)[3] public 'Function1Result' => string 'Detailed information of your request! id: 100, name: John, description: Barrel of Oil, amount: 500' (length=98)
Upvotes: 189
Reputation: 2469
I had the same issue, but I just wrapped the arguments like this and it works now.
$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 )));
Using this function:
print_r($this->client->__getLastRequest());
You can see the Request XML whether it's changing or not depending on your arguments.
Use [ trace = 1, exceptions = 0 ] in SoapClient options.
Upvotes: 2
Reputation: 1008
There is an option to generate php5 objects with WsdlInterpreter class. See more here: https://github.com/gkwelding/WSDLInterpreter
for example:
require_once 'WSDLInterpreter-v1.0.0/WSDLInterpreter.php';
$wsdlLocation = '<your wsdl url>?wsdl';
$wsdlInterpreter = new WSDLInterpreter($wsdlLocation);
$wsdlInterpreter->savePHP('.');
Upvotes: 0
Reputation: 614
If you create the object of SoapParam, This will resolve your problem. Create a class and map it with object type given by WebService, Initialize the values and send in the request. See the sample below.
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);
Upvotes: 5
Reputation: 151
First, use SoapUI to create your soap project from the wsdl. Try to send a request to play with the wsdl's operations. Observe how the xml request composes your data fields.
And then, if you are having problem getting SoapClient acts as you want, here is how I debug it. Set the option trace so that the function __getLastRequest() is available for use.
$soapClient = new SoapClient('http://yourwdsdlurl.com?wsdl', ['trace' => true]);
$params = ['user' => 'Hey', 'account' => '12345'];
$response = $soapClient->__soapCall('<operation>', $params);
$xml = $soapClient->__getLastRequest();
Then the $xml variable contains the xml that SoapClient compose for your request. Compare this xml with the one generated in the SoapUI.
For me, SoapClient seems to ignore the keys of the associative array $params and interpret it as indexed array, causing wrong parameter data in the xml. That is, if I reorder the data in $params, the $response is completely different:
$params = ['account' => '12345', 'user' => 'Hey'];
$response = $soapClient->__soapCall('<operation>', $params);
Upvotes: 4
Reputation: 1126
First initialize webservices:
$client = new SoapClient("http://example.com/webservices?wsdl");
Then set and pass the parameters:
$params = array (
"arg0" => $contactid,
"arg1" => $desc,
"arg2" => $contactname
);
$response = $client->__soapCall('methodname', array($params));
Note that the method name is available in WSDL as operation name, e.g.:
<operation name="methodname">
Upvotes: 31
Reputation: 642
I don't know why my web service has the same structure with you but it doesn't need Class for parameter, just is array.
For example: - My 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());
Here is result:
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)
So in my 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);
but it successfully!
Upvotes: 24
Reputation: 4216
You need a multi-dimensional array, you can try the following:
$params = array(
array(
"id" => 100,
"name" => "John",
),
"Barrel of Oil",
500
);
in PHP an array is a structure and is very flexible. Normally with soap calls I use an XML wrapper so unsure if it will work.
What you may want to try is creating a json query to send or using that to create a xml buy sort of following what is on this page: http://onwebdev.blogspot.com/2011/08/php-converting-rss-to-json.html
Upvotes: 0
Reputation: 1291
You need declare class Contract
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,
);
or
$params = array(
$contract,
"description" => "Barrel of Oil",
"amount" => 500,
);
Then
$response = $client->__soapCall("Function1", array("FirstFunction" => $params));
or
$response = $client->__soapCall("Function1", $params);
Upvotes: 0
Reputation: 7762
read this;-
http://php.net/manual/en/soapclient.call.php
Or
This is a good example, for the SOAP function "__call". However it is deprecated.
<?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>";
?>
Upvotes: 5