Passed
Push — 2.2.0 ( ...194d6e )
by steve
16:59
created

SmartyExtension::pluginHandler()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 13
c 0
b 0
f 0
nc 4
nop 6
dl 0
loc 21
ccs 0
cts 16
cp 0
crap 20
rs 9.8333
1
<?php
2
/**
3
 * @link http://www.newicon.net/neon
4
 * @copyright Copyright (c) 2015 Newicon Ltd
5
 * @license http://www.newicon.net/neon/license
6
 */
7
8
9
namespace neon\core\view;
10
11
use neon\core\helpers\Str;
12
use Yii;
13
use neon\core\helpers\Url;
14
use \Smarty;
15
use \neon\core\helpers\Arr;
16
17
/**
18
 * Description of SmartyExtension
19
 *
20
 * @author elita
21
 */
22
class SmartyExtension
23
{
24
	/**
25
	 * @var \yii\smarty\ViewRenderer ViewRenderer
26
	 */
27
	protected $viewRenderer;
28
	/**
29
	 * @var Smarty
30
	 */
31
	protected $smarty;
32
33
34
	/**
35
	 * @param \yii\smarty\ViewRenderer $viewRenderer
36
	 * @param Smarty $smarty
37
	 */
38
	public function __construct($viewRenderer, $smarty)
39
	{
40
		$this->viewRenderer = $viewRenderer;
41
		$smarty = $this->smarty = $smarty;
42
		$smarty->registerPlugin('function', 'path', [$this, 'functionPath']);
43
		$smarty->registerPlugin('function', 'set', [$this, 'functionSet']);
44
		$smarty->registerPlugin('function', 'meta', [$this, 'functionMeta']);
45
		$smarty->registerPlugin('block', 'title', [$this, 'blockTitle']);
46
		$smarty->registerPlugin('block', 'description', [$this, 'blockDescription']);
47
		$smarty->registerPlugin('compiler', 'use', [$this, 'compilerUse']);
48
		$smarty->registerPlugin('modifier', 'void', [$this, 'modifierVoid']);
49
		// apply common shared plugins between cosmos and core.
50
		// this is a bit messy as ideally cosmos would use the same renderer as the admin. *.tpl views
51
		SmartySharedPlugins::apply($viewRenderer, $smarty);
52
		$this->smarty->registerDefaultPluginHandler([$this, 'pluginHandler']);
53
	}
54
55
	/**
56
	 * Default Plugin Handler
57
	 *
58
	 * called when Smarty encounters an undefined tag during compilation
59
	 *
60
	 * @param string                     $name    name of the undefined tag
61
	 * @param string                     $type    tag type (e.g. Smarty::PLUGIN_FUNCTION, Smarty::PLUGIN_BLOCK,
62
	 *                                   Smarty::PLUGIN_COMPILER, Smarty::PLUGIN_MODIFIER, Smarty::PLUGIN_MODIFIERCOMPILER)
63
	 * @param Smarty_Internal_Template   $template    template object
0 ignored issues
show
Bug introduced by
The type neon\core\view\Smarty_Internal_Template was not found. Did you mean Smarty_Internal_Template? If so, make sure to prefix the type with \.
Loading history...
64
	 * @param string                     &$callback    returned function name
65
	 * @param string                     &$script    optional returned script filepath if function is external
66
	 * @param bool                       &$cacheable    true by default, set to false if plugin is not cachable (Smarty >= 3.1.8)
67
	 * @return bool                      true if successfull
68
	 */
69
	public function pluginHandler($name, $type, $template, &$callback, &$script, &$cacheable)
70
	{
71
		// if already registered and type is block then we need to unregister the name as a function and change to a block this is because:
72
		// smarty first encounters an unknown opening tag it calls this function and adds the callback as type function
73
		// then it discovers the closing tag {/tag_name} this time it calls the function again
74
		// registerFunction___$name - this function is handled by \neon\cms\components\Renderer::__callStatic($name, $args)
75
		// this then can get the information on the $name from the function.
76
		switch ($type) {
77
			case Smarty::PLUGIN_FUNCTION:
78
				if ($this->smarty->templateExists("$name.tpl")) {
79
					$callback = '\neon\cms\components\Renderer::registerFunction___'.$name;
80
					$cacheable = false;
81
					return true;
82
				}
83
				return false;
84
			case Smarty::PLUGIN_BLOCK:
85
				$callback = '\neon\cms\components\Renderer::registerBlock___'.$name;
86
				$cacheable = false;
87
				return true;
88
			default:
89
				return false;
90
		}
91
	}
92
93
	/**
94
	 * Smarty template function to get relative URL for using in links
95
	 *
96
	 * Usage is the following:
97
	 *
98
	 * {path route='blog/view' alias=$post.alias user=$user.id}
99
	 *
100
	 * where route is Yii route and the rest of parameters are passed as is.
101
	 *
102
	 * @param array $params
103
	 * @param \Smarty_Internal_Template $template
104
	 *
105
	 * @return string
106
	 */
107
	public function functionPath($params, \Smarty_Internal_Template $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

107
	public function functionPath($params, /** @scrutinizer ignore-unused */ \Smarty_Internal_Template $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...
108
	{
109
		if (!isset($params['route'])) {
110
			trigger_error("path: missing 'route' parameter");
111
		}
112
113
		array_unshift($params, $params['route']) ;
114
		unset($params['route']);
115
116
		return Url::to($params);
117
	}
118
119
	/**
120
	 * Smarty compiler function plugin
121
	 * Usage is the following:
122
	 *
123
	 * {use class="app\assets\AppAsset"}
124
	 * {use class="yii\helpers\Html"}
125
	 * {use class='yii\widgets\ActiveForm' type='block'}
126
	 * {use class='@app\widgets\MyWidget' as='my_widget' type='function'}
127
	 *
128
	 * Supported attributes: class, as, type. Type defaults to 'static'.
129
	 *
130
	 * @param $params
131
	 * @param \Smarty_Internal_Template $template
132
	 * @return string
133
	 * @note Even though this method is public it should not be called directly.
134
	 */
135
	public function compilerUse($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

135
	public function compilerUse($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...
136
	{
137
		if (!isset($params['class'])) {
138
			trigger_error("use: missing 'class' parameter");
139
		}
140
		// Compiler plugin parameters may include quotes, so remove them
141
		foreach ($params as $key => $value) {
142
			$params[$key] = trim($value, '\'""');
143
		}
144
145
		$class = $params['class'];
146
		$alias = Arr::getValue($params, 'as', Str::basename($params['class']));
147
		$type = Arr::getValue($params, 'type', 'static');
148
149
		// Skip already registered block and function
150
		if (($type === 'block' || $type === 'function') && isset($this->smarty->registered_plugins[$type][$alias])) {
151
			return;
152
		}
153
154
		// Register the class during compile time
155
		$this->smarty->registerClass($alias, $class);
156
157
		if ($type === 'block') {
158
			// Register widget tag during compile time
159
			$this->viewRenderer->widgets['blocks'][$alias] = $class;
160
			$this->smarty->registerPlugin('block', $alias, [$this->viewRenderer, '_widget_block__' . $alias]);
161
162
			// Inject code to re-register widget tag during run-time
163
			return <<<PHP
164
<?php
165
    \$viewRenderer=\$_smarty_tpl->default_template_handler_func[0];
166
    \$viewRenderer->widgets['blocks']['$alias'] = '$class';
167
    try {
168
        \$_smarty_tpl->registerPlugin('block', '$alias', [\$viewRenderer, '_widget_block__$alias']);
169
    }
170
    catch (SmartyException \$e) {
171
        /* Ignore already registered exception during first execution after compilation */
172
    }
173
?>
174
PHP;
175
		} elseif ($type === 'function') {
176
			// Register widget tag during compile time
177
			$this->viewRenderer->widgets['functions'][$alias] = $class;
178
			$this->smarty->registerPlugin('function', $alias, [$this->viewRenderer, '_widget_function__' . $alias]);
179
180
			// Inject code to re-register widget tag during run-time
181
			return <<<PHP
182
<?php
183
    \$viewRenderer=\$_smarty_tpl->default_template_handler_func[0];
184
    \$viewRenderer->widgets['functions']['$alias'] = '$class';
185
    try {
186
        \$_smarty_tpl->registerPlugin('function', '$alias', [\$viewRenderer, '_widget_function__$alias']);
187
    }
188
    catch (SmartyException \$e) {
189
        /* Ignore already registered exception during first execution after compilation */
190
    }
191
?>
192
PHP;
193
		}
194
	}
195
196
	/**
197
	 * Smarty modifier plugin
198
	 * Converts any output to void
199
	 * @param mixed $arg
200
	 * @return string
201
	 * @note Even though this method is public it should not be called directly.
202
	 */
203
	public function modifierVoid($arg)
0 ignored issues
show
Unused Code introduced by
The parameter $arg 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

203
	public function modifierVoid(/** @scrutinizer ignore-unused */ $arg)

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...
204
	{
205
		return;
206
	}
207
208
	/**
209
	 * Smarty function plugin
210
	 * Usage is the following:
211
	 *
212
	 * {set title="My Page"}
213
	 * {set theme="frontend"}
214
	 * {set layout="main.tpl"}
215
	 *
216
	 * Supported attributes: title, theme, layout
217
	 *
218
	 * @param $params
219
	 * @param \Smarty_Internal_Template $template
220
	 * @return string
221
	 * @note Even though this method is public it should not be called directly.
222
	 */
223
	public function functionSet($params, $template)
224
	{
225
		if (isset($params['title'])) {
226
			$template->tpl_vars['this']->value->title = Yii::$app->getView()->title = Arr::remove($params, 'title');
227
		}
228
		if (isset($params['theme'])) {
229
			$template->tpl_vars['this']->value->theme = Yii::$app->getView()->theme = Arr::remove($params, 'theme');
230
		}
231
		if (isset($params['layout'])) {
232
			Yii::$app->controller->layout = Arr::remove($params, 'layout');
233
		}
234
235
		// We must have consumed all allowed parameters now, otherwise raise error
236
		if (!empty($params)) {
237
			trigger_error('set: Unsupported parameter attribute');
238
		}
239
	}
240
241
	/**
242
	 * Smarty function plugin
243
	 * Usage is the following:
244
	 *
245
	 * {meta keywords="Yii,PHP,Smarty,framework"}
246
	 *
247
	 * Supported attributes: any; all attributes are passed as
248
	 * parameter array to Yii's registerMetaTag function.
249
	 *
250
	 * @param $params
251
	 * @param \Smarty_Internal_Template $template
252
	 * @return string
253
	 * @note Even though this method is public it should not be called directly.
254
	 */
255
	public function functionMeta($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

255
	public function functionMeta($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...
256
	{
257
		$key = isset($params['name']) ? $params['name'] : null;
258
259
		Yii::$app->getView()->registerMetaTag($params, $key);
260
	}
261
262
	/**
263
	 * Smarty block function plugin
264
	 * Usage is the following:
265
	 *
266
	 * {title} Web Site Login {/title}
267
	 *
268
	 * Supported attributes: none.
269
	 *
270
	 * @param $params
271
	 * @param $content
272
	 * @param \Smarty_Internal_Template $template
273
	 * @param $repeat
274
	 * @return string
275
	 * @note Even though this method is public it should not be called directly.
276
	 */
277
	public function blockTitle($params, $content, $template, &$repeat)
0 ignored issues
show
Unused Code introduced by
The parameter $repeat 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

277
	public function blockTitle($params, $content, $template, /** @scrutinizer ignore-unused */ &$repeat)

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 $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

277
	public function blockTitle($params, $content, /** @scrutinizer ignore-unused */ $template, &$repeat)

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...
278
	{
279
		if ($content !== null) {
280
			Yii::$app->getView()->title = $content;
281
		}
282
	}
283
284
	/**
285
	 * Smarty block function plugin
286
	 * Usage is the following:
287
	 *
288
	 * {description}
289
	 *     The text between the opening and closing tags is added as
290
	 *     meta description tag to the page output.
291
	 * {/description}
292
	 *
293
	 * Supported attributes: none.
294
	 *
295
	 * @param $params
296
	 * @param $content
297
	 * @param \Smarty_Internal_Template $template
298
	 * @param $repeat
299
	 * @return string
300
	 * @note Even though this method is public it should not be called directly.
301
	 */
302
	public function blockDescription($params, $content, $template, &$repeat)
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

302
	public function blockDescription($params, $content, /** @scrutinizer ignore-unused */ $template, &$repeat)

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 $repeat 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

302
	public function blockDescription($params, $content, $template, /** @scrutinizer ignore-unused */ &$repeat)

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...
303
	{
304
		if ($content !== null) {
305
			// Clean-up whitespace and newlines
306
			$content = preg_replace('/\s+/', ' ', trim($content));
307
308
			Yii::$app->getView()->registerMetaTag(['name' => 'description',
309
				'content' => $content],
310
				'description');
311
		}
312
	}
313
314
	/**
315
	 * Helper function to convert a textual constant identifier to a View class
316
	 * integer constant value.
317
	 *
318
	 * @param string $string Constant identifier name
319
	 * @param integer $default Default value
320
	 * @return mixed
321
	 */
322
	protected function getViewConstVal($string, $default)
323
	{
324
		$val = @constant('yii\web\View::' . $string);
325
		return isset($val) ? $val : $default;
326
	}
327
}
328