I am trying to make multiple API requests and I have to make the request in different functions that are within a class like so:
class exampleClass
{
function callFunction1 () {
// stuff that makes a call
return $json;
}
function printStuffOut() {
$jsonStuff = $this->callFunction1();
$$jsonStuff->{'result'}[0]->{'fieldName'};
}
function printStuffOut2() {
$jsonStuff = $this->callFunction1();
$jsonStuff->{'result'}[0]->{'fieldName'};
}
}
Am I making two separate API calls?
If I am, is there a way to store that API call information say in an array then use that array in all the other functions in my class?
Answer to first question: Yes you are, each time the method is called it executes all its definition again.
Answer to second question: Yes there is, so called member properties. You can read up about them in the PHP manual here: PHP Manual: Properties
You are making two API calls, but you don't have to.
You can put the contents of a call into a member variable in the class with a default value of NULL, and if you want, you can check if that member variable is NULL before making an API call. For example;
class exampleClass
{
private $api_json = NULL;
private function call_api()
{
if(is_null($this->api_json))
{
$json = // result of api call;
$this->api_json = $json;
}
return $this->api_json;
}
public function printStuffOut() {
$jsonStuff = $this->call_api();
$jsonStuff->{'result'}[0]->{'fieldName'};
}
public function printStuffOut2() {
$jsonStuff = $this->call_api();
$jsonStuff->{'result'}[0]->{'fieldName'};
}
}
You can use following class to achieve multiple API simultaneously/instantly/at once.
Click here to get a class.
How to use it?
Step 1: Get object.
//SANI: GET DATA
$obj = new multiapi();
Step 2: Make a multiple GET Requests.
$obj->data = array(YOUR_URL_1,YOUR_URL_2, OUR_URL_3);
$result = $obj->get_process_requests();
print_r($result);
Step 3: Make a multiple HTTP POST Requests.
//SANI: Request with params only
$obj->data[0]['url'] = 'YOUR_URL_ONE';
$obj->data[0]['post'] = array();
$obj->data[0]['post']['param_1'] = 'param_value_1';
$obj->data[0]['post']['param_2'] = 'param_value_2';
Related
I try to implement a webservice Client using php and got stuck...
I'm using an existing webservice called metadataservice with a known wsdl.
I'll use wsdl2phpgenerator to create the php classes for the datatypes and the Service itself.
Using one of the Webservice Methods (addMetadataToObject), I have to send an Array of objects to the Server.
There is a base class:
class AssetInfo
{
public $dataFieldId = null;
public $dataFieldName = null;
public $dataFieldTagName = null;
public function __construct($dataFieldId, $dataFieldName, $dataFieldTagName)
{
$this->dataFieldId = $dataFieldId;
$this->dataFieldName = $dataFieldName;
$this->dataFieldTagName = $dataFieldTagName;
}
}
and a derived class Holding string values (there are also other derived classes for Longs etc.):
class StringAssetInfo extends AssetInfo
{
public $value = null;
public function __construct($dataFieldId, $dataFieldName,$dataFieldTagName, $value)
{
parent::__construct($dataFieldId, $dataFieldName, $dataFieldTagName);
$this->value = $value;
}
}
For the call of Metadataservice->addMetadataToObject there is also a addMetadataToObject defined:
class addMetadataToObject
{
public $objectId = null;
public $objectType = null;
public $assetInfos = null;
public function __construct($objectId, $objectType)
{
$this->objectId = $objectId;
$this->objectType = $objectType;
}
}
The property $assetInfos should hold an Array of AssetInfo objects. wdsl2phpgenerator creates a class for my MetadataService which is derived from SoapClient. This class provides all the avialable Methods for this Service. Here I only show the addMetadataToObject Method:
public function addMetadataToObject(addMetadataToObject $parameters)
{
return $this->__soapCall('addMetadataToObject', array($parameters));
}
My Code does:
// Define the Data
$ServiceOptions = [];
$AssetInfos = [];
$AssetInfo = new StringAssetInfo(2, "TitleName", "TitleName","New Title Name);
array_push($AssetInfos, $AssetInfo);
// Create the Service
$Service = new MetadataService($ServiceOptions, getServiceWSDL($Options, "MetadataService"));
$Service->__setSoapHeaders(getGalaxySoapHeader($Options));
$NewMetaData = new addMetadataToObject(61755, "ASSET");
$NewMetaData->assetInfos = $AssetInfos;
// Call the Service
$failedAssets = $Service->addMetadataToObject($NewMetaData);
The call throws a Soap Exception that a value could not be extracted. Which makes me wonder. I started to monitor the traffic to the Soap Server using wireshark and yes....there is no value anymore as defined in the StringAsset Info Class...Here is the Soap Body shown by wireshark:
<SOAP-ENV:Body>
<ns1:addMetadataToObject>
<objectId>61755</objectId>
<objectType>ASSET</objectType>
<assetInfos>
<dataFieldId>2</dataFieldId>
<dataFieldName>TitleName</dataFieldName>
<dataFieldTagName>TitleName</dataFieldTagName>
</assetInfos>
</ns1:addMetadataToObject>
Id</SOAP-ENV:Body>
I would expect a tag New Title Name. But ist gone. When I checked the $NewMetaData object in my Code or the $Parameter object in $Service->addMetadataToObject I can see that the property "Value" is defined and set.
For me it seems, that the call to
return $this->__soapCall('addMetadataToObject', array($parameters));
only accepts the properties of the base class AssetInfo but not the properties from the derived class StringAssetInfo.
I also changed the Code to use an Array (instead of an object) for $AssetInfo:
$AssetInfo = array("dataFieldId"=>2, "dataFieldName"=>"TitleName","dataFieldTagName"=>"TitleName, "value"=>"New Title Name");
But without any change. It seems that we have here some Kind of runtime type conversion or type alignment but I can't see the reason of this. I'm still new to webservices at all and also on php (however I have to use both for the Moment:-)
Can anybody comment or give me a hint what's happening here?
I was able to realize it by using Arrays and soapvars, Please note my comments in the code:
$ServiceOptions = [];
$AssetInfos = [];
// I have to use an Array because the Server depends on the order of the properties. I wasn't able to define expected order using the existing objects but with arrays
$AssetInfo = array("dataFieldId"=>2, "dataFieldName"=>"TitleName","dataFieldTagName"=>"TitleName, "value"=>"New Title Name");
// instead of pushing the Array directly, I create an instance of an SoapVar, pass the Array as data and set the Encoding, the expected type and the Namespace uri
array_push($AssetInfos, new SoapVar($AssetInfo, SOAP_ENC_OBJECT, "StringAssetInfo", "http://metadataservice.services.provider.com"));
array_push($AssetInfos, $AssetInfo);
// Create the Service
$Service = new MetadataService($ServiceOptions, getServiceWSDL($Options, "MetadataService"));
$Service->__setSoapHeaders(getGalaxySoapHeader($Options));
$NewMetaData = new addMetadataToObject(61755, "ASSET");
$NewMetaData->assetInfos = $AssetInfos;
// Call the Service
$failedAssets = $Service->addMetadataToObject($NewMetaData);
This produced the expected Output in the Soap Body (and also added some namespaces to the Soap envelope
<SOAP-ENV:Body>
<ns1:addMetadataToObject>
<objectId>61755</objectId>
<objectType>ASSET</objectType>
<assetInfos xsi:type="ns1:StringAssetInfo">
<dataFieldId>2</dataFieldId>
<dataFieldName>TitleName</dataFieldName>
<dataFieldTagName>TitleName</dataFieldTagName>
<value>New Titel Name 1146</value>
</assetInfos>
</ns1:addMetadataToObject>
</SOAP-ENV:Body>
I have a method, which takes a reference
// CarService.php
public function getCars(&$carCollection = null)
{
$promise = // guzzle request for getting all cars would be here
$promise->then(function (ResponseInterface $response) use (&$carCollection) {
$cars= json_decode($response->getBody(), true);
$carCollection= new CarCollection($cars);
});
}
However, when accessing the collection and trying to reuse it, I'm getting the error
Argument 1 passed to {placeholder} must be an instance of {placeholder}, null given
I know that the reason for this is, that the constructor returns nothing, but how can I still assign my variable to a new instance of the CarCollection (which extends Doctrine's ArrayCollection)
I even tried it with a static method as a work around
// CarCollection.php
public static function create(array $cars): CarCollection
{
$carCollection = new CarCollection($cars);
return $carCollection;
}
// CarService.php
public function getCars(&$carCollection = null)
{
$cars = // curl request for getting all cars would be here
$carCollection = CarCollection::create($cars)
}
but it's still null. Why is that? How can I set a referenced variable to a new class?
I access the method like this
$carService = $this->get('tzfrs.vehicle.services.car');
$carCollection = null;
$promises = [
$carService->getCars($carCollection)
];
\GuzzleHttp\Promise\unwrap($promises);
var_dump($carCollection); // null
When I set the reference directly, eg.
// CarService.php
public function getCars(&$carCollection = null)
{
$carCollection = new CarCollection([]);
}
it works without any problems. Seems like the callback is somehow the problem.
Whoever downvoted this, can you please elaborate why and why you voted to close?
I might be misunderstanding the question, but you should be able to modify an object when passing by reference. See here for an example: https://3v4l.org/KtFvZ
In the later example code that you added, you shouldn't pass $carCollection by reference, the & should only be in the method/function defintion, not provided when you call it. I don't think that is your problem though, that should be throwing an error in php7.
I am using xmlprc server in codeignter for web services . the flow of my application is that i need to pass parameters to the xmlrpc server method which then should invoke another controller class method which would set the parameters in a js function and that js method is invoked concurrently .
The problem i am facing is in calling the controller class method from the xmlrpc server method and getting the response to the server parent method which could then be fetched using xmlhttprequest.
my xmlrpc server method is:
function update_p($request) {
$parameters = $request->output_parameters();
$this->session->set_userdata(array("portfolio" =>$parameters['0']["portfolio"]));
$this->session->set_userdata(array("filter" =>$parameters['0']["filter"]));
$url = base_url("ControllerClass/update_p?".$parameters['0']["portfolio"].'&'.$parameters['0']["filter"]);
header("Location: $url");
$xml_rpc_rows=array("portfolio"=>$parameters['0']["portfolio"],"filter"=>$parameters['0']["filter"]);
$response = array(
$xml_rpc_rows,
'struct');
$this->xmlrpc->send_response($response);
}
Controller Class method:
public function update_p() {
$loginid = $this->session->userdata('loginid');
if(!isset($loginid)){
die;
}
error_reporting(E_ERROR);
if (time()>$this->session->userdata('expire')) { redirect("/dashboard/logout?expired=Y","location",401); die; }
$out='';
$request="USER ".$loginid.($this->session->userdata('isMobile')?"#mobile":"")."\n";
if(isset($_GET["portfolio"])) {
$portfolio=trim($_GET["portfolio"]);
$request.='ECHO "LISTP":'."\nLISTP0 #".$portfolio;
if(isset($_GET["filter"])) {
$filter=trim($_GET["filter"]);
$request.=" -".$filter;
}
if(isset($_GET["sort"])) {
$sort=trim($_GET["sort"]);
if ($sort>=1024) $request.=" -s".($sort&1023);
else $request.=" -S".$sort;
}
$ph = isset($_GET["first"]);
if ($ph) {
$this->load->model('Model');
$resultArray = $this->Model->getData($this->session->userdata('loginid'),$this->session->userdata('isMobile')?'mobile':'default','listp');
$request.=" ".$resultArray[0]['listp'];
}
$request.="\nECHO ,\n";
if(isset($_GET["watch"])) {
$portfolio=trim($_GET["watch"]);
if ($ph)
$resultArray = $this->Model->getData($this->session->userdata('loginid'),$this->session->userdata('isMobile')?'mobile':'default','watch');
$request.='ECHO "watchl":'."\nLISTP1 #".$portfolio." -WL ".($ph?$resultArray[0]['watch']:"")."\n";
$request.='ECHO ,"watchs":'."\nLISTP1 #".$portfolio." -WS\nECHO ,\n";
}
}
$request.="RISk\nECHO ,\nPnL\n";
if ($result=$this->getData($request."BYE\n")) {
if (result!='') $out=$result."\n";
}
ob_start('ob_gzhandler');
echo "{".$out."}";
ob_end_flush();
}
I can not figure out how to get the controller method result in the server method anyone who can shed some light on this would be much appreciated .
Thankyou.
Your controller method is expecting to output the result as an echo statement, which goes to the browser, rather than to return it in a variable. This means your server function is having to try to capture the output of that controller method. That setup is much more awkward and prone to error.
Unless you also need to access your update_p method directly from a browser you should change your Controller to simply return the output which really means this controller is more of a library and should probably go in the libraries folder. You will need to change your controller code a bit so that instead of grabbing the parameters from $_GET you are getting them as arguments, which in CodeIgniter is what you should be doing anyway.
So from the end of update_p just do this instead of your echo:
return "{".$out."}";
Then in your xmlrpc server do this:
$controller = new ControllerClass();
$result = $controller->update_p($parameters['0']["portfolio"], $parameters['0']["filter"]);
Then do whatever you want with your $result.
I have a PHP program I'm writing that does a SOAP request, and it returns an Object. I need to write a function where it takes the data from this Object and uses it in various ways, but I don't want it to do a SOAP request each time if the SOAP request for the data in this Object is already resident.
Pseudo-code example:
$price = GetPartPrice("1234");
function GetPartPrice($part_number) {
If Parts_List_Object not found then do SOAP request to get Parts_List_Object.
}
The problem I see is that I don't know where or how to store if the Parts_List_Object is already there. Do I need to set something up to make the StdClass object that gets requested from the SOAP/JSON request global or is there a better method to do all this? Thanks!
One method would be to build a registry of these objects where you store the ones you fetch and look up the ones you need. That allows you to simply grab a reference to the instance that you've already loaded. A very basic example:
class PartListRegistry {
private static $list = array();
// After you do the SOAP request, call this to save a reference to the object
public static function addPartObject($key, $obj) {
self::$list[$key] = $obj;
}
// Call this to see if the object exists already
public static function getPartObject($key) {
if (isset(self::$list[$key])) {
return self::$list[$key];
}
return null;
}
}
function GetPartPrice($part_number) {
$part = PartListRegistry::getPartObject($part_number);
if ($part === null) {
$part = .... // Do your SOAP request here
// Save a reference to the object when you're done
PartListregistry::addPartObject($part_num, $part);
}
// Do your stuff with the part ....
}
I have a php file that previously used to write xml data with tags. Now I'm trying to make it a little remoteobject based. So instead of writing xml I'm trying to return a class object that consists some big multidimensional array. The problem is it is causing a high latency. I'm not sure if it's my php file that is causing latency problem.
My php code :
class output{
public $grid;
public $week;
public $name;
var $_explicitType = "org.test.output";
}
class manager1{
function init($params,$arrayOut)
{
$action = $params[0];
switch ($action)
{
case "reload": return $this->Reload($arrayOut);break;
default:return $this->form($arrayOut);
}
}
private function Reload($arrayOut)
{
$this->getSlice();
$arrayOut->grid = $this->gridValue();
$arrayOut->week = 'no data';
return $arrayOut;
}
private function form($arrayOut)
{
$arrayOut->grid = $this->gridValue();
$arrayOut->week= $this->getAllWeek($this->ThisYear);
return $arrayOut;
}
}
AS-3 code calling php function:
private function init():void{
var _amf:RemoteObject = new RemoteObject();
var params:Array = new Array(); //parameters array
params.push("default");
var arrayOut:output = new output();//strongly typed class
_amf.destination = "dummyDestination";
_amf.endpoint = "http://insight2.ultralysis.com/Amfhp/Amfphp/"; //amfphp home directory
_amf.source = "manager1"; //the php class which will be called
_amf.addEventListener(ResultEvent.Result, handleResult);
_amf.init(params,arrayOut);
}
private function handleResult(event:ResultEvent):void
{
datagrid.dataProvider = event.result.grid;
}
And there is also a class named output in my application:
package org.test{
public class output
{
public var grid:Array;
public var week:Array;
}
}
I'm using this to pass value to flex remoteobject using amfphp.
Actually, it's fairly easy to figure out.
You can use the Network Monitor that is part of Flash Builder. It shows the Request Time and the Response Time, so you can get a pretty good idea if the issue is with the PHP side or the Flex side. You can also see the size of the response.
Be aware that Remote Objects mixed with Multidimentional arrays can be larger than you think, but again the Network Monitor will help you figure out that.