WSDL/Soap web service response complex array parsing using KSOAP2 library - php

I have created PHP web service using nusoap
$namespace="http:/mynamespace.com/mynamespace"
$server = new soap_server();
$server->debug_flag = false;
$server->configureWSDL("test", $namespace);
$server->wsdl->schemaTargetNamespace = $namespace;
$server->wsdl->addComplexType(
'Products',
'complexType',
'struct',
'all',
'',
array('ID' => array('name' => 'ID','type' => 'xsd:int'),
'ProductName' => array('name' => 'ProductName','type' => 'xsd:string'),
'ImageUrl' => array('name' => 'ImageUrl','type' => 'xsd:string')
)
);
$server->wsdl->addComplexType(
'ProductsArray',
'complexType',
'array',
'',
'SOAP-ENC:Array',
array(),
array(
array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'tns:Products[]')
),
'tns:Products'
);
$server->register('GetProductDetails', // method name
array('AgentId' => 'xsd:string'), // input parameters
array('return' => 'tns:ProductsArray'), // output parameters
$namespace, // namespace
$namespace . '#GetProductDetails', // soapaction
'rpc', // style
'sequence', // use
'Get Product Details' // documentation
);
function GetProductDetails($AgentId)
{
$productArray = array();
$sqlQry="SELECT pr.products_id, pr.products_image, pd.products_name FROM `products` pr left join products_description pd on pr.products_id=pd.products_id";
$result=mysql_query($sqlQry);
while($row=mysql_fetch_array($result)){
$product=array();
$product["ID"]=$row['products_id'];
$product["ProductName"]=$row['products_name'];
$product["ImageUrl"]=$row['products_image'];
$productArray[]=$product;
}
return $productArray;
}
$HTTP_RAW_POST_DATA = isset($GLOBALS['HTTP_RAW_POST_DATA'])?$GLOBALS['HTTP_RAW_POST_DATA'] : '';
$server->service($HTTP_RAW_POST_DATA);
and I am getting response in android something like
[Products{ID=29; Name=product1; Url=product1.jpg; }, Products{ID=30; Name=product2; Url=product2.jpg; }]
this responce is in one element of response.getProperty(0)
and if I paste this code in http://jsonviewer.stack.hu/ site then it tells me it is not valid json, I am new in nusoap so I don't know how this gives json/XML response
Is there any problem with code?
I have also tried
Android Code:
SoapObject response = (SoapObject) envelope.bodyIn;
SoapObject nameResult = (SoapObject) response.getProperty(0);
In above nameResult I am getting all response in one single property.

I have never used nusoap before but from what I can tell your properly connecting to your db, and according to what i found nusoap can run standard php scripts in which case replaces function GetProductDetails with what i have below (I'm using json_encode), Your problem was with how you load a single result inside the while loop you must use array_push() instead.
function GetProductDetails($AgentId)
{
// array for JSON response
$productArray = array();
$sqlQry="SELECT pr.products_id, pr.products_image, pd.products_name FROM `products` pr left join products_description pd on pr.products_id=pd.products_id";
$result=mysql_query($sqlQry);
while ($row = mysql_fetch_array($result)) {
// temp user array
$product=array();
$product["ID"]=$row['products_id'];
$product["ProductName"]=$row['products_name'];
$product["ImageUrl"]=$row['products_image'];
// push single product into final response array
array_push($poductArray["products"], $product);
}
// echoing JSON response
echo json_encode($productArray);
}
Hope this works it's clearly untested as I dont have your sql (but it's copied from similar script on my server and rewritten for your purposes) also you should cover the case your database is empty

