Passed
Push — develop ( e398eb...94c1bc )
by Neill
24:20
created

SmartySharedPlugins::protectHtmlEntities()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
c 1
b 0
f 0
dl 0
loc 8
ccs 0
cts 6
cp 0
rs 10
cc 2
nc 2
nop 2
crap 6
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: newicon
5
 * Date: 17/03/2017
6
 * Time: 13:14
7
 */
8
9
namespace neon\core\view;
10
11
use \Neon;
12
use neon\core\helpers\Html;
13
use neon\core\helpers\Hash;
14
use neon\core\helpers\Page;
15
use neon\core\helpers\Str;
16
use neon\core\helpers\Url;
17
use neon\core\helpers\Arr;
18
use neon\core\web\View;
19
20
use \Smarty;
21
use yii\base\InvalidConfigException;
22
23
/**
24
 * Class SmartySharedPlugins
25
 * This class provides smarty plugins that can be shared between the admin smarty renderer and cosmos
26
 * @package neon\core\view
27
 */
28
class SmartySharedPlugins
29
{
30
	const IMG_SRCSET_DEFAULT_WIDTHS = "350,640,768,1024,1280,1536,1920";
31
32
	/**
33
	 * Apply these plugin functions to a smarty object
34
	 * @param mixed $parent
35
	 * @param Smarty $smarty
36
	 * @throws \SmartyException
37
	 */
38
	public static function apply($parent, $smarty)
39
	{
40
		new self($parent, $smarty);
41
	}
42
43
	/**
44
	 * Maintain a list of tags that will be deprecated so we can aid upgrades and provide sensible error messages
45
	 * @return array
46
	 */
47
	public static function deprecatedTags()
48
	{
49
		return ['cosmos_head_script', 'cosmos_body_script'];
50
	}
51
52
	/**
53
	 * SmartySharedPlugins constructor.
54
	 * @param mixed $parent - should implement a parent page interface
55
	 * @param \Smarty $smarty
56
	 * @throws \SmartyException
57
	 */
58
	public function __construct($parent, $smarty)
0 ignored issues
show
Unused Code introduced by
The parameter $parent is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

58
	public function __construct(/** @scrutinizer ignore-unused */ $parent, $smarty)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
59
	{
60
		// app plugin smarty directories
61
		$coreApps = neon()->coreApps;
0 ignored issues
show
Bug Best Practice introduced by
The property coreApps does not exist on neon\core\ApplicationWeb. Since you implemented __get, consider adding a @property annotation.
Loading history...
62
		foreach ($coreApps as $key=>$app) {
63
			$smarty->addPluginsDir(Neon::getAlias("@neon/$key/plugins/smarty"));
64
		}
65
66
		// plugins
67
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'firefly_url', [$this, 'firefly_url']);
68
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'firefly_image', [$this, 'firefly_image']);
69
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'image_srcset', [$this, 'image_srcset']);
70
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'setting', [$this, 'setting']);
71
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'time', [$this, 'time']);
72
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'csrf_element', [$this, 'csrf_element']);
73
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'csrf_meta_tags', [$this, 'csrf_meta_tags']);
74
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'url', [$this, 'url']);
75
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'registerAsset', [$this, 'registerAsset']);
76
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'jsFile', [$this, 'jsFile']);
77
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'cssFile', [$this, 'cssFile']);
78
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'neon_head', [$this, 'neonHead']);
79
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'neon_body_begin', [$this, 'neonBodyBegin']);
80
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'neon_body_end', [$this, 'neonBodyEnd']);
81
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'hasPermission', [$this, 'hasPermission']);
82
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'style', [$this, 'style']);
83
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'uuid', [$this, 'uuid']);
84
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'protectHtmlEntities', [$this, 'protectHtmlEntities']);
85
86
		// modifiers
87
		$smarty->registerPlugin(Smarty::PLUGIN_MODIFIER, 'htmlAttributes', [$this, 'htmlAttributes']);
88
		$smarty->registerPlugin(Smarty::PLUGIN_MODIFIER, 'humanize', '\neon\core\helpers\Str::humanize');
