Multiple duplicate uri parameters in GuzzleHttp - guzzle

I am accessing the Echo Nest API, which requires me to repeat the same uri parameter name bucket. However I can't make this work in Guzzle 6. I read a similar issue from 2012, however the approach does not work.
I have tried adding it manually into the query string without any success.
A sample API call could be:
http://developer.echonest.com/api/v4/song/search?format=json&results=10&api_key=someKey&artist=Silbermond&title=Ja&bucket=id:spotify&bucket=tracks&bucket=audio_summary
Here's my example Client:
/**
* #param array $urlParameters
* #return Client
*/
protected function getClient()
{
return new Client([
'base_uri' => 'http://developer.echonest.com/api/v4/',
'timeout' => 5.0,
'headers' => [
'Accept' => 'application/json',
],
'query' => [
'api_key' => 'someKey',
'format' => 'json',
'results' => '10',
'bucket' => 'id:spotify' // I need multiple bucket parameter values with the 'bucket'-name
]);
}
/**
* #param $artist
* #param $title
* #return stdClass|null
*/
public function searchForArtistAndTitle($artist, $title)
{
$response = $this->getClient()->get(
'song/search?' . $this->generateBucketUriString(),
[
'query' => array_merge($client->getConfig('query'), [
'artist' => $artist,
'title' => $title
])
]
);
// ...
}
Can you help me?

In the Guzzle 6 you are not allowed to pass any aggregate function anymore. Whenever you will pass an array to the query config it will be serialized with the http_build_query function:
if (isset($options['query'])) {
$value = $options['query'];
if (is_array($value)) {
$value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
}
To avoid it you should serialize a query string by your own and pass it as string.
new Client([
'query' => $this->serializeWithDuplicates([
'bucket' => ['id:spotify', 'id:spotify2']
]) // serialize the way to get bucket=id:spotify&bucket=id:spotify2
...
$response = $this->getClient()->get(
...
'query' => $client->getConfig('query').$this->serializeWithDuplicates([
'artist' => $artist,
'title' => $title
])
...
);
Otherwise you could pass into the handler option an adjusted HandlerStack that will have in its stack your Middleware Handler. The one will read some new config param, say, query_with_duplicates, build acceptable Query String and modify Request's Uri with it accordingly.

I had the same need today, but now we are on Guzzle 7, the easiest way of getting duplicates for params (bucket=value1&bucket=value2&bucket=value3...) is to use the Query Build method. For this to work do the following:
// Import the class
use GuzzleHttp\Psr7\Query;
Example params
$params = [
'bucket' => 'value1',
'bucket' => 'value2',
'bucket' => 'value3',
];
Then when passing the params array to the query key, first pass it through the Query::build method
$response = $client->get('/api', [
'query' => Query::build($params),
]);

Related

Argument 1 passed to GuzzleHttp\Client::send() must implement interface

hi I am new to laravel and I am trying to consume the api with laravel 8 I have a problem with my POST and I do not understand
public function storeEntreprise(Request $request){
$request->validate([
'name' => 'required',
'email' => 'required',
'phone_number'=>'required',
'address' => 'required',
'password' => 'required',
'password_confirmation' => 'required'
]);
$client = new Client();
$post = $request->all();
$url = "http://flexy-job.adsyst-solutions.com/api/entreprises-store";
$create = $client->request('POST', $url, [
'headers' => [
'Content-Type' => 'text/html; charset=UTF8',
],
'form-data' => [
'name' => $post['name'],
'email' => $post['email'],
'phone_number' => $post['phone_number'],
'address' => $post['address'],
'logo' => $post['logo'],
'password' => $post['password'],
'password_confirmation' => $post['password_confirmation']
]
]);
//dd($create->getBody());
echo $create->getStatusCode();
//echo $create->getHeader('Content-Type');
echo $create->getBody();
$response = $client->send($create);
return redirect()->back();
}
Can you help me please
You calling (accidentally?) $response = $client->send($create); where $create is response of API request you made ($create = $client->request('POST', $url, ...).
So PHP reports you that you can't pass ResponseInterface where RequestInterface required.
Also, you echo's body of response, and return redirect response at same time. So browser will not show you API response (because of instance back redirect).

How to get the query parameters in a Guzzle/ Psr7 request

I am using Guzzle 6.
I am trying to mock a client and use it like so:
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
$mock_handler = new MockHandler([
new Response(200, ['Content-Type' => 'application/json'], 'foo'),
]);
$history = [];
$history_middleware = Middleware::history($history);
$handler_stack = HandlerStack::create($mock_handler);
$handler_stack->push($history_middleware);
$mock_client = new Client(['handler' => $handler_stack]);
// Use mock client in some way
$mock_client->get("http://example.com", [
'query' => [
'bar' => '10',
'hello' => '20'
],
]);
// ------
// get original request using history
$transaction = $history[0];
/** #var Request $request */
$request = $transaction['request'];
// How can I get the query parameters that was used in the request (i.e. bar)
My question is how can I get the query parameters used in the GuzzleHttp\Psr7\Request class?
The closest I managed to get is the following: $request->getUri()->getQuery(), but this just returns a string like so: bar=10&hello=20.
I seem to have solved my problem.
I can simply do this:
parse_str($request->getUri()->getQuery(), $query);
and I now have an array of the query parameters.
Other solutions are welcome!

Pass Eloquent Model As An Closure Argument In PHP

I'm using Laravel Illuminate/Database outside of laravel application. I'm trying to pass the Eloquent model as my closure argument but its throwing an error. May be I'm passing it wrongly. My code is as following:
// Create a dummy subject (This is working absolutely fine)
SubjectModel::create(array(
'title' => 'Mathematics',
'description' => 'Math Subject',
'slug' => 'math',
'ka_url' => 'http://khanacademy.org/math'
));
$scrapper = new SubjectScrapper();
$scrapper->setUrl('');
This is not working. SubjectModel is not being passed in the following closure
$scrapper->runScrapper(function($subjects) use ($scrapper, SubjectModel $subjectModel) {
if(!empty($subjects))
{
foreach ($subjects as $subject) {
$urlParts = explode('/', $subject['url']);
$slug = end($urlParts);
$subjectModel::create(array(
'title' => $subject['subject_name'],
'slug' => $slug,
'ka_url' => $scrapper->getBaseUrl().$subject['link'],
));
}
}
});
Could anybody please tell me how to accomplish this task.
Try this. No need to pass object in closure
$scrapper = new SubjectScrapper();
$scrapper->setUrl('');
$scrapper->runScrapper(function($subjects) use ($scrapper, $output) {
SubjectModel::create(array(
'title' => 'Math',
'slug' => 'math',
'ka_url' => 'http://math'
));
$output->writeln('<info>Total Subjects Scrapped:: '.count($subjects).'</info>'.PHP_EOL);
});

How to sort by related table field when sending Yii2 REST GET request

I want to expand this question.
Basically I have users endpoint. But I am also returning data from the related profiles table. I am not expanding with profiles, I always want to return it. So I have fields method like this:
public function fields()
{
$fields = parent::fields();
$fields[] = 'profile';
return $fields;
}
When I do GET request and demand sorting by profile.created_at field and user.status, it does not sort by profile.created_at.
GET v1/users?sort=-profile.created_at,status
Can this be achieved somehow ?
This is my current code:
/** #var $query ActiveQuery */
$query = User::find();
// get data from profile table
$query->innerJoinWith('profile');
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => ['defaultOrder' => ['id' => SORT_DESC]],
'pagination' => [
'pageSize' => 10,
],
]);
return $dataProvider;
You have overridden 'sort' parameter of ActiveDataProvider. To keep default behaviour of Sort object and change defaultOrder property, create an instance, such as:
$sort = new \yii\data\Sort([
'attributes' => [
'profile.created_at',
],
'defaultOrder' => ['id' => SORT_DESC],
]);
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => $sort,
'pagination' => [
'pageSize' => 10,
],
]);

Get all parameters after action in Zend?

When I call a router like below in Zend:
coupon/index/search/cat/1/page/1/x/111/y/222
And inside the controller when I get $this->_params, I get an array:
array(
'module' => 'coupon',
'controller' => 'index',
'action' => 'search',
'cat' => '1',
'page' => '1',
'x' => '111',
'y' => '222'
)
But I want to get only:
array(
'cat' => '1',
'page' => '1',
'x' => '111',
'y' => '222'
)
Could you please tell me a way to get the all the params just after the action?
IMHO this is more elegant and includes changes in action, controller and method keys.
$request = $this->getRequest();
$diffArray = array(
$request->getActionKey(),
$request->getControllerKey(),
$request->getModuleKey()
);
$params = array_diff_key(
$request->getUserParams(),
array_flip($diffArray)
);
As far as I know, you will always get the controller, action and module in the params list as it is part of the default. You could do something like this to remove the three from the array you get:
$url_params = $this->getRequest()->getUserParams();
if(isset($url_params['controller']))
unset($url_params['controller']);
if(isset($url_params['action']))
unset($url_params['action']);
if (isset($url_params['module']))
unset($url_params['module']);
Alternatively as you don't want to be doing that every time you need the list, create a helper to do it for you, something like this:
class Helper_Myparams extends Zend_Controller_Action_Helper_Abstract
{
public $params;
public function __construct()
{
$request = Zend_Controller_Front::getInstance()->getRequest();
$this->params = $request->getParams();
}
public function myparams()
{
if(isset($this->params['controller']))
unset($this->params['controller']);
if(isset($this->params['action']))
unset($this->params['action']);
if (isset($this->params['module']))
unset($this->params['module']);
return $this->params;
}
public function direct()
{
return $this->myparams();
}
}
And you can simply call this from your controller to get the list:
$this->_helper->myparams();
So for example using the url:
http://127.0.0.1/testing/urls/cat/1/page/1/x/111/y/222
And the code:
echo "<pre>";
print_r($this->_helper->myparams());
echo "</pre>";
I get the following array printed:
Array
(
[cat] => 1
[page] => 1
[x] => 111
[y] => 222
)
How about this?
In controller:
$params = $this->getRequest()->getParams();
unset($params['module'];
unset($params['controller'];
unset($params['action'];
Pretty clunky; might need some isset() checks to avoid warnings; could jam this segment into its own method or helper. But it would do the job, right?