Passed
Push — php8 ( bd75dc...d8afb4 )
by Fabio
08:15
created

TPropertyValue::ensureHexColor()   F

Complexity

Conditions 21
Paths 1105

Size

Total Lines 40
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
eloc 29
c 0
b 0
f 0
nc 1105
nop 3
dl 0
loc 40
rs 0

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
 * TComponent, TPropertyValue classes
4
 *
5
 * @author Qiang Xue <[email protected]>
6
 *
7
 * Global Events, intra-object events, Class behaviors, expanded behaviors
8
 * @author Brad Anderson <[email protected]>
9
 *
10
 * @link https://github.com/pradosoft/prado
11
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
12
 */
13
14
namespace Prado;
15
16
use Prado\Exceptions\TInvalidDataValueException;
17
use Prado\Web\Javascripts\TJavaScript;
18
19
/**
20
 * TPropertyValue class
21
 *
22
 * TPropertyValue is a utility class that provides static methods
23
 * to convert component property values to specific types.
24
 *
25
 * TPropertyValue is commonly used in component setter methods to ensure
26
 * the new property value is of specific type.
27
 * For example, a boolean-typed property setter method would be as follows,
28
 * <code>
29
 * function setPropertyName($value) {
30
 *     $value=TPropertyValue::ensureBoolean($value);
31
 *     // $value is now of boolean type
32
 * }
33
 * </code>
34
 *
35
 * Properties can be of the following types with specific type conversion rules:
36
 * - string: a boolean value will be converted to 'true' or 'false'.
37
 * - boolean: string 'true' (case-insensitive) will be converted to true,
38
 *            string 'false' (case-insensitive) will be converted to false.
39
 * - integer
40
 * - float
41
 * - array: string starting with '(' and ending with ')' will be considered as
42
 *          as an array expression and will be evaluated. Otherwise, an array
43
 *          with the value to be ensured is returned.
44
 * - object
45
 * - enum: enumerable type, represented by an array of strings.
46
 *
47
 * @author Qiang Xue <[email protected]>
48
 * @since 3.0
49
 */