89
		$smarty->registerPlugin(Smarty::PLUGIN_MODIFIER, 'json', [$this, 'json']);
90
91
		// blocks
92
		$smarty->registerPlugin(Smarty::PLUGIN_BLOCK, 'markdown', [$this, 'markdown']);
93
		// All the same - ways to register a block of js :
94
		$smarty->registerPlugin(Smarty::PLUGIN_BLOCK, 'script', [$this, 'js']);
95
		$smarty->registerPlugin(Smarty::PLUGIN_BLOCK, 'js', [$this, 'js']);
96
		$smarty->registerPlugin(Smarty::PLUGIN_BLOCK, 'Js', [$this, 'js']);
97
		// Register a block of css
98
		$smarty->registerPlugin(Smarty::PLUGIN_BLOCK, 'css', [$this, 'css']);
99
100
		// experimental
101
		$smarty->registerPlugin(Smarty::PLUGIN_BLOCK, 'cmp', [$this, 'cmp']);
102
103
104
		// deprecated tags
105
		$this->registerDeprecatedTags($smarty);
106
	}
107
108
	/**
109
	 * @param \Smarty $smarty
110
	 * @throws \SmartyException
111
	 */
112
	public function registerDeprecatedTags($smarty)
113
	{
114
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'cosmos_head_script', [$this, 'neonHead']);
115
		$smarty->registerPlugin(Smarty::PLUGIN_FUNCTION, 'cosmos_body_script', [$this, 'neonBodyEnd']);
116
	}
117
118
	/**
119
	 * Parse a block of content as markdown
120
	 *
121
	 * ```smarty
122
	 * {markdown} ***markdown content*** {/markdown}
123
	 * ```
124
	 *
125
	 * @param $params
126
	 * @param $content
127
	 * @return string
128
	 */
129
	public function markdown($params, $content)
130
	{
131
		$parser = new MarkdownNeon();
132
		return $parser->parse($content);
133
	}
134
135
136
	/**
137
	 * @param $params
138
	 * @param $content
139
	 * @param $template
140
	 * @param $repeat
141
	 * @return string
142
	 */
143
	public function cmp($params, $content, $template, &$repeat)
144
	{
145
		// only output on the closing tag
146
		if (!$repeat) {
147
			$class = Arr::remove($params, 'class');
148
			$params['content'] = $content;
149
			if (class_exists($class)) {
150
				$widget = new $class();
151
				foreach($params as $key => $val) {
152
					if ($widget->hasProperty($key))
153
						$widget->$key = $val;
154
				}
155
				return $widget->run();
156
			} else {
157
				return "<div class=\"neonWidgetError alert alert-danger\">Widget class '$class' not found</div>";
158
			}
159
		}
160
	}
161
162
	/**
163
	 * Register a style configurable parameter
164
	 *
165
	 * @param array $params
166
	 * @param Smarty $smarty
167
	 */
168
	public function style($params, $smarty)
169
	{
170
		// possible vue style implementation
171
//		Arr::props($params, [
172
//			'name' => ['required' => true, 'type' => 'string'],
173
//			'type' => ['required' => true, 'type' => 'string'],
174
//			'options' => ['required' => false, 'type' => 'array', 'default' => []]
175
//		]);
176
177
		$name = Arr::getRequired($params, 'name');
178
		$type = Arr::getRequired($params, 'type');
179
		$options = Arr::get($params, 'options', []);
180
		if (!is_array($options))
181
			throw new \InvalidArgumentException('"options" property must be an array "' . gettype($options) . '" given');
182
		$default = Arr::get($params, 'default', '');
183
184
		$value = neon()->view->styleManager->add($name, $default, $type, $options);
185
		$smarty->assign($name, $value);
186
	}
187
188
	/**
189
	 * Function to expand an array into html attributes
190
	 *
191
	 * @param array $params
192
	 * @param Object $smarty
193
	 *
194
	 * @return string
195
	 */
196
	public function htmlAttributes($params, $smarty)
0 ignored issues
show
Unused Code introduced by
The parameter $smarty is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

196
	public function htmlAttributes($params, /** @scrutinizer ignore-unused */ $smarty)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
197
	{
198
		dp($params);
199
	}