I have solved it by my self, this is help here if any one needs how to solve this..
I am getting response is parsed using Vector and after that I just simply make a loop that get every attribute and add to ArrayList<HashMap<String, String>>.
My process is like, get response from webservice and parsing that response using vector and I just retrieve properties and add to ArrayList<HashMap<String, String>>.
So If here anyone wants to parse complexType Array Response and finds problem like me, they can find solution like following code
public static final ArrayList<HashMap<String, String>> productMapArray = new ArrayList<HashMap<String, String>>();
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
envelope.dotNet = true;
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
request.addProperty("user_id", "1");
try {
androidHttpTransport.call(SOAP_ACTION, envelope);
Vector<SoapObject> response = (Vector<SoapObject>)envelope.getResponse();
for (SoapObject soapObject : response) {
HashMap<String, String> map = new HashMap<String, String>();
map.put(KEY_ID, soapObject.getProperty(KEY_ID).toString());
map.put(KEY_PRODUCT, soapObject.getProperty(KEY_PRODUCT).toString());
map.put(KEY_IMG, soapObject.getProperty(KEY_IMG).toString());
productMapArray.add(map);
}
if (response.toString().equalsIgnoreCase("invalid")) {
result = false;
} else {
result = true;
}
} catch (SocketException ex) {
result = false;
Log.e("Error : ", "Error on soapPrimitiveData() " + ex.getMessage());
ex.printStackTrace();
} catch (Exception e) {
result = false;
Log.e("Error : ", "Error on soapPrimitiveData() " + e.getMessage());
e.printStackTrace();
}
return result;

Related

Mock response and use history middleware at the same time in Guzzle