50
class TPropertyValue
51
{
52
	/**
53
	 * Converts a value to boolean type.
54
	 * Note, string 'true' (case-insensitive) will be converted to true,
55
	 * string 'false' (case-insensitive) will be converted to false.
56
	 * If a string represents a non-zero number, it will be treated as true.
57
	 * @param mixed $value the value to be converted.
58
	 * @return bool
59
	 */
60
	public static function ensureBoolean($value): bool
61
	{
62
		if (is_string($value)) {
63
			return strcasecmp($value, 'true') == 0 || (is_numeric($value) && $value != 0);
64
		} else {
65
			return (bool) $value;
66
		}
67
	}
68
69
	/**
70
	 * Converts a value to string type.
71
	 * Note, a boolean value will be converted to 'true' if it is true
72
	 * and 'false' if it is false.
73
	 * @param mixed $value the value to be converted.
74
	 * @return string
75
	 */
76
	public static function ensureString($value): string
77
	{
78
		if (TJavaScript::isJsLiteral($value)) {
79
			return $value;
80
		}
81
		if (is_bool($value)) {
82
			return $value ? 'true' : 'false';
83
		} else {
84
			return (string) $value;
85
		}
86
	}
87
88
	/**
89
	 * Converts a value to integer type.
90
	 * @param mixed $value the value to be converted.
91
	 * @return int
92
	 */
93
	public static function ensureInteger($value): int
94
	{
95
		return (int) $value;
96
	}
97
98
	/**
99
	 * Converts a value to float type.
100
	 * @param mixed $value the value to be converted.
101
	 * @return float
102
	 */
103
	public static function ensureFloat($value): float
104
	{
105
		return (float) $value;
106
	}
107
108
	/**
109
	 * Converts a value to array type. If the value is a string and it is
110
	 * in the form (a,b,c) then an array consisting of each of the elements
111
	 * will be returned. If the value is a string and it is not in this form
112
	 * then an array consisting of just the string will be returned. If the value
113
	 * is not a string then
114
	 * @param mixed $value the value to be converted.
115
	 * @return array
116
	 */
117
	public static function ensureArray($value): array
118
	{
119
		if (is_string($value)) {
120
			$value = trim($value);
121
			$len = strlen($value);
122
			if ($len >= 2 && $value[0] == '(' && $value[$len - 1] == ')') {
123
				return eval('return array' . $value . ';');
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
124
			} else {
125
				return $len > 0 ? [$value] : [];
126
			}
127
		} else {
128
			return (array) $value;
129
		}
130
	}
131
132
	/**
133
	 * Converts a value to object type.
134
	 * @param mixed $value the value to be converted.
135
	 * @return object
136
	 */
137
	public static function ensureObject($value): object
138
	{
139
		return (object) $value;
140
	}
141
142
	/**
143
	 * Converts a value to enum type.
144
	 *
145
	 * This method checks if the value is of the specified enumerable type.
146
	 * A value is a valid enumerable value if it is equal to the name of a constant
147
	 * in the specified enumerable type (class).
148
	 * For more details about enumerable, see {@link TEnumerable}.
149
	 *
150
	 * For backward compatibility, this method also supports sanity
151
	 * check of a string value to see if it is among the given list of strings.
152
	 * @param mixed $value the value to be converted.
153
	 * @param mixed $enums class name of the enumerable type, or array of valid enumeration values. If this is not an array,
154
	 * the method considers its parameters are of variable length, and the second till the last parameters are enumeration values.
155
	 * @throws TInvalidDataValueException if the original value is not in the string array.
156
	 * @return string the valid enumeration value
157
	 */
158
	public static function ensureEnum($value, $enums): string
159
	{
160
		static $types = [];
161
		if (func_num_args() === 2 && is_string($enums)) {
162
			/*
163
						// check for Php 8.1 enum instances
164
						if($value instanceof $enums) {
165
							return $value;
166
						}
167
						// check for strings; valid for both Php 8.1 enums and Prado's TEnumerable
168
			*/
169
			if (!isset($types[$enums])) {
170
				$types[$enums] = new \ReflectionClass($enums);
171
			}
172
			if ($types[$enums]->hasConstant($value)) {
173
				return $value;
174
			} else {
175
				throw new TInvalidDataValueException(
176
					'propertyvalue_enumvalue_invalid',
177
					$value,
178
					implode(' | ', $types[$enums]->getConstants())
179
				);
180
			}
181
		} elseif (!is_array($enums)) {
182
			$enums = func_get_args();
183
			array_shift($enums);
184
		}
185
		if (in_array($value, $enums, true)) {
186
			return $value;
187
		} else {
188
			throw new TInvalidDataValueException('propertyvalue_enumvalue_invalid', $value, implode(' | ', $enums));
189
		}
190
	}
191
192
	/**
193
	 * Converts the value to 'null' if the given value is empty
194
	 * @param mixed $value value to be converted
195
	 * @return mixed input or NULL if input is empty
196
	 */
197
	public static function ensureNullIfEmpty($value)
198
	{
199
		return empty($value) ? null : $value;
200
	}
201
202
	/**
203
	 * Converts the value to a web "#RRGGBB" hex color.
204
	 * The value[s] could be as an A) Web Color or # Hex Color string, or B) as a color
205
	 * encoded integer, eg 0x00RRGGBB, C) a triple ($value [red], $green, $blue), or D)
206
	 * an array of red, green, and blue, and index 0, 1, 2 or 'red', 'green', 'blue'.
207
	 * In instance (A), $green is treated as a boolean flag for whether to convert
208
	 * any web colors to their # hex color.  When red, green, or blue colors are specified
209
	 * they are assumed be be bound [0...255], inclusive.
210
	 * @param array|int|string $value String Web Color name or Hex Color (eg. '#336699'),
211
	 *   array of [$r, $g, $b] or ['red' => $red, 'green' => $green, 'blue' = $blue], or
212
	 *   int color (0x00RRGGBB [$blue is null]), or int red [0..255] when $blue is not null.
213
	 * @param bool|int $green When $blue !== null, $green is an int color, otherwise its
214
	 *   the flag to allow converting Web Color names to their web colors. Default true,
215
	 *	 for allow web colors to translate into their # hex color.
216
	 * @param ?int $blue The blue color. Default null for (A) or (B)
217
	 * @return string The valid # hex color.
218
	 */
219
	public static function ensureHexColor($value, $green = true, ?int $blue = null)
220
	{
221
		if (is_array($value)) {
222
			$blue = array_key_exists('blue', $value) ? $value['blue'] : (array_key_exists(2, $value) ? $value[2] : null);
223
			$green = array_key_exists('green', $value) ? $value['green'] : (array_key_exists(1, $value) ? $value[1] : true);
224
			$value = array_key_exists('red', $value) ? $value['red'] : (array_key_exists(0, $value) ? $value[0] : null);
225
		}
226
		if (is_numeric($value)) {
227
			if ($blue === null) {
228
				$blue = $value & 0xFF;
229
				$green = ($value >> 8) & 0xFF;
230
				$value = ($value >> 16) & 0xFF;
231
			}
232
			return '#' . strtoupper(
233
				str_pad(dechex(max(0, min($value, 255))), 2, '0', STR_PAD_LEFT) .
234
						 str_pad(dechex(max(0, min($green, 255))), 2, '0', STR_PAD_LEFT) .
235
						 str_pad(dechex(max(0, min($blue, 255))), 2, '0', STR_PAD_LEFT)
236
			);
237
		}
238
		$value = self::ensureString($value);
239
		$len = strlen($value);
240
		if ($green && $len > 0 && $value[0] !== '#') {
241
			static $colors;
242
			if (!$colors) {
243
				$reflect = new \ReflectionClass(\Prado\Web\UI\TWebColors::class);
244
				$colors = $reflect->getConstants();
245
				$colors = array_change_key_case($colors);
246
			}
247
			if (array_key_exists($lvalue = strtolower($value), $colors)) {
248
				$value = $colors[$lvalue];
249
				$len = strlen($value);
250
			}
251
		}
252
		if ($len == 0 || $value[0] !== '#' || ($len !== 4 && $len !== 7) || !preg_match('/^#[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?$/', $value)) {
253
			throw new TInvalidDataValueException('propertyvalue_invalid_hex_color', $value);
254
		}
255
		if ($len === 4) {
256
			$value = preg_replace('/^#(.)(.)(.)$/', '#${1}${1}${2}${2}${3}${3}', $value);
257
		}
258
		return strtoupper($value);
259
	}
260
}
261