200
201
	/**
202
	 * Smarty template function to get absolute URL for using in links
203
	 *
204
	 * Usage is the following:
205
	 *
206
	 * {url route='blog/view' alias=$post.alias user=$user.id}
207
	 *
208
	 * where route is Yii route and the rest of parameters are passed as is.
209
	 *
210
	 * @param array $params
211
	 * @return string
212
	 */
213
	public function url($params)
214
	{
215
		if (!isset($params['route'])) {
216
			trigger_error("path: missing 'route' parameter");
217
		}
218
		array_unshift($params, $params['route']) ;
219
		unset($params['route']);
220
		return Url::toRoute($params, true);
221
	}
222
223
	/**
224
	 * tag: csrf_element
225
	 *
226
	 * Output a form element with the csrf key in it.
227
	 * This is a hidden field and allows the form to post to yii
228
	 *
229
	 * ```{csrf_element}```
230
	 *
231
	 * @param array $params ['id']
232
	 * @return string html
233
	 */
234
	public function csrf_element($params)
0 ignored issues
show
Unused Code introduced by
The parameter $params is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

234
	public function csrf_element(/** @scrutinizer ignore-unused */ $params)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
235
	{
236
		return '<input type="hidden" name="'.neon()->request->csrfParam.'" value="' . neon()->request->getCsrfToken() . '" />';
237
	}
238
239
	/**
240
	 * Output Csrf meta tags
241
	 * @param $params
242
	 * @param $smarty
243
	 * @return string
244
	 */
245
	public function csrf_meta_tags($params, $smarty)
0 ignored issues
show
Unused Code introduced by
The parameter $smarty is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

245
	public function csrf_meta_tags($params, /** @scrutinizer ignore-unused */ $smarty)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

245
	public function csrf_meta_tags(/** @scrutinizer ignore-unused */ $params, $smarty)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
246
	{
247
		return Html::csrfMetaTags();
248
	}
249
250
	/**
251
	 * tag: firefly_url
252
	 *
253
	 * Get a url for a file managed by firefly from it's id
254
	 *
255
	 * ```{firefly_url id="the file uuid"}```
256
	 *
257
	 * @param array $params ['id']
258
	 * @return string  the URL to the file
259
	 * @throws \InvalidArgumentException
260
	 */
261
	public function firefly_url($params)
262
	{
263
		if (isset($params['id']))
264
			return neon()->firefly->getUrl($params['id']);
265
	}
266
267
	/**
268
	 * tag: firefly_image
269
	 *
270
	 * Get a url for an image managed by firefly from it's id
271
	 *
272
	 * ```{firefly_url id="the file uuid" ...}```
273
	 *
274
	 * @param array $params
275
	 *   'id' - the image id
276
	 *   'w' - the image width
277
	 *   'h' - the image height
278
	 *   'q' - quality of compression (0-100)
279
	 *   'fit' - fit the image into the shape
280
	 *   'rotate' - angle to rotate image by
281
	 *   'flip' - flip image horizontally (h) or vertically (v)
282
	 *   'crop' - crop the image
283
	 *
284
	 * @return string  the URL to the file
285
	 * @throws \InvalidArgumentException
286
	 */
287 45
	public function firefly_image($params)
288
	{
289 45
		if (isset($params['id']))
290 45
			return neon()->firefly->getImage(Arr::pull($params, 'id'), $params);
291
	}