Is there any way to mock response and request in Guzzle?
I have a class which sends some request and I want to test.
In Guzzle doc I found a way how can I mock response and request separately. But how can I combine them?
Because, If use history stack, guzzle trying to send a real request.
And visa verse, when I mock response handler can't test request.
class MyClass {
public function __construct($guzzleClient) {
$this->client = $guzzleClient;
}
public function registerUser($name, $lang)
{
$body = ['name' => $name, 'lang' = $lang, 'state' => 'online'];
$response = $this->sendRequest('PUT', '/users', ['body' => $body];
return $response->getStatusCode() == 201;
}
protected function sendRequest($method, $resource, array $options = [])
{
try {
$response = $this->client->request($method, $resource, $options);
} catch (BadResponseException $e) {
$response = $e->getResponse();
}
$this->response = $response;
return $response;
}
}
Test:
class MyClassTest {
//....
public function testRegisterUser()
{
$guzzleMock = new \GuzzleHttp\Handler\MockHandler([
new \GuzzleHttp\Psr7\Response(201, [], 'user created response'),
]);
$guzzleClient = new \GuzzleHttp\Client(['handler' => $guzzleMock]);
$myClass = new MyClass($guzzleClient);
/**
* But how can I check that request contains all fields that I put in the body? Or if I add some extra header?
*/
$this->assertTrue($myClass->registerUser('John Doe', 'en'));
}
//...
}
#Alex Blex was very close.
Solution:
$container = [];
$history = \GuzzleHttp\Middleware::history($container);
$guzzleMock = new \GuzzleHttp\Handler\MockHandler([
new \GuzzleHttp\Psr7\Response(201, [], 'user created response'),
]);
$stack = \GuzzleHttp\HandlerStack::create($guzzleMock);
$stack->push($history);
$guzzleClient = new \GuzzleHttp\Client(['handler' => $stack]);
First of all, you don't mock requests. The requests are the real ones you are going to use in production. The mock handler is actually a stack, so you can push multiple handlers there:
$container = [];
$history = \GuzzleHttp\Middleware::history($container);
$stack = \GuzzleHttp\Handler\MockHandler::createWithMiddleware([
new \GuzzleHttp\Psr7\Response(201, [], 'user created response'),
]);
$stack->push($history);
$guzzleClient = new \GuzzleHttp\Client(['handler' => $stack]);
After you run your tests, $container will have all transactions for you to assert. In your particular test - a single transaction. You are interested in $container[0]['request'], since $container[0]['response'] will contain your canned response, so there is nothing to assert really.

SOAP Request return a null response

I am not familiar with SOAP webservices but, i need consume one for a project.
Acording the specification, the webservice has 3 (three) methods:
Enviar
Consultar
Validar
So, i use an instance of SoapClient:
# http://webservices.sathomologa.sef.sc.gov.br/wsDfeSiv/Recepcao.asmx?WSDL
$this->client = new SoapClient(static::SERVICE_WSDL, [
'exceptions' => 1,
'trace' => 1
]);
I think that, i can't use the "auto mapped" methods because i need sign the XML data.
So, i use the SoapClient::__doRequest method:
# Enviar
$this->operation = $operation;
# http://tempuri.org/Enviar
$action = 'http://tempuri.org/' . $operation;
# http://webservices.sathomologa.sef.sc.gov.br/wsDfeSiv/Recepcao.asmx
$location = static::SERVICE_URL;
$v = SOAP_1_1;
$data = $this->xml->saveXML();
try {
$this->client->__doRequest($data, $location, $action, $v);
var_dump($this->client->__getLastResponse());
} catch(SoapFault $e) {
var_dump($e);
}
My problem is that, the SoapClient::__getLastResponse() always return null. Any ideas ?

PubNub Server does not format message properly

I have the server configuration to speak to the Android clients as:
<?php
require_once("mysql.class.php");
require_once("lib/autoloader.php");
// Setting up the PubNub Server:
use Pubnub\Pubnub;
$pubnub = new Pubnub(
"pub-c...", ## PUBLISH_KEY
"sub-c..." ## SUBSCRIBE_KEY
);
// Publishing :
$post_data = json_encode(array("type"=> "groupMessage", "data" => array("chatUser" => "SERVER", "chatMsg" => "Now lets talk", "chatTime"=>1446514201516)));
$info = $pubnub->publish('MainChat', $post_data);
print_r($info);
print_r($post_data);
?>
and html:
<!doctype html>
<html>
<head>
<title>PubNub PHP Test Page</title>
</head>
<body>
<form method="POST" action="index.php">
<input type="submit" name="submit" value="TestSendMessage" />
</form>
</body>
</html>
The publish function works in the server as I can see the messages arrive in the log console of the client Android app, but the message is never parsed correctly and therefore does not appear in the listview given the SubscribeCallback:
public void subscribeWithPresence(String channel) {
this.channel = channel;
Callback subscribeCallback = new Callback() {
#Override
public void successCallback(String channel, Object message) {
if (message instanceof JSONObject) {
try {
JSONObject jsonObj = (JSONObject) message;
JSONObject json = jsonObj.getJSONObject("data");
final String name = json.getString(Constants.JSON_USER);
final String msg = json.getString(Constants.JSON_MSG);
final long time = json.getLong(Constants.JSON_TIME);
if (name.equals(mPubNub.getUUID())) return; // Ignore own messages
final ChatMessage chatMsg = new ChatMessage(name, msg, time);
presentActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
// Adding messages published to the channel
mChatAdapter.addMessage(chatMsg);
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
Log.d("PUBNUB", "Channel: " + channel + " Msg: " + message.toString());
}
#Override
public void connectCallback(String channel, Object message) {
Log.d("Subscribe", "Connected! " + message.toString());
//hereNow(false);
// setStateLogin();
}
};
try {
mPubNub.subscribe(this.channel, subscribeCallback);
//presenceSubscribe();
} catch (PubnubException e) {
e.printStackTrace();
// Checking if success
Log.d("Fail subscribe ", "on channel: " + channel);
}
}
Testing the server output in the browser by clicking TestSendMessage yields:
Array ( [0] => 1 [1] => Sent [2] => 14465159776373950 ) {"type":"groupMessage","data":{"chatUser":"SERVER","chatMsg":"Now lets talk","chatTime":1446514201516}}
and in app the log output from line: Log.d("PUBNUB", "Channel: " + channel + " Msg: " + message.toString());
Returns: D/PUBNUB: Channel: MainChat Msg: {"type":"groupMessage","data":{"chatUser":"SERVER","chatMsg":"Now lets talk","chatTime":1446514201516}}
as it should, but the message never appears within the ListView of messages and thusly fails the JSON parsing.
The JSON tags are straightforward from the Constants class as:
public static final String JSON_GROUP = "groupMessage";
public static final String JSON_USER = "chatUser";
public static final String JSON_MSG = "chatMsg";
public static final String JSON_TIME = "chatTime";
How can the server sending be reconfigured to allow the success of in app parsing?
Sending JSON over PubNub
Send the JSON object without stringifying it first. In the case for PHP, do not json_encode the message. PubNub SDK will encode and decode it for you.
This:
$post_data = array("type"=> "groupMessage", "data" => array(
"chatUser" => "SERVER", "chatMsg" => "Now lets talk",
"chatTime"=>1446514201516));
Not this:
$post_data = json_encode(array("type"=> "groupMessage", "data" => array(
"chatUser" => "SERVER", "chatMsg" => "Now lets talk",
"chatTime"=>1446514201516)));
Please comment if this resolves or not.

web-service to get sharepoint data gives error

I am executing following in my web-service file to get the sharepoint list data:
$authParams = array('login' => 'user', 'password' => 'pass');
/* A string that contains either the display name or the GUID for the list.
* It is recommended that you use the GUID, which must be surrounded by curly
* braces ({}).
*/
$listName = "TestList1";
$rowLimit = '150';
$wsdl = "http://192.168.1.197:5000/sharepoint/ListsWSDL.wsdl";
//Creating the SOAP client and initializing the GetListItems method parameters
$soapClient = new SoapClient($wsdl, $authParams);
$params = array('listName' => $listName, 'rowLimit' => $rowLimit);
//Calling the GetListItems Web Service
$rawXMLresponse = null;
try{
$rawXMLresponse = $soapClient->GetListItems($params)->GetListItemsResult->any;
}
catch(SoapFault $fault){
echo 'Fault code: '.$fault->faultcode;
echo 'Fault string: '.$fault->faultstring;
}
But it is going into the catch block with following error:
Fault code: HTTPFault string: Not Found
what is the problem. Thanks in advance.
Try http://[sharepoint site url]/_vti_bin/lists.asmx?WSDL for the wsdl,
but the actual webservice exists on http://[sharepoint site url]/_vti_bin/lists.asmx
This list of webservices has a page showing the url for each service.

FirePHP doesn't always write log messages

I set my loggers up in my Bootstrap.php like so:
$logger = new Zend_Log();
if($environment->debug == '1')
{
$stream = #fopen('/var/www/html/rta/rta.log','a',false);
if(!$stream){ throw new Exception('Failed to open log stream'); }
$writer = new Zend_Log_Writer_Stream($stream);
$logger->addWriter($writer);
$logger->addWriter(new Zend_Log_Writer_Firebug());
}
else
{
// Do something else
}
Zend_Registry::set('logger',$logger);
I have the following code that I set up to fail:
$data = array(
'config_id' => $config->getConfigId(),
'pass_column' => $config->getPassColumn(),
'filename' => $config->getFilename(),
'date_format' => $config->getDateFormat(),
'mapping_config' => $config->getMappingConfig(),
'config_name' => $config->getConfigName(),
'client_id' => $config->getClientId(),
'description' => $config->getDescription(),
);
$where = $this->getDbTable()->getAdapter()->quoteInto('config_id = ?',$config->getConfigId());
$where = null;
try
{
$this->getDbTable()->update($data,$where);
}catch(Exception $e)
{
Zend_Registry::get('logger')->err('Could not update configuration.');
Zend_Registry::get('logger')->err($e);
return false;
}
return true;
I set two log writers: Stream and FirePHP.
The stream log writer successfully caught and wrote the exception but FirePHP didn't do anything. If I put other log messages other places in my code, like indexAction it shows those just fine in both. Am I missing something?
EDIT
The failure code is in my database mapper, not a controller. Could it be that it doesn't have access to the HTTP headers?
The following example below shows how to make FirePHP get the header info it needs without using the FrontController.
// create the logger and log writer
$writer = new Zend_Log_Writer_Firebug();
$logger = new Zend_Log($writer);
// get the wildfire channel
$channel = Zend_Wildfire_Channel_HttpHeaders::getInstance();
// create and set the HTTP response
$response = new Zend_Controller_Response_Http();
$channel->setResponse($response);
// create and set the HTTP request
$channel->setRequest(new Zend_Controller_Request_Http());
// record log messages
$logger->info('info message');
$logger->warn('warning message');
$logger->err('error message');
// insert the wildfire headers into the HTTP response
$channel->flush();
// send the HTTP response headers
$response->sendHeaders();
?>

Categories