Passed
Push — dev ( d2f61c...886cc9 )
by Marcin
09:09
created

Validator   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 187
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 10
Bugs 0 Features 0
Metric Value
eloc 35
c 10
b 0
f 0
dl 0
loc 187
rs 10
ccs 45
cts 45
cp 1
wmc 20

11 Methods

Rating   Name   Duplication   Size   Complexity  
A assertInstanceOf() 0 5 2
A assertOkHttpCode() 0 4 1
A assertErrorHttpCode() 0 5 1
A assertIsArray() 0 3 1
A assertIsType() 0 6 2
A assertIsString() 0 3 1
A assertArrayHasNoMixedKeys() 0 15 5
A assertIsIntRange() 0 12 4
A assertIsBool() 0 3 1
A assertIsObject() 0 3 1
A assertIsInt() 0 3 1
1
<?php
2
declare(strict_types=1);
3
4
namespace MarcinOrlowski\ResponseBuilder;
5
6
use MarcinOrlowski\ResponseBuilder\Exceptions as Ex;
7
use MarcinOrlowski\ResponseBuilder\ResponseBuilder as RB;
8
9
/**
10
 * Laravel API Response Builder
11
 *
12
 * @package   MarcinOrlowski\ResponseBuilder
13
 *
14
 * @author    Marcin Orlowski <mail (#) marcinOrlowski (.) com>
15
 * @copyright 2016-2020 Marcin Orlowski
16
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
17
 * @link      https://github.com/MarcinOrlowski/laravel-api-response-builder
18
 */
