Passed
Push — master ( a355c3...d448eb )
by Fabio
07:53
created

TJavaScript::renderScriptBlocksCallback()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 6
ccs 0
cts 2
cp 0
crap 6
rs 10
1
<?php
2
/**
3
 * TJavaScript class file
4
 *
5
 * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
6
 * @link https://github.com/pradosoft/prado
7
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
8
 * @package Prado\Web\Javascripts
9
 */
10
11
namespace Prado\Web\Javascripts;
12
13
use Prado\Web\THttpUtility;
14
use Prado\Prado;
15
16
/**
17
 * TJavaScript class.
18
 *
19
 * TJavaScript is a utility class containing commonly-used javascript-related
20
 * functions.
21
 *
22
 * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
23
 * @package Prado\Web\Javascripts
24
 * @since 3.0
25
 */
26
class TJavaScript
27
{
28
	/**
29
	 * Renders a list of javascript files
30
	 * @param array $files URLs to the javascript files
31
	 * @return string rendering result
32
	 */
33
	public static function renderScriptFiles($files)
34
	{
35
		$str = '';
36
		foreach ($files as $file) {
37
			$str .= self::renderScriptFile($file);
38
		}
39
		return $str;
40
	}
41
42
	/**
43
	 * Renders a javascript file
44
	 * @param Prado\Web\Javascripts\TJavaScriptAsset|string $asset URL to the javascript file or TJavaScriptAsset
0 ignored issues
show
Bug introduced by
The type Prado\Prado\Web\Javascripts\TJavaScriptAsset was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
45
	 * @return string rendering result
46
	 */
47
	public static function renderScriptFile($asset)
48
	{
49
		if (is_object($asset) && ($asset instanceof TJavaScriptAsset)) {
50
			return $asset->__toString() . "\n";
51
		}
52
		return '<script src="' . THttpUtility::htmlEncode($asset) . "\"></script>\n";
53
	}
54
55
	/**
56
	 * Renders a list of javascript blocks
57
	 * @param array $scripts javascript blocks
58
	 * @return string rendering result
59
	 */
60
	public static function renderScriptBlocks($scripts)
61
	{
62
		if (count($scripts)) {
63
			return "<script>\n/*<![CDATA[*/\n" . implode("\n", $scripts) . "\n/*]]>*/\n</script>\n";
64
		} else {
65
			return '';
66
		}
67
	}
68
69
	/**
70
	 * Renders a list of javascript code
71
	 * @param array $scripts javascript blocks
72
	 * @return string rendering result
73
	 */
74
	public static function renderScriptBlocksCallback($scripts)
75
	{
76
		if (count($scripts)) {
77
			return implode("\n", $scripts) . "\n";
78
		} else {
79
			return '';
80
		}
81
	}
82
83
	/**
84
	 * Renders javascript block
85
	 * @param string $script javascript block
86
	 * @return string rendering result
87
	 */
88
	public static function renderScriptBlock($script)
89
	{
90
		return "<script>\n/*<![CDATA[*/\n{$script}\n/*]]>*/\n</script>\n";
91
	}
92
93
	/**
94
	 * Quotes a javascript string.
95
	 * After processing, the string is safely enclosed within a pair of
96
	 * quotation marks and can serve as a javascript string.
97
	 * @param string $js string to be quoted
98
	 * @return string the quoted string
99
	 */
100
	public static function quoteString($js)
101
	{
102
		return self::jsonEncode($js, JSON_HEX_QUOT | JSON_HEX_APOS | JSON_HEX_TAG);
103
	}
104
105
	/**
106
	 * @param mixed $js
107
	 * @return TJavaScriptLiteral Marks a string as a javascript function. Once marke, the string is considered as a
108
	 * raw javascript function that is not supposed to be encoded by {@link encode}
109
	 */
110
	public static function quoteJsLiteral($js)
111
	{
112
		if ($js instanceof TJavaScriptLiteral) {
113
			return $js;
114
		} else {
115
			return new TJavaScriptLiteral($js);
116
		}
117
	}
118
119
	/**
120
	 * @param mixed $js
121 92
	 * @return bool true if the parameter is marked as a javascript function, i.e. if it's considered as a
122
	 * raw javascript function that is not supposed to be encoded by {@link encode}
123 92
	 */
124
	public static function isJsLiteral($js)
125
	{
126
		return ($js instanceof TJavaScriptLiteral);
127
	}
128
129
	/**
130
	 * Encodes a PHP variable into javascript representation.
131
	 *
132
	 * Example:
133
	 * <code>
134
	 * $options['onLoading'] = "doit";
135
	 * $options['onComplete'] = "more";
136
	 * echo TJavaScript::encode($options);
137
	 * //expects the following javascript code
138
	 * // {'onLoading':'doit','onComplete':'more'}
139
	 * </code>
140
	 *
141
	 * For higher complexity data structures use {@link jsonEncode} and {@link jsonDecode}
142
	 * to serialize and unserialize.
143
	 *
144
	 * @param mixed $value PHP variable to be encoded
145
	 * @param bool $toMap whether the output is a map or a list.
146
	 * @since 3.1.5
147
	 * @param bool $encodeEmptyStrings wether to encode empty strings too. Default to false for BC.
148
	 * @return string the encoded string
149
	 */
150
	public static function encode($value, $toMap = true, $encodeEmptyStrings = false)
151
	{
152
		if (is_string($value)) {
153
			return self::quoteString($value);
154
		} elseif (is_bool($value)) {
155
			return $value ? 'true' : 'false';
156
		} elseif (is_array($value)) {
157
			$results = '';
158
			if (($n = count($value)) > 0 && array_keys($value) !== range(0, $n - 1)) {
159
				foreach ($value as $k => $v) {
160
					if ($v !== '' || $encodeEmptyStrings) {
161
						if ($results !== '') {
162
							$results .= ',';
163
						}
164
						$results .= "'$k':" . self::encode($v, $toMap, $encodeEmptyStrings);
165
					}
166
				}
167
				return '{' . $results . '}';
168
			} else {
169
				foreach ($value as $v) {
170
					if ($v !== '' || $encodeEmptyStrings) {
171
						if ($results !== '') {
172
							$results .= ',';
173
						}
174
						$results .= self::encode($v, $toMap, $encodeEmptyStrings);
175
					}
176
				}
177
				return '[' . $results . ']';
178
			}
179
		} elseif (is_int($value)) {
180
			return "$value";
181
		} elseif (is_float($value)) {
182
			switch ($value) {
183
				case -INF:
184
					return 'Number.NEGATIVE_INFINITY';
185
					break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
186
				case INF:
187
					return 'Number.POSITIVE_INFINITY';
188
					break;
189
				default:
190
					$locale = localeConv();
191
					if ($locale['decimal_point'] == '.') {
192
						return "$value";
193
					} else {
194
						return str_replace($locale['decimal_point'], '.', "$value");
195
					}
196
					break;
197
			}
198
		} elseif (is_object($value)) {
199
			if ($value instanceof TJavaScriptLiteral) {
200
				return $value->toJavaScriptLiteral();
201
			} else {
202
				return self::encode(get_object_vars($value), $toMap);
203
			}
204
		} elseif ($value === null) {
205
			return 'null';
206
		} else {
207
			return '';
208
		}
209
	}
210
	/**
211
	 * Encodes a PHP variable into javascript string.
212
	 * This method invokes json_encode to perform the encoding.
213
	 * @param mixed $value variable to be encoded
214
	 * @param mixed $options
215
	 * @return string encoded string
216
	 */
217
	public static function jsonEncode($value, $options = 0)
218
	{
219
		if (($g = Prado::getApplication()->getGlobalization(false)) !== null &&
220
			strtoupper($enc = $g->getCharset()) != 'UTF-8') {
221
			self::convertToUtf8($value, $enc);
222
		}
223
224
		$s = @json_encode($value, $options);
225
		self::checkJsonError();
226
		return $s;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $s could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
227
	}
228
229
	/**
230
	 * Encodes an string or the content of an array to UTF8
231
	 * @param array|mixed|string $value
232
	 * @param string $sourceEncoding
233
	 */
234
	private static function convertToUtf8(&$value, $sourceEncoding)
235
	{
236
		if (is_string($value)) {
237
			$value = iconv($sourceEncoding, 'UTF-8', $value);
238
		} elseif (is_array($value)) {
239
			foreach ($value as &$element) {
240
				self::convertToUtf8($element, $sourceEncoding);
241
			}
242
		}
243
	}
244
245
	/**
246
	 * Decodes a javascript string into PHP variable.
247
	 * This method invokes json_decode to perform the decoding.
248
	 * @param string $value string to be decoded
249
	 * @param bool $assoc whether to convert returned objects to associative arrays
250
	 * @param int $depth recursion depth
251
	 * @return mixed decoded variable
252
	 */
253
	public static function jsonDecode($value, $assoc = false, $depth = 512)
254
	{
255
		$s = @json_decode($value, $assoc, $depth);
256
		self::checkJsonError();
257
		return $s;
258
	}
259
260
	private static function checkJsonError()
261
	{
262
		switch ($err = json_last_error()) {
263
			case JSON_ERROR_NONE:
264
				return;
265
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
266
			case JSON_ERROR_DEPTH:
267
				$msg = 'Maximum stack depth exceeded';
268
				break;
269
			case JSON_ERROR_STATE_MISMATCH:
270
				$msg = 'Underflow or the modes mismatch';
271
				break;
272
			case JSON_ERROR_CTRL_CHAR:
273
				$msg = 'Unexpected control character found';
274
				break;
275
			case JSON_ERROR_SYNTAX:
276
				$msg = 'Syntax error, malformed JSON';
277
				break;
278
			case JSON_ERROR_UTF8:
279
				$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
280
				break;
281
			default:
282
				$msg = 'Unknown error';
283
				break;
284
		}
285
		throw new \Exception("JSON error ($err): $msg");
286
	}
287
288
	/**
289
	 * Minimize the size of a javascript script.
290
	 * This method is based on Douglas Crockford's JSMin.
291
	 * @param string $code code that you want to minimzie
292
	 * @return string minimized version of the code
293
	 */
294
	public static function JSMin($code)
295
	{
296
		return \JSMin\JSMin::minify($code);
297
	}
298
}
299