TPropertyValue::ensureHexColor()   F
last analyzed

Complexity

Conditions 21
Paths 1105

Size

Total Lines 44
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 462

Importance

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