I want to write phpunit test for save method at my repository. My repo code is:
public function saveCustomer(Custom $custom)
{
try
{
$custom->save();
return array(
'status' => true,
'customerId' => $custom->getId()
);
}
catch(\Exception $e)
{
return array(
'status' => false,
'customerId' => 0
);
}
}
I wrote this test:
public function testSaveNewUye()
{
$request = array(
'email' => 'www#www.com',
'phone' => '555 555 555',
'password' => '34636'
);
$repo = new CustomerRepository();
$result_actual = $this->$repo->saveCustomer($request);
$result_expected = array(
'status' => true,
'customerId' => \DB::table('custom')->select('id')->orderBy('id', 'DESC')->first() + 1
);
self::assertEquals($result_expected, $result_actual);
}
I got the error given below:
ErrorException: Object of class App\CustomerRepository could not be converted to int
Can you help me?
Problem is here:
$repo = new CustomerRepository();
$result_actual = $this->$repo->saveCustomer($request);
You are assigning and using variables not the same.
Try like this instead:
$this->repo = new CustomerRepository();
// ^------- assign to `$this`
$result_actual = $this->repo->saveCustomer($request);
// ^------- remove `$`
When doing $this->$repo-> PHP tries to convert the (object) $repo to a string $this->(object)-> which does not work.
Then you have a second error here:
\DB::table('custom')->select('id')->orderBy('id', 'DESC')->first() + 1
From the database you get an object (instanceof stdClass) which you cannot simply + 1.
The whole thing is probably something like
\DB::table('custom')->select('id')->orderBy('id', 'DESC')->first()->id + 1
(From the returned object, you want the property id.)
Related
I have an object function to send news to an API:
class Manager
{
public function __construct(GuzzleHttp\Client $client)
{
$this->client = $client;
}
public function uploadNews($title, $text, $timestamp = null)
{
// DEFAULT FOR PUBLISH TIMESTAMP IS SET IF VALUE IS NULL
$timestamp = $timestamp ?? time();
$requestBody = [
'header' => [
'Accept' => 'application/json',
],
'timeout' => 300,
'body' => [
'title' => $title,
'text' => $text,
'publish_date' => $timestamp,
]
];
return $this->client->request('POST', 'http://api/endpoint', $requestBody);
}
}
How do I write a PHPUnit unit test to test the final $request passed to the client's request() function is of the expected format, when the $timestamp is not set (the API expects a timestamp)? I've written a unit test. But is not ideal, since there could be a difference in the tow timestamps.
class ManagerTest extends \PHPUnit\Framework\TestCase
{
public function testCanUploadNewsWithoutTimestamp()
{
$expectedRequestBody = [
'header' => [
'Accept' => 'application/json',
],
'timeout' => 300,
'body' => [
'title' => 'News title',
'text' => 'News article sample text.',
'publish_date' => time(),
]
];
$guzzleMock = $this->createMock(GuzzleHttp\Client::class);
$guzzleMock->expects($this->once())
->method('request')
->with(
'POST',
'http://api/endpoint',
$expectedRequestBody
);
(new Manager($guzzleMock))->uploadNews(
'News title',
'News article sample text.'
);
}
}
This is my current test result:
Parameter 2 for invocation GuzzleHttp\Client::request('POST', 'http://api/endpoint', Array (...)) does not match expected value.
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
## ##
'body' => Array (
'title' => 'News title'
'text' => 'News article sample text.'
- 'publish_date' => 1574550178
+ 'publish_date' => 1574550179
)
)
Please note that the only thing I need to make sure is that the timestamp is passed with request. The value of the timestamp doesn't matter.
PS: I'm really new to Test Driven Development, so the answer might be obvious and I might still not know it.
I have an ecommerce website which is under development right now. I bought a web software. I want to connect to the webservice and add some brands.
This is my webservice WSDL url: http://www.cantabu.com/Servis/UrunServis.svc?wsdl
The method for adding a new brand is "SaveMarka".
This is my initial code:
ini_set("soap.wsdl_cache_enabled", "0");
$wsdl = "http://www.cantabu.com/Servis/UrunServis.svc?wsdl";
$authCode = "MY_WEBSERVICE_AUTHENTICATION_CODE";
$client = new SoapClient($wsdl);
When i print_r $client->__getFunctions() The result is (Related to SaveMarka method):
Array
(
[4] => SaveMarkaResponse SaveMarka(SaveMarka $parameters)
)
And when i print_r $client->__getTypes(), the result is (Up to 5th index of the result array, because others are unrelated to SaveMarka):
Array
(
[0] => struct ArrayOfint {
int int;
}
[1] => struct ArrayOfstring {
string string;
}
[2] => struct ArrayOfKategori {
Kategori Kategori;
}
[3] => struct Kategori {
boolean Aktif;
int ID;
string Icerik;
string Kod;
int PID;
string SeoAnahtarKelime;
string SeoSayfaAciklama;
string SeoSayfaBaslik;
int Sira;
string Tanim;
}
[4] => struct ArrayOfMarka {
Marka Marka;
}
[5] => struct Marka {
boolean Aktif;
int ID;
string SeoAnahtarKelime;
string SeoSayfaAciklama;
string SeoSayfaBaslik;
string Tanim;
}
In their web service document, they say; if you want to add a new brand, the ID should be 0 (zero). Otherwise, whe webservice will update the brand related to that ID.
I have tried different variations of SaveMarka method. But they all failed with varied results.
First of all, i have created a Marka class.
class Marka{
var $ID;
var $SeoAnahtarKelime;
var $SeoSayfaBaslik;
var $SeoSayfaAciklama;
var $Tanim;
var $Aktif;
function __construct($id, $seo, $seoAciklama, $seoBaslik, $ad){
$this->ID = $id;
$this->SeoAnahtarKelime = $seo;
$this->SeoSayfaBaslik = $seoBaslik;
$this->SeoSayfaAciklama = $seoAciklama;
$this->Tanim = $ad;
$this->Aktif = true;
}
}
Then i have tried to do this:
$marka = new Marka(0, "pg", "P&G", "P&G", "P&G");
$newMarka = array(
"UyeKodu" => $authCode",
"Marka" => $marka
);
$client->__soapCall("SaveMarka", $newMarka);
The result is:
Type: SoapFault
Message: The formatter threw an exception while trying to deserialize
the message: Error in deserializing body of request message for
operation 'SaveMarka'. End element 'Body' from namespace
'http://schemas.xmlsoap.org/soap/envelope/' expected. Found element
'param1' from namespace ''. Line 2, position 150.
I also tried (I don't know why):
$marka = new Marka(0, "pg", "P&G", "P&G", "P&G");
$newMarka = array(array(
"UyeKodu" => $authCode",
"Marka" => $marka
));
$client->__soapCall("SaveMarka", $newMarka);
And the result is:
Type: SoapFault
Message: Object reference not set to an instance of an object.
Then i get rid of the Marka class and tried to do it simpler without using a class:
$newMarka = array(
"UyeKodu" => $authCode,
"ID" => 0,
"Tanim" => "P&G",
"Aktif" => true,
"SeoAnahtarKelime" => "pg",
"SeoSayfaBaslik" => "P&G",
"SeoSayfaAciklama" => "P&G"
);
$client->__soapCall("SaveMarka", $newMarka);
Result is:
Type: SoapFault
Message: The formatter threw an exception while trying to deserialize
the message: Error in deserializing body of request message for
operation 'SaveMarka'. End element 'Body' from namespace
'http://schemas.xmlsoap.org/soap/envelope/' expected. Found element
'param1' from namespace ''. Line 2, position 150.
And also (again, i don't know why)
$newMarka = array(array(
"UyeKodu" => $authCode,
"ID" => 0,
"Tanim" => "P&G",
"Aktif" => true,
"SeoAnahtarKelime" => "pg",
"SeoSayfaBaslik" => "P&G",
"SeoSayfaAciklama" => "P&G"
));
$client->__soapCall("SaveMarka", $newMarka);
And the result is:
Type: SoapFault
Message: Object reference not set to an instance of an object.
What am i doing wrong?
Can anyone please help me with adding a new brand? I have supplied the functions, types, wsdl link and all my tries.
Please, help.
I am using XML-RPC Lib for PHP to use online signature.
This is the official doc :
$doc = array(
"content" => new xmlrpcval($doc_content, "base64"),
"name" => new xmlrpcval($doc_name, "string")
);
$language = "fr";
$signers = array(new xmlrpcval($signer, "struct"));
$request = array(
"documents" => new xmlrpcval(array(new xmlrpcval($doc, "struct")), "array"),
...
But now I want to put several documents in the request. Here is my code :
$docs = array();
foreach ($documents as $document)
{
// Signature field
$field = array(
'page' => new xmlrpcval($document->page, 'int'),
'x' => new xmlrpcval($document->x, 'int'),
'y' => new xmlrpcval($document->y, 'int'),
'label' => new xmlrpcval($document->nom, 'string'),
);
// Document
$docs []= new xmlrpcval(array(
'content' => new xmlrpcval($document->content, 'base64'),
'name' => new xmlrpcval($document->nom, 'string'),
'signatureFields' => new xmlrpcval($field, 'array'),
),'struct');
}
$request = array(
'documents' => new xmlrpcval($docs, 'array'),
And I catch this error :
Message: Call to a member function serialize() on a non-object
Does someone allready used this library ? Cause I am lost right now..
I have come to realise that even if we have an array still for using the phpxmlrpc library, we need to define the array individually, so if one has to pass an array here is what can be done,
$listids // this was my one dimensional array
$subs_list_array = array();
foreach ($listids as $id) {
$subs_list_array[] = new xmlrpcval($id, "int");
}
$msg = new xmlrpcmsg(
"contact.subscribe", array(
//Set user id
new xmlrpcval($registration_id, "int"),
new xmlrpcval($subs_list_array, "array")// <- Now I am able to use the array
)
);
For recursive encoding of php arrays, you can also use the php_xmlrpc_encode function that will recursively convert arbitrarily deep data structures
I have found a php script that would in theorie match my needs, however I cant get it to work and I was wondering if maybe the script is outdated or if I am doing something wrong.
The script looks like this:
<?php
/**
* #package Yahoo Answer
* #author The HungryCoder
* #link http://hungrycoder.xenexbd.com/?p=953
* #version 1.0
* #license GPL, This class does not come with any expressed or implied warranties! Use at your own risks!
*/
class yahooAnswer{
var $appID;
var $searchQuestionURL = 'http://answers.yahooapis.com/AnswersService/V1/questionSearch?';
var $getQuestionURL = 'http://answers.yahooapis.com/AnswersService/V1/getQuestion?';
private $numResults = 10;
private $numStart = 0;
function __construct($appid) {
$this->appID=$appid;
}
function set_numResults($num_results){
$this->numResults = $num_results;
}
/**
* Search for questions for the given keywords. Returned results can be associative array or XML
* #param <string> $kewyord
* #return <string> Returns the results set either in XML format or associative array.
*/
function search_questions($params){
if(!is_array($params)){
throw new Exception('The parameters must be an array!');
}
$defaults = array(
'search_in' => '',
'category_name' => '',
'date_range' => '', //7, 7-30, 30-60, 60-90, more90
'sort' => 'relevance', //relevance, date_desc, date_asc
'type' => 'all',
'output' => 'php',
'results' => $this->numResults,
'start' => $this->numStart,
'region' => 'us',
'appid' => $this->appID,
);
$params = array_merge($defaults,$params);
if(!$params['appid']){
throw new Exception('APP ID is empty!', 404);
}
if(!$params['query']) {
throw new Exception('Query is not set!', '404');
}
$req_params = $this->array2query_string($params);
$url = $this->searchQuestionURL.$req_params;
$results = $this->make_call($url);
if($params['output']=='php'){
$results = unserialize($results);
return $results['Questions'];
}
return $results;
}
/**
* Get all answers of a given question ID
* #param <array> $params keys are: question_id, output, appid
* #return <string> Returns all answers in expected format. default format is php array
*/
function get_question($params){
if(!is_array($params)){
throw new Exception('The parameter must be an array!');
}
$defaults = array(
'question_id' => '',
'output' => 'php',
'appid' => $this->appID,
);
$params = array_merge($defaults,$params);
if(!$params['appid']){
throw new Exception('APP ID is empty!', 404);
}
if(!$params['question_id']) {
throw new Exception('Question ID is not set!', '404');
}
$req_params = $this->array2query_string($params);
$url = $this->getQuestionURL.$req_params;
$results = $this->make_call($url);
if($params['output']=='php'){
$results = unserialize($results);
return $results['Questions'][0];
}
return $results;
}
protected function make_call($url){
if(function_exists('curl_init')){
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);
curl_setopt($ch, CURLOPT_TIMEOUT,60);
$result = curl_exec($ch);
curl_close($ch);
return $result;
} else if(function_exists('file_get_contents')) {
return file_get_contents($url);
} else {
throw new Exception('No method available to contact remote server! We must need cURL or file_get_contents()!', '500');
}
}
protected function array2query_string($array){
if(!is_array($array)) throw new Exception('Parameter must be an array', '500');
$params ='';
foreach($array as $key=>$val){
$params .= "$key=$val&";
}
return $params;
}
}
$appid = 'MYAPPID';
$params = array(
'query' => 'test', //enter your keyword here. this will be searched on yahoo answer
'results' => 2, //number of questions it should return
'type' => 'resolved', //only resolved questiosn will be returned. other values can be all, open, undecided
'output' => 'php', //result will be PHP array. Other values can be xml, json, rss
);
$question_id = 'test'; //without this i get an error "Question ID is not set!"
$yn = new yahooAnswer($appid);
//search questions
try{
$questions = $yn->search_questions($params);
} catch (Exception $e){
echo ($e->getMessage());
}
foreach ($questions as $question) {
//now get the answers for the question_id;
try{
$answers = $yn->get_question(array('question_id'=>$question_id));
echo '<pre>';
print_r($answers);
echo '<pre>';
} catch (Exception $e){
echo($e->getMessage());
}
}
?>
But instead of a valid output I just get this:
Array
(
[id] =>
[type] =>
[Subject] =>
[Content] =>
[Date] =>
[Timestamp] =>
[Link] => http://answers.yahoo.com/question/?qid=
[Category] => Array
(
[id] =>
[content] =>
)
[UserId] =>
[UserNick] =>
[UserPhotoURL] =>
[NumAnswers] =>
[NumComments] =>
[ChosenAnswer] =>
[ChosenAnswererId] =>
[ChosenAnswererNick] =>
[ChosenAnswerTimestamp] =>
[ChosenAnswerAwardTimestamp] =>
)
I have tried it with other keywords, but the result is always the same.
This part $question_id = 'test'; is not included in the official script, but without it I keep getting Question ID is not set!.
I also tried to change it, add it at another place in the script etc. Everything I could think of, but the result was always that array with no information besides the [Link]
Since I got almost zero php experience at all, I am not even where start looking for an error :/ Would be glad if some1 could point me in the right direction!
Regards!
p.s. of course "MYAPPID" is changed to my real yahoo app id.
In order to make this example work, change this line:
$answers = $yn->get_question(array('question_id'=>$question_id));
to:
$answers = $yn->get_question(array('question_id'=>$question['id']));
That change pulls the actual question ID out of the response from search_questions(), and uses it in the call to get_question().
I would like to query some stuffs via SOAP by generating WSDL with NuSOAP.
I know there are lots of questions related to the topic, but I didn't have success to adapt the codes to my particular problem.
I was successful in generating WSDL code which returns just an array of structs (associative array), BUT I would rather like to return an object (struct) which contains an integer variable, a string variable AND an array of structs.
So, this is the code that works for returning an array of structs:
<?php
function getStuffs( $user='', $pass='' ) {
// here we can check user and pass and do whatever (if it isn't alright, we can throw exception or return NULL or sg. similar)
// .......
$stuff_array = array();
$stuff_array[] = array( 'id'=>122, 'name'=>'One stuff');
$stuff_array[] = array( 'id'=>213, 'name'=>'Another stuff');
$stuff_array[] = array( 'id'=>435, 'name'=>'Whatever stuff');
$stuff_array[] = array( 'id'=>65, 'name'=>'Cool Stuff');
$stuff_array[] = array( 'id'=>92, 'name'=>'Wow, what a stuff');
return $stuff_array;
}
require_once 'nusoap/lib/nusoap.php';
$server = new soap_server;
// $myNamespace = $_SERVER['SCRIPT_URI'];
$myNamespace = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];
$server->configureWSDL('MyStuffService', 'urn:' . $myNamespace);
// $server->wsdl->schemaTargetNamespace = 'http://soapinterop.org/xsd/';
$server->wsdl->addComplexType(
// name
'Stuffs',
// typeClass (complexType|simpleType|attribute)
'complexType',
// phpType: currently supported are array and struct (php assoc array)
'struct',
// compositor (all|sequence|choice)
'all',
// restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
'',
// elements = array ( name = array(name=>'',type=>'') )
array(
'id' => array(
'name' => 'id',
'type' => 'xsd:int'
),
'name' => array(
'name' => 'name',
'type' => 'xsd:string'
)
)
);
$server->wsdl->addComplexType(
// name
'StuffsArray',
// typeClass (complexType|simpleType|attribute)
'complexType',
// phpType: currently supported are array and struct (php assoc array)
'array',
// compositor (all|sequence|choice)
'',
// restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
'SOAP-ENC:Array',
// elements = array ( name = array(name=>'',type=>'') )
array(),
// attrs
array(
array(
'ref' => 'SOAP-ENC:arrayType',
'wsdl:arrayType' => 'tns:Stuffs[]'
)
),
// arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
'tns:Stuffs'
);
$server->register(
// string $name the name of the PHP function, class.method or class..method
'getStuffs',
// array $in assoc array of input values: key = param name, value = param type
array(
'user' => 'xsd:string',
'pass' => 'xsd:string'
),
// array $out assoc array of output values: key = param name, value = param type
array(
'return' => 'tns:StuffsArray'
),
// mixed $namespace the element namespace for the method or false
'urn:' . $myNamespace,
// mixed $soapaction the soapaction for the method or false
'urn:' . $myNamespace . "#getStuffs",
// mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
'rpc',
// mixed $use optional (encoded|literal) or false
'encoded',
// string $documentation optional Description to include in WSDL
'Fetch array of Stuffs ("id", "name").' // documentation
);
#$server->wsdl->schemaTargetNamespace = $myNamespace;
$server->service(isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '');
exit();
?>
In a C# Console Application, after adding a Web Reference called "StuffService" with the "?wsdl" appended to the appropriate URL where this PHP-file can be found, this code works, I can perfectly query the stuff_array values like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WebServiceTest
{
class Program
{
static void Main(string[] args)
{
StuffService.MyStuffService myService = new StuffService.MyStuffService();
StuffService.Stuffs[] stuffs = myService.getStuffs("someone", "1234");
foreach (var stuff in stuffs)
{
Console.WriteLine(stuff.id+".: "+stuff.name);
}
Console.WriteLine();
Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}
That's cool, BUT I'd like to develop this code to give back an object like this:
class ResponseObject {
public $responseCode = 0;
public $responseMessage = '';
public $stuffArray = NULL;
}
$responseObject = NULL;
function getStuffs( $user='', $pass='' ) {
global $responseObject;
$responseObject = new ResponseObject();
// check stuffs in a simple way now
if($user != 'someone' && $pass != '1234'){
$responseObject->responseCode = 2;
$responseObject->responseMessage = 'Authentication failed';
return $responseObject;
}
$responseObject->stuffArray = array();
$responseObject->stuffArray[] = array( 'id'=>122, 'name'=>'One stuff');
$responseObject->stuffArray[] = array( 'id'=>213, 'name'=>'Another stuff');
$responseObject->stuffArray[] = array( 'id'=>435, 'name'=>'Whatever stuff');
$responseObject->stuffArray[] = array( 'id'=>65, 'name'=>'Cool Stuff');
$responseObject->stuffArray[] = array( 'id'=>92, 'name'=>'Wow, what a stuff');
$responseObject->responseCode = 1;
$responseObject->responseMessage = 'Successful!';
return $responseObject;
}
What's the appropriate NuSOAP code for that?
Thanks!! :)
I hope I could clarify what I would like to achieve: returning a struct which contains an int, a string and an array of structs, but don't know how to write the appropriate NuSOAP-code for that. This way I could firstly check the responseCode, and handle it with the appropriate error messages OR outputting the stuffArray, etc.
After long hours of experimentation, I found the solution!
So giving back a structure containing three members - an int responseCode, a string responseMessage and an array of structs called stuffArray in the example - via SOAP with NuSOAP (PHP) looks like this below, I put some comments in the code to make it more unambiguous:
<?php
class ResponseObject {
public $responseCode = 0;
public $responseMessage = 'Unknown error!';
public $stuffArray = NULL;
}
/**
* #return object
*/
function getStuffs( $user='', $pass='' ) {
$responseObject = new ResponseObject();
// check stuffs in a simple way now
if( !($user == 'someone' and $pass == '1234') ){
$responseObject->responseCode = 2;
$responseObject->responseMessage = 'Authentication failed!';
return $responseObject;
}
$responseObject->stuffArray = array();
$responseObject->stuffArray[] = array( 'id'=>122, 'name'=>'One stuff');
$responseObject->stuffArray[] = array( 'id'=>213, 'name'=>'Another stuff');
$responseObject->stuffArray[] = array( 'id'=>435, 'name'=>'Whatever stuff');
$responseObject->stuffArray[] = array( 'id'=>65, 'name'=>'Cool Stuff');
$responseObject->stuffArray[] = array( 'id'=>92, 'name'=>'Wow, what a stuff');
$responseObject->responseCode = 1;
$responseObject->responseMessage = 'Successful!';
return $responseObject;
}
require_once 'nusoap/lib/nusoap.php';
$server = new soap_server;
// $myNamespace = $_SERVER['SCRIPT_URI'];
$myNamespace = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];
$server->configureWSDL(
// string $serviceName, name of the service
'MyStuffService',
// mixed $namespace optional 'tns' service namespace or false
// 'urn:' . $myNamespace
$myNamespace
);
// $server->wsdl->schemaTargetNamespace = 'http://soapinterop.org/xsd/';
$server->wsdl->schemaTargetNamespace = $myNamespace;
$server->wsdl->addComplexType(
// name
'Stuffs',
// typeClass (complexType|simpleType|attribute)
'complexType',
// phpType: currently supported are array and struct (php assoc array)
'struct',
// compositor (all|sequence|choice)
'all',
// restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
'',
// elements = array ( name = array(name=>'',type=>'') )
array(
'id' => array(
'name' => 'id',
'type' => 'xsd:int'
),
'name' => array(
'name' => 'name',
'type' => 'xsd:string'
)
)
);
$server->wsdl->addComplexType(
// name
'StuffsArray',
// typeClass (complexType|simpleType|attribute)
'complexType',
// phpType: currently supported are array and struct (php assoc array)
'array',
// compositor (all|sequence|choice)
'',
// restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
'SOAP-ENC:Array',
// elements = array ( name = array(name=>'',type=>'') )
array(),
// attrs
array(
array(
'ref' => 'SOAP-ENC:arrayType',
'wsdl:arrayType' => 'tns:Stuffs[]'
)
),
// arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
'tns:Stuffs'
);
$server->wsdl->addComplexType(
// name
'ResponseObject',
// typeClass (complexType|simpleType|attribute)
'complexType',
// phpType: currently supported are array and struct (php assoc array)
'struct',
// compositor (all|sequence|choice)
'all',
// restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
'',
// elements = array ( name = array(name=>'',type=>'') )
array
(
'responseCode' => array( 'type' => 'xsd:int'),
'responseMessage' => array( 'type' => 'xsd:string'),
'stuffArray' => array( 'type' => 'tns:StuffsArray'
// DON'T UNCOMMENT THE FOLLOWING COMMENTED LINES, BECAUSE THIS WAY IT DOESN'T WORK!!! - Left it in the code not to forget it....
// ,
// 'minOccurs' => '0',
// 'maxOccurs' => 'unbounded'
)
)
);
$server->register(
// string $name the name of the PHP function, class.method or class..method
'getStuffs',
// array $in assoc array of input values: key = param name, value = param type
array(
'user' => 'xsd:string',
'pass' => 'xsd:string'
),
// array $out assoc array of output values: key = param name, value = param type
array(
'return' => 'tns:ResponseObject'
),
// mixed $namespace the element namespace for the method or false
// 'urn:' . $myNamespace,
$myNamespace,
// mixed $soapaction the soapaction for the method or false
// 'urn:' . $myNamespace . "#getStuffs",
$myNamespace . "#getStuffs",
// mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
'rpc',
// mixed $use optional (encoded|literal) or false
'encoded',
// string $documentation optional Description to include in WSDL
'Fetch array of Stuffs ("id", "name").' // documentation
);
// $server->wsdl->schemaTargetNamespace = $myNamespace;
// function def.: nusoap/lib/class.soap_server.php (236)
$server->service(isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '');
// DON'T UNCOMMENT THE FOLLOWING LINES!! - Don't call these headers explicitly,
// everything will be handled in function service() appropriately - I know it by experience that it's not a good choice...
// output:wsdl
// header('Content-Type: text/xml;charset=utf-8');
// header('Content-Type: text/xml');
// echo $server->wsdl->serialize();
exit(0);
Give this file a name, for example getStuffComplex.php, and then copy this file somewhere on your webserver, and remember its path.
For example one domain name on my local webserver is http://soap.local, and the above mentioned PHP-code can be reached at http://soap.local/getStuffComplex.php.
Let's say you want to call getStuffs() function in a C# code via a SOAP client, from a Console Application under Visual Studio 2010. In this case you have to do the following steps:
Create a new Console Application project
Right click "References" - "Add Service Reference"
Click "Advanced..."
Click "Add Web Reference..."
Paste the path of the previously saved PHP-file's URL (with the content above) and append the "?wsdl" string in the URL field. For example in my case: http://soap.local/getStuffComplex.php?wsdl
Click the green right arrow ("Go") or hit Enter after fill out URL field. If getStuff() method is found, the situation is hopeful.
Give the reference a name on the right side (Web reference name), for example "StuffServiceComplex" (I will use this name in my code), than hit Enter. Now you have to see it under "Web References".
Copy the code below into Program.cs, and test it by hitting F5 or clicking the green "play" icon.
The C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services.Protocols;
namespace WebServiceTestComplex
{
class Program
{
static void Main(string[] args)
{
try
{
StuffServiceComplex.MyStuffService myService = new StuffServiceComplex.MyStuffService();
StuffServiceComplex.ResponseObject myRespObject = myService.getStuffs("someone", "1234");
switch (myRespObject.responseCode)
{
// Everything was OK, results can be output
case 1:
Console.WriteLine("Everything's OK, let's write the results to the standard output:");
foreach (var stuff in myRespObject.stuffArray)
{
Console.WriteLine("\t"+stuff.id + ".:\t" + stuff.name);
}
break;
// Authentication failed
case 2:
// Unknown error
case 0:
default:
Console.WriteLine("Error:");
Console.WriteLine("\tError code: "+myRespObject.responseCode);
Console.WriteLine("\tError message: " + myRespObject.responseMessage);
break;
}
}
catch (SoapException e)
{
Console.WriteLine("=== SOAP EXCEPTION!! ===");
Console.WriteLine(e);
}
catch (Exception e)
{
Console.WriteLine("=== OTHER EXCEPTION!! ===");
Console.WriteLine(e.ToString());
}
Console.WriteLine();
Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}
The output:
Everything's OK, let's write the results to the standard output:
122.: One stuff
213.: Another stuff
435.: Whatever stuff
65.: Cool Stuff
92.: Wow, what a stuff
Press a key...
I hope this helps someone who struggled with bringing PHP and SOAP and .NET together.
(Note: take care about character coding when using accents or any special letters. By default, ANSI could be used (but character encodings have to be the same).)