Skip to content

Commit f9719fc

Browse files
committed
✨ +class Query (WIP)
1 parent 594a841 commit f9719fc

File tree

5 files changed

+278
-201
lines changed

5 files changed

+278
-201
lines changed

src/Psr7/Query.php

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
<?php
2+
/**
3+
* Class Query
4+
*
5+
* @created 27.03.2021
6+
* @author smiley <smiley@chillerlan.net>
7+
* @copyright 2021 smiley
8+
* @license MIT
9+
*/
10+
11+
namespace chillerlan\HTTP\Psr7;
12+
13+
use function array_combine;
14+
use function array_keys;
15+
use function array_merge;
16+
use function array_values;
17+
use function explode;
18+
use function implode;
19+
use function is_array;
20+
use function parse_str;
21+
use function parse_url;
22+
use function sort;
23+
use function uksort;
24+
use const PHP_URL_QUERY;
25+
use const SORT_STRING;
26+
27+
/**
28+
*
29+
*/
30+
class Query{
31+
32+
public const BOOLEANS_AS_BOOL = 0;
33+
public const BOOLEANS_AS_INT = 1;
34+
public const BOOLEANS_AS_STRING = 2;
35+
public const BOOLEANS_AS_INT_STRING = 3;
36+
37+
/**
38+
* @param iterable $params
39+
* @param int|null $bool_cast converts booleans to a type determined like following:
40+
* BOOLEANS_AS_BOOL : unchanged boolean value (default)
41+
* BOOLEANS_AS_INT : integer values 0 or 1
42+
* BOOLEANS_AS_STRING : "true"/"false" strings
43+
* BOOLEANS_AS_INT_STRING: "0"/"1"
44+
*
45+
* @param bool|null $remove_empty remove empty and NULL values
46+
*
47+
* @return array
48+
*/
49+
public static function cleanParams(iterable $params, int $bool_cast = null, bool $remove_empty = null):array{
50+
$p = [];
51+
$bool_cast = $bool_cast ?? self::BOOLEANS_AS_BOOL;
52+
$remove_empty = $remove_empty ?? true;
53+
54+
foreach($params as $key => $value){
55+
56+
if(is_bool($value)){
57+
58+
if($bool_cast === self::BOOLEANS_AS_BOOL){
59+
$p[$key] = $value;
60+
}
61+
elseif($bool_cast === self::BOOLEANS_AS_INT){
62+
$p[$key] = (int)$value;
63+
}
64+
elseif($bool_cast === self::BOOLEANS_AS_STRING){
65+
$p[$key] = $value ? 'true' : 'false';
66+
}
67+
elseif($bool_cast === self::BOOLEANS_AS_INT_STRING){
68+
$p[$key] = (string)(int)$value;
69+
}
70+
71+
}
72+
elseif(is_iterable($value)){
73+
$p[$key] = call_user_func_array(__METHOD__, [$value, $bool_cast, $remove_empty]);
74+
}
75+
elseif($remove_empty === true && ($value === null || (!is_numeric($value) && empty($value)))){
76+
continue;
77+
}
78+
else{
79+
$p[$key] = $value;
80+
}
81+
}
82+
83+
return $p;
84+
}
85+
86+
/**
87+
* from https://github.com/abraham/twitteroauth/blob/master/src/Util.php
88+
*/
89+
public static function build(array $params, bool $urlencode = null, string $delimiter = null, string $enclosure = null):string{
90+
91+
if(empty($params)){
92+
return '';
93+
}
94+
95+
// urlencode both keys and values
96+
if($urlencode ?? true){
97+
$params = array_combine(
98+
r_rawurlencode(array_keys($params)),
99+
r_rawurlencode(array_values($params))
100+
);
101+
}
102+
103+
// Parameters are sorted by name, using lexicographical byte value ordering.
104+
// Ref: Spec: 9.1.1 (1)
105+
uksort($params, 'strcmp');
106+
107+
$pairs = [];
108+
$enclosure = $enclosure ?? '';
109+
110+
foreach($params as $parameter => $value){
111+
112+
if(is_array($value)){
113+
// If two or more parameters share the same name, they are sorted by their value
114+
// Ref: Spec: 9.1.1 (1)
115+
// June 12th, 2010 - changed to sort because of issue 164 by hidetaka
116+
sort($value, SORT_STRING);
117+
118+
foreach($value as $duplicateValue){
119+
$pairs[] = $parameter.'='.$enclosure.$duplicateValue.$enclosure;
120+
}
121+
122+
}
123+
else{
124+
$pairs[] = $parameter.'='.$enclosure.$value.$enclosure;
125+
}
126+
127+
}
128+
129+
// For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
130+
// Each name-value pair is separated by an '&' character (ASCII code 38)
131+
return implode($delimiter ?? '&', $pairs);
132+
}
133+
134+
/**
135+
* merges additional query parameters into an existing query string
136+
*
137+
* @param string $uri
138+
* @param array $query
139+
*
140+
* @return string
141+
*/
142+
public static function merge(string $uri, array $query):string{
143+
$parsedquery = self::parse(parse_url($uri, PHP_URL_QUERY) ?: '');
144+
$requestURI = explode('?', $uri)[0];
145+
$params = array_merge($parsedquery, $query);
146+
147+
if(!empty($params)){
148+
$requestURI .= '?'.Query::build($params);
149+
}
150+
151+
return $requestURI;
152+
}
153+
154+
/**
155+
* @todo placeholder/WIP
156+
*/
157+
public static function parse(string $querystring):array{
158+
parse_str($querystring, $parsedquery);
159+
160+
return $parsedquery;
161+
}
162+
163+
}