292
293
	/**
294
	 * tag: image_srcset
295
	 *
296
	 * Gets a string suitable for placing inside an image tag srcset, works in conjunction with firefly_image_srcset
297
	 *
298
	 * ```{image_srcset firefly_id="the file uuid" ...}```
299
	 *
300
	 * Examples:
301
	 * ```{image_srcset image_id='z08MMpEHcW27bd_diYLIMw'}```
302
	 * ```{image_srcset image_id='z08MMpEHcW27bd_diYLIMw' id='image-tag-id' alt='image alt text' style='object-fit:cover' class='imgsetclass'}```
303
	 * ```{image_srcset image_id='z08MMpEHcW27bd_diYLIMw' widths='1000,2000'}```
304
	 * ```{image_srcset image_id='z08MMpEHcW27bd_diYLIMw' widths='1000,2000' breaks='50vw,100vw' min-break='600px'}```
305
	 * ```{image_srcset image_id='z08MMpEHcW27bd_diYLIMw' widths='300,600,900' resolutions='2x,3x'}```
306
	 *
307
	 * @todo: consider supporting additional firefly parameters
308
	 * @param $params
309
	 *    'firefly_id   - the image id
310
	 *    'quality'     - quality parameter is passed through as a firefly q parameter
311
	 *    'widths'      - comma separated list of widths in pixels as ints
312
	 *    'src-width'   - width to use for the img src (if unspecified the the smallest from widths will be used) in pixels as int
313
	 *    'breaks'      - comma separated list of break point sizes (will be automatically generated if not present) as int with 'px' or 'vw' specified
314
	 *    'min-break'   - force use of a specific min-width as int with 'px' or 'vw' specified
315
	 *    'resolutions' - alternative to breaks, a set of resolutions (will be ignored if breaks are used) as float/int with 'x' specified
316
	 *    + any other parameters passed in will be built into the resulting tag string (these are not validated)
317
	 * @return string the srcset string
318
	 * @throws \InvalidArgumentException
319
	 * @see https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images
320
	 */
321 75
	public function image_srcset($params)
