Passed
Push — main ( b6169a...2d2e59 )
by smiley
10:24
created

Query::cleanParams()   C

Complexity

Conditions 13
Paths 10

Size

Total Lines 35
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 13
eloc 20
c 1
b 0
f 0
nc 10
nop 3
dl 0
loc 35
rs 6.6166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Class Query
4
 *
5
 * @created      27.03.2021
6
 * @author       smiley <[email protected]>
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)),
0 ignored issues
show
Bug introduced by
It seems like r_rawurlencode(array_keys($params)) can also be of type string; however, parameter $keys of array_combine() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

98
				/** @scrutinizer ignore-type */ r_rawurlencode(array_keys($params)),
Loading history...
99
				r_rawurlencode(array_values($params))
0 ignored issues
show
Bug introduced by
It seems like r_rawurlencode(array_values($params)) can also be of type string; however, parameter $values of array_combine() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

99
				/** @scrutinizer ignore-type */ r_rawurlencode(array_values($params))
Loading history...
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
}
164