src/Psr7/message_helpers.php

Lines changed: 4 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,10 @@
1111
use InvalidArgumentException, TypeError;
1212
use Psr\Http\Message\{MessageInterface, RequestInterface, ResponseInterface, UploadedFileInterface, UriInterface};
1313

14-
use function array_combine, array_filter, array_keys, array_map, array_merge, array_values, call_user_func_array, count, explode,
15-
gzdecode, gzinflate, gzuncompress, implode, is_array, is_bool, is_iterable, is_numeric, is_scalar, is_string,
16-
json_decode, json_encode, parse_str, parse_url, rawurldecode, rawurlencode, simplexml_load_string, sort, strtolower, trim,
17-
ucfirst, uksort;
18-
19-
use const PHP_URL_QUERY, SORT_STRING;
14+
use function array_filter, array_keys, array_map, array_values, count, explode,
15+
gzdecode, gzinflate, gzuncompress, implode, is_array, is_numeric, is_scalar, is_string,
16+
json_decode, json_encode, rawurldecode, rawurlencode, simplexml_load_string, strtolower, trim,
17+
ucfirst;
2018

2119
const PSR7_INCLUDES = true;
2220

@@ -215,129 +213,6 @@ function r_rawurlencode($data){
215213
return rawurlencode((string)$data);
216214
}
217215