322
	{
323 75
		if (!isset($params['firefly_id'])) {
324 3
			throw new \InvalidArgumentException("'firefly_id' is a required parameter");
325
		}
326 72
		if (!isset($params['widths'])) {
327
			// todo: this should be possible to set via configuration
328
			// use some hopefully sensible defaults
329 63
			$params['widths'] = self::IMG_SRCSET_DEFAULT_WIDTHS;
330
		}
331
332 72
		$id = Arr::pull($params,'firefly_id');
333 72
		$widths = array_map('trim',explode(',',Arr::pull($params,'widths')));
334 72
		$srcsetParts = [];
335 72
		$srcSizeParts = [];
336 72
		$useResolutions = [];
337 72
		$minBreak = false;
338 72
		if (isset($params['min-break'])) {
339 12
			$minBreak = Arr::pull($params,'min-break');
340 12
			if (!Str::validateNumericWithUnits($minBreak,['px','vw'])) {
341 6
				throw new \InvalidArgumentException("The min-break value '".$minBreak."' should be numeric and end with 'px' or 'vw'");
342
			}
343
		}
344 66
		if (isset($params['breaks'])) {
345
			// optionally validate & collate the breaks for the 'sizes' attribute
346 12
			$breaks = array_map('trim',explode(',',Arr::pull($params,'breaks')));
347 12
			foreach ($breaks as $idx=>$break) {
348 12
				if (!Str::validateNumericWithUnits($break, ['px','vw'])) {
349 6
					throw new \InvalidArgumentException("The break value '".$break."' should be numeric and end with 'px' or 'vw'");
350
				}
351 6
				if ($idx==0 && $minBreak) {
352
					$break = "(min-width: ".$minBreak.") ".$break;
353
				}
354 6
				$srcSizeParts[]=$break;
355
			}
356
		}
357 54
		elseif (isset($params['resolutions'])) {
358
			// optionally validate & collate any specified resolutions to use (if breaks haven't been specified)
359 12
			$useResolutions = array_map('trim',explode(',',Arr::pull($params,'resolutions')));
360 12
			if (count($useResolutions) != count($widths)-1) {
361 6
				throw new \InvalidArgumentException("Since there are ".count($widths)." widths you should specify ".(count($widths)-1)." resolutions to apply");
362
			}
363 6
			foreach ($useResolutions as $useResolution) {
364 6
				if (!Str::validateNumericWithUnits($useResolution,['x'])) {
365 4
					throw new \InvalidArgumentException("The resolution '".$useResolution."' is not a valid resolution, it should be numeric and then end with an 'x'");
366
				}
367
			}
368
		}
369
		else {
370
			// if neither 'breaks' or 'resolutions' was specified then use the widths
371 42
			foreach ($widths as $idx=>$width) {
372 42
				if ($idx==0 && $minBreak) {
373 6
					$width = "(min-width: ".$minBreak.") ".$width;
374
				}
375 42
				$srcSizeParts[] = $width."px";
376
			}
377
		}
378
379
		// validate and collate the widths
380 51
		$useQuality = false;
381 51
		if (isset($params['quality'])) {
382 6
			$useQuality = Arr::pull($params, 'quality');
383 6
			if (!is_numeric($useQuality)) {
384 3
				throw new \InvalidArgumentException("the quality '".$useQuality."' must be numeric");
385
			}
386
		}
387 48
		foreach ($widths as $idx=>$width) {
388 48
			if (!is_numeric($width)) {
389 3
				throw new \InvalidArgumentException("One of the widths specified was not numeric '".$width."'");
390
			}
391 45
			$useParams = ['id'=>$id, 'w'=>(int)$width];
392 45
			if ($useQuality) {
393 3
				$useParams['q'] = $useQuality;
394
			}
395 45
			$imageUrl = $this->firefly_image($useParams);
396 45
			if ($useResolutions) {
397 3
				$srcsetParts[] = $imageUrl.( ($idx>=1) ? ' '.$useResolutions[$idx-1] : '' );
398
			}
399
			else {
400 42
				$srcsetParts[] = $imageUrl . ' ' . $width . 'w';
401
			}
402 45
			if ($idx==0 && !isset($params['src-width']) && !isset($params['src'])) {
403 37
				$params['src'] = $imageUrl;
404
			}
405
		}
406
407
		// collate the tag attributes
408 45
		if (isset($params['src-width'])) {
409 9
			$srcWidth = Arr::pull($params,'src-width');
410 9
			if (!is_numeric($srcWidth)) {
411 3
				throw new \InvalidArgumentException("src-width '".$srcWidth."' must be numeric");
412
			}
413 6
			$useParams = ['id'=>$id, 'w'=>(int)$srcWidth];
414 6
			if (isset($params['quality'])) {
415
				$useParams = (int)$params['quality'];
416
			}
417 6
			if (!isset($params['src'])) {
418 6
				$params['src'] = $this->firefly_image($useParams);
0 ignored issues
show
Bug introduced by
It seems like $useParams can also be of type integer; however, parameter $params of neon\core\view\SmartySha...lugins::firefly_image() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

418
				$params['src'] = $this->firefly_image(/** @scrutinizer ignore-type */ $useParams);
Loading history...
419
			}
420
		}
421 42
		if ($srcSizeParts && !isset($params['sizes'])) {
422 36
			$params['sizes'] = implode(', ', $srcSizeParts);
423
		}
424 42
		if ($srcsetParts && !isset($params['srcset'])) {
425 39
			$params['srcset'] = implode(', ', $srcsetParts);
426
		}
427
428
		// finally generate the tag ... note that these can overwrite the previously generated params
429 42
		$tagAttributes =  [];
430 42
		foreach ($params as $key=>$value) {
431 42
			$tagAttributes[] = $key."='".htmlspecialchars($value)."'";
432
		}
433
434 42
		return "<img ".implode(' ',$tagAttributes).">";
435
	}
436
437
	/**
438
	 * tag: setting
439
	 *
440
	 * Get a setting value from the settings manager
441
	 *
442
	 * ```{setting app='aaa' name='nnn' [default='xxx' assign='yyy']}```
443
	 *
444
	 * @param array $params
445
	 *   app - required - the settings app area
446
	 *   name - required - the setting required
447
	 *   default - optional - a default value if it's not set
448
	 *   assign - optional - if set assigns to this variable else returns the value
449
	 * @param object $smarty
450
	 * @return string
451
	 */
452
	public function setting($params, $smarty)
453
	{
454
		$app = isset($params['app']) ? $params['app'] : null;
455
		$name = isset($params['name']) ? $params['name'] : null;
456
		$default = isset($params['default']) ? $params['default'] : null;
457
		$assign = isset($params['assign']) ? $params['assign'] : null;
458
		if ($app && $name) {
459
			$value = neon('settings')->manager->get($app, $name, $default);
0 ignored issues
show
Bug introduced by
The method get() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

459
			/** @scrutinizer ignore-call */ 
460
   $value = neon('settings')->manager->get($app, $name, $default);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug Best Practice introduced by
The property manager does not exist on neon\core\ApplicationWeb. Since you implemented __get, consider adding a @property annotation.
Loading history...
460
			if ($assign)
461
				$smarty->assign($assign, $value);
462
			else
463
				return $value;
464
		} else {
465
			return "Usage: you must provide an 'app' and a 'name' parameter. You provided ".print_r($params,true);
466
		}
467
	}
