I am using this PHP library https://github.com/web3p/web3.php to make the requests to smart contracts on BSC.
$web3 = new Web3('https://bsc-dataseed.binance.org');
$contract = new Contract($web3->provider, $abi);
$contract->at('0x10ED43C718714eb63d5aA57B78B54704E256024E')->call('WETH', function($err, $result) {
print_r($result);
});
Works perfectly but the problem is when I try to call a function that has parameters both uint256 and address[] . For example
And here's the code:
$contract->at('0x10ED43C718714eb63d5aA57B78B54704E256024E')->call('quote', [
'25000000000000000000',
'[0x8C851d1a123Ff703BD1f9dabe631b69902Df5f97, 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56]',
], function($err, $result) {
print_r($result);
});
I get the following error. Tried to send the parameters as dictionary with param name. Couldn't figure out how should be done.
InvalidArgumentException
Please make sure you have put all function params and callback.
Your snippet tries to encode the second param as an array but you're passing a string.
The number of $params is dynamic in the PHP code, don't wrap them in an array.
$contract->at('0x10ED43C718714eb63d5aA57B78B54704E256024E')->call(
// function name
'getAmountsOut',
// note the removed array wrapper
// first param
'25000000000000000000',
// second param
[
'0x8C851d1a123Ff703BD1f9dabe631b69902Df5f97',
'0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56'
],
// callback
function($err, $result) {
print_r($result);
}
);
Related
I wonder how to use sequence in HTTP::fake call back.
What I want is to get a sequence of responses when the body of my request contains ListSupplierRoutes.
here is my code:
Http::fake(function (Request $request) {
$body = $request->body();
$xmlFileName = 'login';
if (Str::contains($body, 'Login')) {
$xmlFileName = 'login';
}
if (Str::contains($body, 'ListSupplierRoutes')) {
return Http::sequence()
->push($this->loadXMLResponse('list-supplier-routes-ryanair'))
->push($this->loadXMLResponse('list-supplier-routes-ezy'));
}
// Some other conditions
return Http::response($this->loadXMLResponse($xmlFileName));
});
With this approach I get the below exception:
BadMethodCallException : Method Illuminate\Http\Client\ResponseSequence::then does not exist.
/..../vendor/laravel/framework/src/Illuminate/Macroable/Traits/Macroable.php:103
.../vendor/laravel/framework/src/Illuminate/Http/Client/PendingRequest.php:730
.../vendor/laravel/framework/src/Illuminate/Http/Client/PendingRequest.php:707
.../vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php:64
.../vendor/guzzlehttp/guzzle/src/Middleware.php:37
.../vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php:71
.../vendor/guzzlehttp/guzzle/src/Middleware.php:61
.../vendor/guzzlehttp/guzzle/src/HandlerStack.php:75
.../vendor/guzzlehttp/guzzle/src/Client.php:331
.../vendor/guzzlehttp/guzzle/src/Client.php:168
.../vendor/guzzlehttp/guzzle/src/Client.php:187
.../vendor/laravel/framework/src/Illuminate/Http/Client/PendingRequest.php:609
.../vendor/laravel/framework/src/Illuminate/Support/helpers.php:234
.../vendor/laravel/framework/src/Illuminate/Http/Client/PendingRequest.php:624
.../vendor/laravel/framework/src/Illuminate/Http/Client/PendingRequest.php:528
Make sure your $this->loadXMLResponse() is returning either a string or an array. Also, the Http::fake() requires that you pass an associative array of url mapping to Http::resonse() type or Http::sequence().
For instance
Http::fake(['http://stackoverflow.com' => Http::sequence()->push('OK', 200)->push('Bad Request', 400)])
Disclaimer: This is my first time working with ReactPHP and "php promises", so the solution might just be staring me in the face 🙄
I'm currently working on a little project where I need to create a Slack bot. I decided to use the Botman package and utilize it's Slack RTM driver. This driver utilizes ReactPHP's promises to communicate with the RTM API.
My problem:
When I make the bot reply on a command, I want to get the get retrieve the response from RTM API, so I can cache the ID of the posted message.
Problem is that, the response is being returned inside one of these ReactPHP\Promise\Promise but I simply can't figure out how to retrieve the data.
What I'm doing:
So when a command is triggered, the bot sends a reply Slack:
$response = $bot->reply($response)->then(function (Payload $item) {
return $this->reply = $item;
});
But then $response consists of an (empty?) ReactPHP\Promise\Promise:
React\Promise\Promise^ {#887
-canceller: null
-result: null
-handlers: []
-progressHandlers: & []
-requiredCancelRequests: 0
-cancelRequests: 0
}
I've also tried using done() instead of then(), which is what (as far as I can understand) the official ReactPHP docs suggest you should use to retrieve data from a promise:
$response = $bot->reply($response)->done(function (Payload $item) {
return $this->reply = $item;
});
But then $response returns as null.
The funny thing is, during debugging, I tried to do a var_dump($item) inside the then() but had forgot to remove a non-existing method on the promise. But then the var_dump actually returned the data 🤯
$response = $bot->reply($response)->then(function (Payload $item) {
var_dump($item);
return $this->reply = $item;
})->resolve();
So from what I can fathom, it's like I somehow need to "execute" the promise again, even though it has been resolved before being returned.
Inside the Bot's reply method, this is what's going on and how the ReactPHP promise is being generated:
public function apiCall($method, array $args = [], $multipart = false, $callDeferred = true)
{
// create the request url
$requestUrl = self::BASE_URL . $method;
// set the api token
$args['token'] = $this->token;
// send a post request with all arguments
$requestType = $multipart ? 'multipart' : 'form_params';
$requestData = $multipart ? $this->convertToMultipartArray($args) : $args;
$promise = $this->httpClient->postAsync($requestUrl, [
$requestType => $requestData,
]);
// Add requests to the event loop to be handled at a later date.
if ($callDeferred) {
$this->loop->futureTick(function () use ($promise) {
$promise->wait();
});
} else {
$promise->wait();
}
// When the response has arrived, parse it and resolve. Note that our
// promises aren't pretty; Guzzle promises are not compatible with React
// promises, so the only Guzzle promises ever used die in here and it is
// React from here on out.
$deferred = new Deferred();
$promise->then(function (ResponseInterface $response) use ($deferred) {
// get the response as a json object
$payload = Payload::fromJson((string) $response->getBody());
// check if there was an error
if (isset($payload['ok']) && $payload['ok'] === true) {
$deferred->resolve($payload);
} else {
// make a nice-looking error message and throw an exception
$niceMessage = ucfirst(str_replace('_', ' ', $payload['error']));
$deferred->reject(new ApiException($niceMessage));
}
});
return $deferred->promise();
}
You can see the full source of it here.
Please just point me in some kind of direction. I feel like I tried everything, but obviously I'm missing something or doing something wrong.
ReactPHP core team member here. There are a few options and things going on here.
First off then will never return the value from a promise, it will return a new promise so you can create a promise chain. As a result of that you do a new async operation in each then that takes in the result from the previous one.
Secondly done never returns result value and works pretty much like then but will throw any uncaught exceptions from the previous promise in the chain.
The thing with both then and done is that they are your resolution methods. A promise a merely represents the result of an operation that isn't done yet. It will call the callable you hand to then/done once the operation is ready and resolves the promise. So ultimately all your operations happen inside a callable one way or the other and in the broadest sense. (Which can also be a __invoke method on a class depending on how you set it up. And also why I'm so excited about short closures coming in PHP 7.4.)
You have two options here:
Run all your operations inside callable's
Use RecoilPHP
The former means a lot more mind mapping and learning how async works and how to wrap your mind around that. The latter makes it easier but requires you to run each path in a coroutine (callable with some cool magic).
I am passing a POST request with 3 variables
Id (Randomly Generated),
Name (Specified)
Capacity (Specified)
from an Angular Service post. These are in the payload of the POST, and also visible in $request variable in the Laravel resource controller method "store()".
public function store(Request $request)
{
$servers = new Server();
return $request->getContent();
}
Here in Chrome's developer tool>network>POST request>on preview I get this
[{name: "bakar", capacity: 50, id: 8012}]
0: {name: "bakar", capacity: 50, id: 8012}
but when I use
public function store(Request $request)
{
$servers = new Server();
$data = $request->getContent();
$servers->id = $data->id;
$servers->name = $data->name;
$servers->capacity = $data->capacity;
$servers->save();
}
In the above method I got an error exception stating:
" Trying to get property of non-object "
How can I solve this?
Based on your JSON sample, $data should contain an array, which then contains a single object at its first index.
Therefore you cannot do e.g. $data->id because that's assuming that $data has a property called $id...it doesn't, the object at its first index does.
So simply $data[0]->id would allow you to access that index, and then access the $id property of the object at that index. Of course if your request contained multiple items in the array, you might need to use a loop to go through them all and get the values. It depends what you're expecting and what you intended to do with it.
Or, it may be the case that your PHP is correct, and it's your client which is sending the data in the wrong format. It's not clear what the desired outcome actually is.
Edit:
Since it appears that $data is still a JSON string when it arrives in your store() function, you need to decode it. So first write
$data = json_decode($request->getContent());
(instead of $data = $request->getContent();) and then proceed as above.
Complete sample:
public function store(Request $request)
{
$servers = new Server();
$data = json_decode($request->getContent());
$servers->id = $data[0]->id;
$servers->name = $data[0]->name;
$servers->capacity = $data[0]->capacity;
$servers->save();
}
Before I start, I want to let you know I'm really a noob in PHP and this is the first API I'm making.
It works pretty good if I want to echo one array of information (for example food details), but when I try to do the same with multiple items it returns empty.
I've checked the variable values in debug. It's fine in debug and I see an array which contains multiple sub arrays.
My code
$app->get('/allfoods', 'authenticate', function () use ($app) {
global $user_id;
$db = new FoodHandler();
// In here i get foods with their details via mysql
$result = $db->GetAllFoods();
$response = array();
$response["error"] = false;
$response["foods"] = array();
// looping through result and preparing food array
while ($row = $result->fetch_assoc()) {
$tmp = array();
$tmp['food_id'] = $row['food_id'];
$tmp['food_name'] = $row['food_name'];
$tmp['food_desc'] = $row['food_desc'];
$tmp['food_category'] = $row['food_category'];
$tmp['food_creationDate'] = $row['food_creationDate'];
array_push($response["foods"], $tmp);
}
echoRespnse(200, $response);});
My output function (which works great if there is no array in my array)
function echoRespnse($status_code, $response) {
$app = \Slim\Slim::getInstance();
// Http response code
$app->status($status_code);
// setting response content type to json
$app->contentType('application/json');
echo json_encode($response);
}
$app->run();?>
What is my setup?
Localhost wamp with php 7.2.4
Apache 2.4.33
Mysql 5.7.21
I'm also using Postman to send my request (I also tried it in C#, both give back empty content)
I see several issues with your code. First, there is a problem with your route definition. When defining a route, you should pass two arguments to the get method: a pattern (a string,/allfoods in your case) and an instance of Clousure (a callable, your route callback, the anonymous function in your case.) More details in official docs.
So, first thing is to remove the authenticate string from method parameters and change your route definition to this:
$app->get('/allfoods', function ($request, $response, $args) {
// Body of the function goes here
});
Please note I also removed the use ($app) as you have access to application instance uising $this keyword, so no need for that (described in official docs as well).
Second thing is about generating the response. When using Slim framework it is always a good idea to return the $response object instead of echoing response (read more in official docs). Thisgives you some advantages, for example the helper method whitJson helps you whit generating JSON output.
To refine your whole code in a more Slim-ish way:
$app->get('/allfoods', function ($request, $response, $args) {
global $user_id;
$db = new FoodHandler();
// In here i get foods with their details via mysql
$result = $db->GetAllFoods();
$data= array();
$data["error"] = false;
$data["foods"] = array();
// looping through result and preparing food array
while ($row = $result->fetch_assoc()) {
$tmp = array();
$tmp['food_id'] = $row['food_id'];
$tmp['food_name'] = $row['food_name'];
$tmp['food_desc'] = $row['food_desc'];
$tmp['food_category'] = $row['food_category'];
$tmp['food_creationDate'] = $row['food_creationDate'];
array_push($data["foods"], $tmp);
}
// Return JSON data using helper method
return $response->withJson($data);
}
And you won't need the echoResponse function anymore.
I'm using Zurmo and trying to create a new account using REST API. I followed this documentation precisely: http://zurmo.org/wiki/rest-api-specification-accounts to pass the required parameters as json array.
This is my php code:
public function actionCreateOrUpdate()
{
$params=$_POST;
$modelClassName=$this->getModelName();
foreach ($params as $param)
{
if (!isset($param))
{
$message = Zurmo::t('ZurmoModule', 'Please provide data.');
throw new ApiException($message);
}
$r=$this->GetParam($param);
$res= array('status' => 'SUCCESS', 'data' => array($r));
print_r(json_encode($res,true));
}
}
function GetParam ($param){
$modelClassName=$this->getModelName();
if (isset($param['mobile_id'] ) && !$param['mobile_id']=='' &&!$param['mobile_id']==null)
{ $id=$param['mobile_id'];
$params=array();
foreach ($param as $k => $v) {
if(!($k=='mobile_id')) {
$params[$k] = $v;}
}
if ($params=null){$message = Zurmo::t('ZurmoModule', 'Please provide data.');
throw new ApiException($message);}
$tableName = $modelClassName::getTableName();
$beans = ZurmoRedBean::find($tableName, "mobile_id = '$id'");
if (count($beans) > 0)
{
$result = $this->processUpdate($id, $params);
}else{
$result = $this->processCreate($params,$id);
}
}
return $result;
}
The problem is that the $_POST method is returning an empty array. While debugging I tried to use print_r($_POST) and it also returned an empty array. I also tried to pass parameters as plain text and got the same result. I tried $_GET method and it worked. I think the problem is in the $_POST method, maybe I need to change something in my .php files. Any ideas please?
You should first hit the api with static data, to check if it works fine, then try to integrate php within that static data. You will need to read the documentation for which action accepts which format, and which method is supported(GET OR POST). Then try die(); , before sending if the array formed is as per the documentation.
I had similar issue when creating Account using REST API from java client. The problem was I did not send the proper POST request.
Another symptom also was on server side print_r(file_get_contents("php://input"),true); php code returned the correct request data.
Specifically the root cause was:
The Content-Type HTTP header was not "application/x-www-form-urlencoded"
The value field value in POST request was not properly encoded ( I used java.net.URLEncoder.encode method to overcome this)
After fixing these it worked.