19
class Validator
20
{
21
	/**
22
	 * Checks if given $val is of type boolean
23
	 *
24
	 * @param string $var_name Name of the key to be used if exception is thrown.
25
	 * @param mixed  $value    Variable to be asserted.
26
	 *
27
	 * @return void
28
	 *
29
	 * @throws \InvalidArgumentException
30
	 */
31
	public static function assertIsBool(string $var_name, $value): void
32
	{
33
		self::assertIsType($var_name, $value, [Type::BOOLEAN], Ex\NotBooleanException::class);
34
	}
35
36
	/**
37
	 * Checks if given $val is of type integer
38
	 *
39
	 * @param string $var_name Name of the key to be used if exception is thrown.
40
	 * @param mixed  $value    Variable to be asserted.
41
	 *
42
	 * @return void
43
	 *
44
	 * @throws \InvalidArgumentException
45
	 */
46
	public static function assertIsInt(string $var_name, $value): void
47
	{
48
		self::assertIsType($var_name, $value, [Type::INTEGER], Ex\NotBooleanException::class);
49 2
	}
50
51 2
	/**
52 1
	 * Checks if given $val is of type array
53
	 *
54
	 * @param string $var_name Name of the key to be used if exception is thrown.
55
	 * @param mixed  $value    Variable to be asserted.
56
	 *
57
	 * @return void
58
	 *
59
	 * @throws \InvalidArgumentException
60
	 */
61
	public static function assertIsArray(string $var_name, $value): void
62
	{
63
		self::assertIsType($var_name, $value, [Type::ARRAY], Ex\NotArrayException::class);
64 97
	}
65
66 97
	/**
67 97
	 * Checks if given $val is an object
68
	 *
69
	 * @param string $var_name Name of the key to be used if exception is thrown.
70
	 * @param mixed  $value    Variable to be asserted.
71
	 *
72
	 * @return void
73
	 *
74
	 * @throws \InvalidArgumentException
75
	 */
76
	public static function assertIsObject(string $var_name, $value): void
77
	{
78
		self::assertIsType($var_name, $value, [Type::OBJECT], Ex\NotObjectException::class);
79 2
	}
80
81 2
	/**
82 1
	 * Checks if given $val is of type string
83
	 *
84
	 * @param string $var_name Label or name of the variable to be used in exception message (if thrown).
85
	 * @param mixed  $value    Variable to be asserted.
86
	 *
87
	 * @return void
88
	 *
89
	 * @throws \InvalidArgumentException
90
	 */
91
	public static function assertIsString(string $var_name, $value): void
92
	{
93
		self::assertIsType($var_name, $value, [Type::STRING], Ex\NotStringException::class);
94 14
	}
95
96 14
	/**
97 13
	 * @param string $var_name Label or name of the variable to be used in exception message (if thrown).
98
	 * @param mixed  $value    Variable to be asserted.
99
	 * @param int    $min      Min allowed value (inclusive)
100
	 * @param int    $max      Max allowed value (inclusive)
101
	 *
102
	 * @return void
103
	 *
104
	 * @throws \InvalidArgumentException
105
	 * @throws \RuntimeException
106
	 */
107
	public static function assertIsIntRange(string $var_name, $value, int $min, int $max): void
108
	{
109 13
		self::assertIsInt($var_name, $value);
110
111 13
		if ($min > $max) {
112 10
			throw new \InvalidArgumentException(
113
				\sprintf('%s: Invalid range for "%s". Ensure bound values are not swapped.', __FUNCTION__, $var_name));
114
		}
115
116
		if (($min > $value) || ($value > $max)) {
117
			throw new \OutOfBoundsException(
118
				\sprintf('Value of "%s" (%d) is out of bounds. Must be between %d-%d inclusive.', $var_name, $value, $min, $max));
119
		}
120
	}
121
122
	/**
123
	 * Checks if $item (of name $key) is of type that is include in $allowed_types.
124
	 *
125 97
	 * @param string $var_name      Label or name of the variable to be used in exception message (if thrown).
126
	 * @param mixed  $value         Variable to be asserted.
127 97
	 * @param array  $allowed_types Array of allowed types for $value, i.e. [Type::INTEGER]
128
	 * @param string $ex_class      Name of exception class to thrown when assertion failed.
129 97
	 *
130 1
	 * @return void
131 1
	 *
132
	 * @throws \InvalidArgumentException
133
	 */
134 97
	public static function assertIsType(string $var_name, $value, array $allowed_types,
135 4
	                                    string $ex_class = Ex\InvalidTypeException::class): void
136 4
	{
137
		$type = \gettype($value);
138 97
		if (!\in_array($type, $allowed_types, true)) {
139
			throw new $ex_class($var_name, $type, $allowed_types);
140
		}
141
	}
142
143
	/**
144
	 * Ensures given $http_code is valid code for error response.
145
	 *
146
	 * @param int $http_code
147
	 */
148
	public static function assertErrorHttpCode(int $http_code): void
149
	{
150
		self::assertIsInt('http_code', $http_code);
151 97
		self::assertIsIntRange('http_code', $http_code,
152
			RB::ERROR_HTTP_CODE_MIN, RB::ERROR_HTTP_CODE_MAX);
153 97
	}
154 97
155 12
	/**
156 12
	 * Ensures given $http_code is valid for response indicating sucessful operation.
157 12
	 *
158
	 * @param int $http_code
159
	 */
160 97
	public static function assertOkHttpCode(int $http_code): void
161
	{
162
		self::assertIsInt('http_code', $http_code);
163
		self::assertIsIntRange('http_code', $http_code, 200, 299);
164
	}
165
166
	/**
167 10
	 * Ensures $obj (that is value coming from variable, which name is passed in $label) is instance of $cls class.
168
	 *
169 10
	 * @param string $var_name Name of variable that the $obj value is coming from. Used for exception message.
170 10
	 * @param object $obj      Object to check instance of
171 10
	 * @param string $cls      Target class we want to check $obj agains.
172 10
	 */
173
	public static function assertInstanceOf(string $var_name, object $obj, string $cls): void
174
	{
175
		if (!($obj instanceof $cls)) {
176
			throw new \InvalidArgumentException(
177
				\sprintf('"%s" must be instance of "%s".', $var_name, $cls)
178
			);
179 9
		}
180
	}
181 9
182 9
	/**
183 9
	 * Ensure that we either have array with user provided keys i.e. ['foo'=>'bar'], which will then
184
	 * be turned into JSON object or array without user specified keys (['bar']) which we would return as JSON
185
	 * array. But you can't mix these two as the final JSON would not produce predictable results.
186
	 *
187
	 * @param array $data
188
	 *
189
	 * @throws Ex\ArrayWithMixedKeysException
190
	 */
191
	public static function assertArrayHasNoMixedKeys(array $data): void
192 4
	{
193
		$string_keys_cnt = 0;
194 4
		$int_keys_cnt = 0;
195 1
		foreach (\array_keys($data) as $key) {
196 1
			if (\is_int($key)) {
197
				if ($string_keys_cnt > 0) {
198
					throw new Ex\ArrayWithMixedKeysException();
199 3
				}
200
				$int_keys_cnt++;
201
			} else {
202
				if ($int_keys_cnt > 0) {
203
					throw new Ex\ArrayWithMixedKeysException();
204
				}
205
				$string_keys_cnt++;
206
			}
207
		}
208
	}
209
}
210