468
469
	/**
470
	 * tag: time
471
	 *
472
	 * Convert a timestamp into a YYYY-MM-DD HH:MM:SS string
473
	 *
474
	 * Usage:
475
	 * ```
476
	 *   {time} - returns the current time
477
	 *   {time stamp='123456'} - returns the timestamp formatted
478
	 * ```
479
	 *
480
	 * @param $params empty for now and integer timestamp otherwise
0 ignored issues
show
Bug introduced by
The type neon\core\view\empty 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...
481
	 * @return string YYYY-MM-DD HH:MM:SS
482
	 */
483
	public function time($params)
484
	{
485
		$format = 'Y-m-d H:i:s';
486
		if (isset($params['stamp']))
487
			return date($format, (integer)$params['stamp']);
488
		return date($format);
489
	}
490
491
	/**
492
	 * Output a pre tag of nicely formatted json - useful for debugging
493
	 *
494
	 * @param $params
495
	 * @return string
496
	 */
497
	public function json($params)
498
	{
499
		return '<pre>' . json_encode($params, JSON_PRETTY_PRINT) . '</pre>';
500
	}
501
502
	/**
503
	 * Looks for a `position` or `pos` key in the params and returns the integer value for the string position
504
	 * ```
505
	 * $this->getAssetPosition(['pos' => 'end']) // gives: 3
506
	 * ```
507
	 * @see SmartySharedPlugins::registerAsset
508
	 * @see SmartySharedPlugins::js()
509
	 * @param array $params
510
	 * @param string $default - defaults to 'end'
511
	 * @return int
512
	 * @throws \Exception
513
	 */
514
	public function getAssetPosition($params, $default='end')
515
	{
516
		$position = Arr::get($params, 'pos', Arr::get($params, 'position', $default));
517
		$positions = [
518
			'head'  => View::POS_HEAD,
519
			'begin' => View::POS_BEGIN,
520
			'end'   => View::POS_END,
521
			'ready' => View::POS_READY,
522
			'load'  => View::POS_LOAD,
523
		];
524
		if (!array_key_exists($position, $positions)) {
525
			throw new \Exception('The javascript position specified must be one of ' . print_r(array_keys($positions)) . ', you specified "'.$position.'"');
526
		}
527
		return $positions[$position];
528
	}
529
530
	/**
531
	 * Smarty block function plugin
532
	 * Usage is the following:
533
	 *
534
	 * ```
535
	 * {Js} Javascript code here {/Js}
536
	 * {Js pos='end'} Javascript code here {/Js}
537
	 * {Js pos='ready'} jquery on ready code here {/Js}
538
	 * ```
539
	 *
540
	 * @param $params
541
	 *
542
	 *   [position|pos] with values:
543
	 *   The position param specified where the javascript block will be rendered on the page it can have
544
	 *   the following values:
545
	 *
546
	 *   - "head"  : This means the javascript is rendered in the head section.
547
	 *   - "begin" : This means the javascript is rendered at the beginning of the body section.
548
	 *   - "end"   : This means the javascript is rendered at the end of the body section.
549
	 *   - "ready" : This means the JavaScript code block will be enclosed within `jQuery(document).ready()`.
550
	 *   - "load"  : This means the JavaScript code block will be enclosed within `jQuery(window).load()`.
551
	 *
552
	 *
553
	 * @param $content
554
	 * @return void
555
	 * @throws \Exception
556
	 */
557
	public function js($params, $content)
558
	{
559
		if ($content == null) return;
560
		$key = Arr::get($params, 'key', null);
561
		$content = str_replace(['<script>', '</script>'], '', $content);
562
		neon()->view->registerJs($content, $this->getAssetPosition($params), $key);
563
	}
