Passed
Push — master ( 8c5c26...d4b9fc )
by Fabio
07:44 queued 03:21
created

TPropertyValue::ensureObject()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
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 471
		if (is_string($value)) {
63
			return strcasecmp($value, 'true') == 0 || (is_numeric($value) && $value != 0);
64 471
		} else {
65
			return (bool) $value;
66
		}
67 471
	}
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 92
		if (TJavaScript::isJsLiteral($value)) {
79
			return $value;
80 92
		}
81
		if (is_bool($value)) {
82
			return $value ? 'true' : 'false';
83 92
		} else {
84
			return (string) $value;
85
		}
86 92
	}
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 175
		return (int) $value;
96
	}
97 175
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 143
		return (float) $value;
106
	}
107 143
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 13
		if (func_num_args() === 2 && is_string($enums)) {
162
			if (!isset($types[$enums])) {
163 13
				$types[$enums] = new \ReflectionClass($enums);
164 13
			}
165 12
			if ($types[$enums]->hasConstant($value)) {
166 7
				return $value;
167
			} else {
168 12
				throw new TInvalidDataValueException(
169 12
					'propertyvalue_enumvalue_invalid',
170
					$value,
171 2
					implode(' | ', $types[$enums]->getConstants())
172 2
				);
173 2
			}
174 2
		} elseif (!is_array($enums)) {
175
			$enums = func_get_args();
176
			array_shift($enums);
177 1
		}
178
		if (in_array($value, $enums, true)) {
179
			return $value;
180
		} else {
181 1
			throw new TInvalidDataValueException('propertyvalue_enumvalue_invalid', $value, implode(' | ', $enums));
182 1
		}
183
	}
184 1
185
	/**
186
	 * Converts the value to 'null' if the given value is empty
187
	 * @param mixed $value value to be converted
188
	 * @return mixed input or NULL if input is empty
189
	 */
190
	public static function ensureNullIfEmpty($value)
191
	{
192
		return empty($value) ? null : $value;
193
	}
194
195
	/**
196
	 * Converts the value to a web "#RRGGBB" hex color.
197
	 * The value[s] could be as an A) Web Color or # Hex Color string, or B) as a color
198
	 * encoded integer, eg 0x00RRGGBB, C) a triple ($value [red], $green, $blue), or D)
199
	 * an array of red, green, and blue, and index 0, 1, 2 or 'red', 'green', 'blue'.
200
	 * In instance (A), $green is treated as a boolean flag for whether to convert
201
	 * any web colors to their # hex color.  When red, green, or blue colors are specified
202
	 * they are assumed be be bound [0...255], inclusive.
203
	 * @param array|int|string $value String Web Color name or Hex Color (eg. '#336699'),
204
	 *   array of [$r, $g, $b] or ['red' => $red, 'green' => $green, 'blue' = $blue], or
205
	 *   int color (0x00RRGGBB [$blue is null]), or int red [0..255] when $blue is not null.
206
	 * @param bool|int $green When $blue !== null, $green is an int color, otherwise its
207
	 *   the flag to allow converting Web Color names to their web colors. Default true,
208
	 *	 for allow web colors to translate into their # hex color.
209
	 * @param ?int $blue The blue color. Default null for (A) or (B)
210
	 * @return string The valid # hex color.
211
	 */
212
	public static function ensureHexColor($value, $green = true, ?int $blue = null)
213
	{
214
		if (is_array($value)) {
215
			$blue = array_key_exists('blue', $value) ? $value['blue'] : (array_key_exists(2, $value) ? $value[2] : null);
216
			$green = array_key_exists('green', $value) ? $value['green'] : (array_key_exists(1, $value) ? $value[1] : true);
217
			$value = array_key_exists('red', $value) ? $value['red'] : (array_key_exists(0, $value) ? $value[0] : null);
218
		}
219
		if (is_numeric($value)) {
220
			if ($blue === null) {
221
				$blue = $value & 0xFF;
222
				$green = ($value >> 8) & 0xFF;
223
				$value = ($value >> 16) & 0xFF;
224
			}
225
			return '#' . strtoupper(
226
				str_pad(dechex(max(0, min($value, 255))), 2, '0', STR_PAD_LEFT) .
227
						 str_pad(dechex(max(0, min($green, 255))), 2, '0', STR_PAD_LEFT) .
228
						 str_pad(dechex(max(0, min($blue, 255))), 2, '0', STR_PAD_LEFT)
229
			);
230
		}
231
		$value = self::ensureString($value);
232
		$len = strlen($value);
233
		if ($green && $len > 0 && $value[0] !== '#') {
234
			static $colors;
235
			if (!$colors) {
236
				$reflect = new \ReflectionClass(\Prado\Web\UI\TWebColors::class);
237
				$colors = $reflect->getConstants();
238
				$colors = array_change_key_case($colors);
239
			}
240
			if (array_key_exists($lvalue = strtolower($value), $colors)) {
241
				$value = $colors[$lvalue];
242
				$len = strlen($value);
243
			}
244
		}
245
		if ($len == 0 || $value[0] !== '#' || ($len !== 4 && $len !== 7) || !preg_match('/^#[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?$/', $value)) {
246
			throw new TInvalidDataValueException('propertyvalue_invalid_hex_color', $value);
247
		}
248
		if ($len === 4) {
249
			$value = preg_replace('/^#(.)(.)(.)$/', '#${1}${1}${2}${2}${3}${3}', $value);
250
		}
251
		return strtoupper($value);
252
	}
253
}
254