218-
/**
219-
* from https://github.com/abraham/twitteroauth/blob/master/src/Util.php
220-
*/
221-
function build_http_query(array $params, bool $urlencode = null, string $delimiter = null, string $enclosure = null):string{
222-
223-
if(empty($params)){
224-
return '';
225-
}
226-
227-
// urlencode both keys and values
228-
if($urlencode ?? true){
229-
$params = array_combine(
230-
r_rawurlencode(array_keys($params)),
231-
r_rawurlencode(array_values($params))
232-
);
233-
}
234-
235-
// Parameters are sorted by name, using lexicographical byte value ordering.
236-
// Ref: Spec: 9.1.1 (1)
237-
uksort($params, 'strcmp');
238-
239-
$pairs = [];
240-
$enclosure = $enclosure ?? '';
241-
242-
foreach($params as $parameter => $value){
243-
244-
if(is_array($value)){
245-
// If two or more parameters share the same name, they are sorted by their value
246-
// Ref: Spec: 9.1.1 (1)
247-
// June 12th, 2010 - changed to sort because of issue 164 by hidetaka
248-
sort($value, SORT_STRING);
249-
250-
foreach($value as $duplicateValue){
251-
$pairs[] = $parameter.'='.$enclosure.$duplicateValue.$enclosure;
252-
}
253-
254-
}
255-
else{
256-
$pairs[] = $parameter.'='.$enclosure.$value.$enclosure;
257-
}
258-
259-
}
260-
261-
// For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
262-
// Each name-value pair is separated by an '&' character (ASCII code 38)
263-
return implode($delimiter ?? '&', $pairs);
264-
}
265-
266-
const BOOLEANS_AS_BOOL = 0;
267-
const BOOLEANS_AS_INT = 1;
268-
const BOOLEANS_AS_STRING = 2;
269-
const BOOLEANS_AS_INT_STRING = 3;
270-
271-
/**
272-
* @param iterable $params
273-
* @param int|null $bool_cast converts booleans to a type determined like following:
274-
* BOOLEANS_AS_BOOL : unchanged boolean value (default)
275-
* BOOLEANS_AS_INT : integer values 0 or 1
276-
* BOOLEANS_AS_STRING : "true"/"false" strings
277-
* BOOLEANS_AS_INT_STRING: "0"/"1"
278-
*
279-
* @param bool|null $remove_empty remove empty and NULL values
280-
*
281-
* @return array
282-
*/
283-
function clean_query_params(iterable $params, int $bool_cast = null, bool $remove_empty = null):array{
284-
$p = [];
285-
$bool_cast = $bool_cast ?? BOOLEANS_AS_BOOL;
286-
$remove_empty = $remove_empty ?? true;
287-
288-
foreach($params as $key => $value){
289-
290-
if(is_bool($value)){
291-
292-
if($bool_cast === BOOLEANS_AS_BOOL){
293-
$p[$key] = $value;
294-
}
295-
elseif($bool_cast === BOOLEANS_AS_INT){
296-
$p[$key] = (int)$value;
297-
}
298-
elseif($bool_cast === BOOLEANS_AS_STRING){
299-
$p[$key] = $value ? 'true' : 'false';
300-
}
301-
elseif($bool_cast === BOOLEANS_AS_INT_STRING){
302-
$p[$key] = (string)(int)$value;
303-
}
304-
305-
}
306-
elseif(is_iterable($value)){
307-
$p[$key] = call_user_func_array(__FUNCTION__, [$value, $bool_cast, $remove_empty]);
308-
}
309-
elseif($remove_empty === true && ($value === null || (!is_numeric($value) && empty($value)))){
310-
continue;
311-
}
312-
else{
313-
$p[$key] = $value;
314-
}
315-
}
316-
317-
return $p;
318-
}
319-
320-
/**
321-
* merges additional query parameters into an existing query string
322-
*
323-
* @param string $uri
324-
* @param array $query
325-
*
326-
* @return string
327-
*/
328-
function merge_query(string $uri, array $query):string{
329-
parse_str(parse_url($uri, PHP_URL_QUERY), $parsedquery);
330-
331-
$requestURI = explode('?', $uri)[0];
332-
$params = array_merge($parsedquery, $query);
333-
334-
if(!empty($params)){
335-
$requestURI .= '?'.build_http_query($params);
336-
}
337-
338-
return $requestURI;
339-
}
340-
341216
/**
342217
* Return an UploadedFile instance array.
343218
*

tests/CurlUtils/CurlMultiClientTest.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@
1212

1313
use chillerlan\HTTP\CurlUtils\{CurlMultiClient, MultiResponseHandlerInterface};
1414
use chillerlan\HTTP\HTTPOptions;
15-
use chillerlan\HTTP\Psr7\Request;
15+
use chillerlan\HTTP\Psr7\{Request, Query};
1616
use PHPUnit\Framework\TestCase;
1717
use Psr\Http\Client\ClientExceptionInterface;
1818
use Psr\Http\Message\{RequestInterface, ResponseInterface};
1919

20-
use function chillerlan\HTTP\Psr7\build_http_query;
2120
use function array_column, defined, implode, in_array, ksort;
2221

2322
/**
@@ -53,7 +52,7 @@ protected function getRequests():array{
5352
foreach(['de', 'en', 'es', 'fr', 'zh'] as $lang){
5453
$requests[] = new Request(
5554
Request::METHOD_GET,
56-
'https://api.guildwars2.com/v2/items?'.build_http_query(['lang' => $lang, 'ids' => implode(',', $chunk)])
55+
'https://api.guildwars2.com/v2/items?'.Query::build(['lang' => $lang, 'ids' => implode(',', $chunk)])
5756
);
5857
}
5958
}
@@ -98,8 +97,6 @@ public function testMultiRequest():void{
9897

9998
if(defined('TEST_IS_CI') && TEST_IS_CI === true){
10099
$this->markTestSkipped('i have no idea why the headers are empty on travis');
101-
102-
return;
103100
}
104101

105102
$requests = $this->getRequests();

0 commit comments

Comments
 (0)