564
565
	/**
566
	 * Register a block of css code
567
	 *
568
	 * ```
569
	 * {css position='head'}
570
	 * .myStyle {color:'red'}
571
	 * {/css}
572
	 * ```
573
	 *
574
	 * @param $params
575
	 * [position|pos] string - the string position in the page where css should be output - defaults to 'head'
576
	 * [key] string - a key to uniquely identify this css block so it will not be rendered twice
577
	 * @param $content
578
	 * @throws \Exception
579
	 */
580
	public function css($params, $content)
581
	{
582
		if ($content == null) return;
583
		$key = Arr::get($params, 'key', null);
584
		$content = str_replace(['<style>', '</style>'], '', $content);
585
		neon()->view->registerCss($content, ['position'=>$this->getAssetPosition($params, 'head')], $key);
586
	}
587
588
	/**
589
	 * Register Asset bundle
590
	 *
591
	 * ```
592
	 * {registerAsset name='\yii\web\JqueryAsset'} // jquery will be loaded before the end body tag
593
	 * {registerAsset path='\yii\web\JqueryAsset' pos='end'} // jquery will be loaded before the end body tag
594
	 * {registerAsset path='\yii\web\ThemeBootstrap' assignUrl='themeUrl'} // jquery will be loaded before the end body tag
595
	 *```
596
	 *
597
	 * @param array $params
598
	 * - [name|path] {string} = a asset bundle path to register for e.g. \yii\web\JqueryAsset
599
	 * - [pos|position] {string:head|begin|end|ready|load} = the position where the bundle should be output on the page defaults to 'end'
600
	 * @param Smarty $smarty
601
	 * @throws InvalidConfigException if the asset bundle does not exist or a circular dependency is detected
602
	 * @throws \Exception if incorrect asset position is given
603
	 * @return void
604
	 */
605
	public function registerAsset($params, $smarty)
606
	{
607
		// get the bundle - will look for `name` or `bundle` or `path` keys
608
		$class = Arr::get($params, 'name', Arr::get($params, 'path', null));
609
		if ($class == null) return;
610
611
		// get the position - will looks for `pos` or `position` keys - defaults View::POS_END
612
		$position = Arr::get($params, 'pos', Arr::get($params, 'position', 'end'));
613
614
		$bundle = neon()->view->registerAssetBundle($class, $this->getAssetPosition($position));
0 ignored issues
show
Bug introduced by
It seems like $position can also be of type string; however, parameter $params of neon\core\view\SmartySha...ins::getAssetPosition() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

614
		$bundle = neon()->view->registerAssetBundle($class, $this->getAssetPosition(/** @scrutinizer ignore-type */ $position));
Loading history...
615
		$assign = Arr::get($params, 'assignUrl', Arr::get($params, 'assign', false));
616
		$smarty->assign($assign, $bundle->baseUrl);
0 ignored issues
show
Bug introduced by
It seems like $assign can also be of type false; however, parameter $tpl_var of Smarty_Internal_Data::assign() does only seem to accept array|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

616
		$smarty->assign(/** @scrutinizer ignore-type */ $assign, $bundle->baseUrl);
Loading history...
617
	}
618
619
	/**
620
	 * @param array $params
621
	 * - [src|url]    string - the js src attribute
622
	 * - [attributes] array  - additional html attributes for the script tag also supports the special `depends`
623
	 *                           attribute enabling this file to depend on an asset bundle
624
	 * - [depends]    string - asset bundle dependencies
625
	 * - [key]        string - key to uniquely identify this file - optional
626
	 */
627
	public static function jsFile($params)
628
	{
629
		$src = Arr::get($params, 'src', Arr::get($params, 'url', null));
630
		if ($src === null) {
631
			trigger_error("jsFile: missing 'url' or 'src' parameter");
632
		}
633
		$attributes = Arr::get($params, 'attributes', []);
634
		$attributes['depends'] = Arr::get($params, 'depends', null);
635
		$key = Arr::get($params, 'key', null);
636
		neon()->view->registerJsFile($src, $attributes, $key);
637
	}
638
639
	/**
640
	 * @param array $params
641
	 * - [src|url]    string - the js src attribute
642
	 * - [attributes] array  - additional html attributes for the script tag also supports the special `depends`
643
	 *                           attribute enabling this file to depend on an asset bundle
644
	 * - [depends]    string - asset bundle dependencies
645
	 * - [key]        string - key to uniquely identify this file - optional
646
	 */
647
	public static function cssFile($params)
648
	{
649
		$src = Arr::get($params, 'src', Arr::get($params, 'url', null));
650
		if ($src === null) {
651
			trigger_error("jsFile: missing 'url' or 'src' parameter");
652
		}
653
		$attributes = Arr::get($params, 'attributes', []);
654
		$attributes['depends'] = Arr::get($params, 'depends', null);
655
		$key = Arr::get($params, 'key', null);
656
		neon()->view->registerCssFile($src, $attributes, $key);
657
	}
658
659
660
	/**
661
	 * Generates a UUID
662
	 * return string $UUID
663
	 */
664
	public function uuid($params, $template) {
0 ignored issues
show
Unused Code introduced by
The parameter $template is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

664
	public function uuid($params, /** @scrutinizer ignore-unused */ $template) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

664
	public function uuid(/** @scrutinizer ignore-unused */ $params, $template) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
665
		return Hash::uuid64();
666
	}
667
668
	/**
669
	 * Outputs scripts at the head
670
	 * - this tag marks where the - 'head' - View::POS_HEAD - position is
671
	 */
672
	public function neonHead()
673
	{
674
		return neon()->view->head();
0 ignored issues
show
Bug introduced by
Are you sure the usage of neon()->view->head() targeting yii\web\View::head() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
675
	}
676
677
	/**
678
	 * Outputs scripts after the first body tag
679
	 * - this tag marks where the - 'begin' - View::POS_BEGIN - position is
680
	 */
681
	public function neonBodyBegin()
682
	{
683
		return neon()->view->beginBody();
0 ignored issues
show
Bug introduced by
Are you sure the usage of neon()->view->beginBody() targeting yii\web\View::beginBody() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
684
	}
685
686
	/**
687
	 * Outputs scripts at the end body tag position
688
	 * - this tag marks where the - 'end' - View::POS_END - position is
689
	 */
690
	public function neonBodyEnd()
691
	{
692
		return neon()->view->endBody();
0 ignored issues
show
Bug introduced by
Are you sure the usage of neon()->view->endBody() targeting yii\web\View::endBody() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
693
	}
694
695
	/**
696
	 * check if a user has permission to do something
697
	 * @param array $params
698
	 * - [permission] string - the permission to check
699
	 * - [assign] string  - if set then the result is set to this parameter.
700
	 *   if not set then it is set to the same name as the permission
701
	 * - additional params - any additional params will be passed through to the
702
	 *   permission test
703
	 * @param Smarty $smarty
704
	 */
705
	public function hasPermission($params, $smarty)
706
	{
707
		if (empty($params['permission']))
708
			trigger_error("permission: missing 'permission' parameter");
709
		$permission = $params['permission'];
710
		$assign = empty($params['assign']) ? $permission : $params['assign'];
711
		$canDo = neon()->user->can($permission, $params);
712
		$smarty->assign($assign, $canDo);
713
	}
714
715
	/**
716
	 * Protects any HtmlEntities that are interpreted into javascript by
717
	 * via HTML. E.g. &lt; will be conerted to < by the browser. So this further
718
	 * protects by converting it to &amp;lt; so it beomes &lt; in the browser
719
	 * @param array $params
720
	 * - [input] string - the input string to protect
721
	 * - [assign] string (optional) - if set, then assign it to this parameter. If
722
	 *   not set, then return the converted string
723
	 * @param Smarty $smarty
724
	 * @return string  if no assign parameter provided, return the result
725
	 */
726
	public function protectHtmlEntities($params, $smarty)
727
	{
728
		$input = $params['input'];
729
		$output = str_replace('&','&amp;', $input);
730
		if (!empty($params['assign'])) {
731
			$smarty->assign($params['assign'], $output);
732
		} else {
733
			return $output;
734
		}
735
	}
736
}
737