Completed
Push — master ( bf2930...494091 )
by David
07:08 queued 03:26
created
lib/Dwoo/Adapters/ZendFramework/PluginProxy.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -46,7 +46,7 @@
 block discarded – undo
46 46
     /**
47 47
      * Dwoo_Adapters_ZendFramework_PluginProxy's constructor.
48 48
      *
49
-     * @param Zend_View_Interface $view
49
+     * @param Dwoo_Adapters_ZendFramework_View $view
50 50
      */
51 51
     public function __construct(Zend_View_Interface $view)
52 52
     {
Please login to merge, or discard this patch.
Indentation   +78 added lines, -78 removed lines patch added patch discarded remove patch
@@ -36,88 +36,88 @@
 block discarded – undo
36 36
  */
37 37
 class Dwoo_Adapters_ZendFramework_PluginProxy implements IPluginProxy
38 38
 {
39
-    /**
40
-     * reference to the zend view owning this proxy.
41
-     *
42
-     * @var Zend_View_Interface
43
-     */
44
-    public $view;
39
+	/**
40
+	 * reference to the zend view owning this proxy.
41
+	 *
42
+	 * @var Zend_View_Interface
43
+	 */
44
+	public $view;
45 45
 
46
-    /**
47
-     * Dwoo_Adapters_ZendFramework_PluginProxy's constructor.
48
-     *
49
-     * @param Zend_View_Interface $view
50
-     */
51
-    public function __construct(Zend_View_Interface $view)
52
-    {
53
-        $this->view = $view;
54
-    }
46
+	/**
47
+	 * Dwoo_Adapters_ZendFramework_PluginProxy's constructor.
48
+	 *
49
+	 * @param Zend_View_Interface $view
50
+	 */
51
+	public function __construct(Zend_View_Interface $view)
52
+	{
53
+		$this->view = $view;
54
+	}
55 55
 
56
-    /**
57
-     * Called from Dwoo_Compiler to check if the requested plugin is available.
58
-     *
59
-     * @param string $name
60
-     *
61
-     * @return bool
62
-     */
63
-    public function handles($name)
64
-    {
65
-        try {
66
-            $this->view->getHelper($name);
67
-        } catch (Zend_Loader_PluginLoader_Exception $e) {
68
-            return false;
69
-        }
56
+	/**
57
+	 * Called from Dwoo_Compiler to check if the requested plugin is available.
58
+	 *
59
+	 * @param string $name
60
+	 *
61
+	 * @return bool
62
+	 */
63
+	public function handles($name)
64
+	{
65
+		try {
66
+			$this->view->getHelper($name);
67
+		} catch (Zend_Loader_PluginLoader_Exception $e) {
68
+			return false;
69
+		}
70 70
 
71
-        return true;
72
-    }
71
+		return true;
72
+	}
73 73
 
74
-    /**
75
-     * returns the code (as a string) to call the plugin
76
-     * (this will be executed at runtime inside the Dwoo class).
77
-     *
78
-     * @param string $name   the plugin name
79
-     * @param array  $params a parameter array, array key "*" is the rest array
80
-     *
81
-     * @return string
82
-     */
83
-    public function getCode($name, $params)
84
-    {
85
-        return '$this->getPluginProxy()->view->'.$name.'('.Compiler::implode_r($params).')';
86
-    }
74
+	/**
75
+	 * returns the code (as a string) to call the plugin
76
+	 * (this will be executed at runtime inside the Dwoo class).
77
+	 *
78
+	 * @param string $name   the plugin name
79
+	 * @param array  $params a parameter array, array key "*" is the rest array
80
+	 *
81
+	 * @return string
82
+	 */
83
+	public function getCode($name, $params)
84
+	{
85
+		return '$this->getPluginProxy()->view->'.$name.'('.Compiler::implode_r($params).')';
86
+	}
87 87
 
88
-    /**
89
-     * returns a callback to the plugin, this is used with the reflection API to
90
-     * find out about the plugin's parameter names etc.
91
-     *
92
-     * should you need a rest array (i.e. for ZendFramework helpers) without the
93
-     * possibility to edit the plugin's code, you can provide a callback to some
94
-     * other function with the correct parameter signature, i.e. :
95
-     * <code>
96
-     * return array($this, "callbackHelper");
97
-     * // and callbackHelper would be as such:
98
-     * public function callbackHelper(array $rest=array()){}
99
-     * </code>
100
-     *
101
-     * @param string $name the plugin name
102
-     *
103
-     * @return callback
104
-     */
105
-    public function getCallback($name)
106
-    {
107
-        return array($this->view->getHelper($name), $name);
108
-    }
88
+	/**
89
+	 * returns a callback to the plugin, this is used with the reflection API to
90
+	 * find out about the plugin's parameter names etc.
91
+	 *
92
+	 * should you need a rest array (i.e. for ZendFramework helpers) without the
93
+	 * possibility to edit the plugin's code, you can provide a callback to some
94
+	 * other function with the correct parameter signature, i.e. :
95
+	 * <code>
96
+	 * return array($this, "callbackHelper");
97
+	 * // and callbackHelper would be as such:
98
+	 * public function callbackHelper(array $rest=array()){}
99
+	 * </code>
100
+	 *
101
+	 * @param string $name the plugin name
102
+	 *
103
+	 * @return callback
104
+	 */
105
+	public function getCallback($name)
106
+	{
107
+		return array($this->view->getHelper($name), $name);
108
+	}
109 109
 
110
-    /**
111
-     * returns some code that will check if the plugin is loaded and if not load it
112
-     * this is optional, if your plugins are autoloaded or whatever, just return an
113
-     * empty string.
114
-     *
115
-     * @param string $name the plugin name
116
-     *
117
-     * @return string
118
-     */
119
-    public function getLoader($name)
120
-    {
121
-        return '';
122
-    }
110
+	/**
111
+	 * returns some code that will check if the plugin is loaded and if not load it
112
+	 * this is optional, if your plugins are autoloaded or whatever, just return an
113
+	 * empty string.
114
+	 *
115
+	 * @param string $name the plugin name
116
+	 *
117
+	 * @return string
118
+	 */
119
+	public function getLoader($name)
120
+	{
121
+		return '';
122
+	}
123 123
 }
Please login to merge, or discard this patch.
lib/Dwoo/Adapters/ZendFramework/View.php 2 patches
Doc Comments   -2 removed lines patch added patch discarded remove patch
@@ -83,7 +83,6 @@  discard block
 block discarded – undo
83 83
      *  - type class name or object for engine, dataProvider or compiler
84 84
      *  - any set* method (compileDir for setCompileDir ...)
85 85
      *
86
-     * @param array $options
87 86
      *
88 87
      * @return Dwoo_Adapters_ZendFramework_View
89 88
      */
@@ -437,7 +436,6 @@  discard block
 block discarded – undo
437 436
      * Processes a view script and outputs it. Output is then
438 437
      * passed through filters.
439 438
      *
440
-     * @param string $name The script script name to process
441 439
      *
442 440
      * @return string The script output
443 441
      */
Please login to merge, or discard this patch.
Indentation   +503 added lines, -503 removed lines patch added patch discarded remove patch
@@ -16,507 +16,507 @@
 block discarded – undo
16 16
  */
17 17
 class Dwoo_Adapters_ZendFramework_View extends Zend_View_Abstract
18 18
 {
19
-    /**
20
-     * @var Core
21
-     */
22
-    protected $_engine = null;
23
-
24
-    /**
25
-     * @var Dwoo_Data
26
-     */
27
-    protected $_dataProvider = null;
28
-
29
-    /**
30
-     * @var Dwoo_Compiler
31
-     */
32
-    protected $_compiler = null;
33
-
34
-    /**
35
-     * Changing Filter's scope to play nicely.
36
-     *
37
-     * @var array
38
-     */
39
-    protected $_filter = array();
40
-
41
-    /**
42
-     * @var string
43
-     */
44
-    protected $_templateFileClass = 'Dwoo_Template_File';
45
-
46
-    /**
47
-     * @var array
48
-     */
49
-    protected $_templateFileSettings = array();
50
-
51
-    /**
52
-     * @var Dwoo_IPluginProxy
53
-     */
54
-    protected $_pluginProxy = null;
55
-
56
-    /**
57
-     * Constructor method.
58
-     * See setOptions for $opt details.
59
-     *
60
-     * @see setOptions
61
-     *
62
-     * @param array|Zend_Config List of options or Zend_Config instance
63
-     */
64
-    public function __construct($opt = array())
65
-    {
66
-        if (is_array($opt)) {
67
-            $this->setOptions($opt);
68
-        } elseif ($opt instanceof Zend_Config) {
69
-            $this->setConfig($opt);
70
-        }
71
-
72
-        $this->init();
73
-    }
74
-
75
-    /**
76
-     * Set object state from options array
77
-     *  - engine        = engine class name|engine object|array of options for engine
78
-     *  - dataProvider  = data provider class name|data provider object|array of options for data provider
79
-     *  - compiler      = compiler class name|compiler object|array of options for compiler
80
-     *  - templateFile  =.
81
-     *
82
-     *  Array of options:
83
-     *  - type class name or object for engine, dataProvider or compiler
84
-     *  - any set* method (compileDir for setCompileDir ...)
85
-     *
86
-     * @param array $options
87
-     *
88
-     * @return Dwoo_Adapters_ZendFramework_View
89
-     */
90
-    public function setOptions(array $opt = array())
91
-    {
92
-        // Making sure that everything is loaded.
93
-        $classes = array('engine', 'dataProvider', 'compiler');
94
-
95
-        // Setting options to Dwoo objects...
96
-        foreach ($opt as $type => $settings) {
97
-            if (!method_exists($this, 'set'.$type)) {
98
-                throw new Dwoo_Exception("Unknown type $type");
99
-            }
100
-
101
-            if (is_string($settings) || is_object($settings)) {
102
-                call_user_func(array($this, 'set'.$type), $settings);
103
-            } elseif (is_array($settings)) {
104
-                // Set requested class
105
-                if (array_key_exists('type', $settings)) {
106
-                    call_user_func(array($this, 'set'.$type), $settings['type']);
107
-                }
108
-
109
-                if (in_array($type, $classes)) {
110
-                    // Call get so that the class is initialized
111
-                    $rel = call_user_func(array($this, 'get'.$type));
112
-
113
-                    // Call set*() methods so that all the settings are set.
114
-                    foreach ($settings as $method => $value) {
115
-                        if (method_exists($rel, 'set'.$method)) {
116
-                            call_user_func(array($rel, 'set'.$method), $value);
117
-                        }
118
-                    }
119
-                } elseif ('templateFile' == $type) {
120
-                    // Remember the settings for the templateFile
121
-                    $this->_templateFileSettings = $settings;
122
-                }
123
-            }
124
-        }
125
-    }
126
-
127
-    /**
128
-     * Set object state from Zend_Config object.
129
-     *
130
-     * @param Zend_Config $config
131
-     *
132
-     * @return Dwoo_Adapters_ZendFramework_View
133
-     */
134
-    public function setConfig(Zend_Config $config)
135
-    {
136
-        return $this->setOptions($config->toArray());
137
-    }
138
-
139
-    /**
140
-     * Called before template rendering.
141
-     *
142
-     * Binds plugin proxy to the Dwoo.
143
-     *
144
-     * @see Dwoo_Adapters_ZendFramework_View::getPluginProxy();
145
-     * @see Dwoo_Core::setPluginProxy();
146
-     */
147
-    protected function preRender()
148
-    {
149
-        $this->getEngine()->setPluginProxy($this->getPluginProxy());
150
-    }
151
-
152
-    /**
153
-     * Wraper for Dwoo_Data::__set()
154
-     * allows to assign variables using the object syntax.
155
-     *
156
-     * @see Dwoo_Data::__set()
157
-     *
158
-     * @param string $name  the variable name
159
-     * @param string $value the value to assign to it
160
-     */
161
-    public function __set($name, $value)
162
-    {
163
-        $this->getDataProvider()->__set($name, $value);
164
-    }
165
-
166
-    /**
167
-     * Sraper for Dwoo_Data::__get() allows to read variables using the object
168
-     * syntax.
169
-     *
170
-     * @see Dwoo_Data::__get()
171
-     *
172
-     * @param string $name the variable name
173
-     *
174
-     * @return mixed
175
-     */
176
-    public function __get($name)
177
-    {
178
-        return $this->getDataProvider()->__get($name);
179
-    }
180
-
181
-    /**
182
-     * Wraper for Dwoo_Data::__isset()
183
-     * supports calls to isset($dwooData->var).
184
-     *
185
-     * @see Dwoo_Data::__isset()
186
-     *
187
-     * @param string $name the variable name
188
-     */
189
-    public function __isset($name)
190
-    {
191
-        return $this->getDataProvider()->__isset($name);
192
-    }
193
-
194
-    /**
195
-     * Wraper for Dwoo_Data::_unset()
196
-     * supports unsetting variables using the object syntax.
197
-     *
198
-     * @see Dwoo_Data::__unset()
199
-     *
200
-     * @param string $name the variable name
201
-     */
202
-    public function __unset($name)
203
-    {
204
-        $this->getDataProvider()->__unset($name);
205
-    }
206
-
207
-    /**
208
-     * Catches clone request and clones data provider.
209
-     */
210
-    public function __clone()
211
-    {
212
-        $this->setDataProvider(clone $this->getDataProvider());
213
-    }
214
-
215
-    /**
216
-     * Returns plugin proxy interface.
217
-     *
218
-     * @return Dwoo_IPluginProxy
219
-     */
220
-    public function getPluginProxy()
221
-    {
222
-        if (!$this->_pluginProxy) {
223
-            $this->_pluginProxy = new Dwoo_Adapters_ZendFramework_PluginProxy($this);
224
-        }
225
-
226
-        return $this->_pluginProxy;
227
-    }
228
-
229
-    /**
230
-     * Sets plugin proxy.
231
-     *
232
-     * @param Dwoo_IPluginProxy
233
-     *
234
-     * @return Dwoo_Adapters_ZendFramework_View
235
-     */
236
-    public function setPluginProxy(Dwoo_IPluginProxy $pluginProxy)
237
-    {
238
-        $this->_pluginProxy = $pluginProxy;
239
-
240
-        return $this;
241
-    }
242
-
243
-    /**
244
-     * Sets template engine.
245
-     *
246
-     * @param string|Dwoo Object or name of the class
247
-     */
248
-    public function setEngine($engine)
249
-    {
250
-        // if param given as an object
251
-        if ($engine instanceof Dwoo_Core) {
252
-            $this->_engine = $engine;
253
-        } elseif (is_subclass_of($engine, 'Dwoo') || 'Dwoo' === $engine) {
254
-            $this->_engine = new $engine();
255
-        } else {
256
-            throw new Dwoo_Exception('Custom engine must be a subclass of Dwoo');
257
-        }
258
-    }
259
-
260
-    /**
261
-     * Return the Dwoo template engine object.
262
-     *
263
-     * @return Dwoo
264
-     */
265
-    public function getEngine()
266
-    {
267
-        if (null === $this->_engine) {
268
-            $this->_engine = new Dwoo_Adapters_ZendFramework_Dwoo();
269
-        }
270
-
271
-        return $this->_engine;
272
-    }
273
-
274
-    /**
275
-     * Sets Dwoo data object.
276
-     *
277
-     * @param string|Dwoo_Data Object or name of the class
278
-     */
279
-    public function setDataProvider($data)
280
-    {
281
-        if ($data instanceof Dwoo_IDataProvider) {
282
-            $this->_dataProvider = $data;
283
-        } elseif (is_subclass_of($data, 'Dwoo_Data') || 'Dwoo_Data' == $data) {
284
-            $this->_dataProvider = new $data();
285
-        } else {
286
-            throw new Dwoo_Exception('Custom data provider must be a subclass of Dwoo_Data or instance of Dwoo_IDataProvider');
287
-        }
288
-    }
289
-
290
-    /**
291
-     * Return the Dwoo data object.
292
-     *
293
-     * @return Dwoo_Data
294
-     */
295
-    public function getDataProvider()
296
-    {
297
-        if (null === $this->_dataProvider) {
298
-            $this->_dataProvider = new Dwoo_Data();
299
-
300
-            // Satisfy Zend_View_Abstract wishes to access this unexisting property
301
-            // by setting it to empty array (see Zend_View_Abstract::_filter)
302
-            $this->_dataProvider->_filter = array();
303
-        }
304
-
305
-        return $this->_dataProvider;
306
-    }
307
-
308
-    /**
309
-     * Sets Dwoo compiler.
310
-     *
311
-     * @param string|Dwoo_Compiler Object or name of the class
312
-     */
313
-    public function setCompiler($compiler)
314
-    {
315
-
316
-        // if param given as an object
317
-        if ($compiler instanceof Dwoo_ICompiler) {
318
-            $this->_compiler = $compiler;
319
-        }
320
-        // if param given as a string
321
-        elseif (is_subclass_of($compiler, 'Dwoo_Compiler') || 'Dwoo_Compiler' == $compiler) {
322
-            $this->_compiler = new $compiler();
323
-        } else {
324
-            throw new Dwoo_Exception('Custom compiler must be a subclass of Dwoo_Compiler or instance of Dwoo_ICompiler');
325
-        }
326
-    }
327
-
328
-    /**
329
-     * Return the Dwoo compiler object.
330
-     *
331
-     * @return Dwoo_Compiler
332
-     */
333
-    public function getCompiler()
334
-    {
335
-        if (null === $this->_compiler) {
336
-            $this->_compiler = Dwoo_Compiler::compilerFactory();
337
-        }
338
-
339
-        return $this->_compiler;
340
-    }
341
-
342
-    /**
343
-     * Initializes Dwoo_ITemplate type of class and sets properties from _templateFileSettings.
344
-     *
345
-     * @param string Dwoo_ITemplate $template
346
-     *
347
-     * @return Dwoo_ITemplate
348
-     */
349
-    public function getTemplateFile($template)
350
-    {
351
-        $templateFileClass = $this->_templateFileClass;
352
-
353
-        $dwooTemplateFile = new $templateFileClass($template);
354
-
355
-        if (!($dwooTemplateFile instanceof Dwoo_ITemplate)) {
356
-            throw new Dwoo_Exception('Custom templateFile class must be a subclass of Dwoo_ITemplate');
357
-        }
358
-
359
-        foreach ($this->_templateFileSettings as $method => $value) {
360
-            if (method_exists($dwooTemplateFile, 'set'.$method)) {
361
-                call_user_func(array($dwooTemplateFile, 'set'.$method), $value);
362
-            }
363
-        }
364
-
365
-        return $dwooTemplateFile;
366
-    }
367
-
368
-    /**
369
-     * Dwoo_ITemplate type of class.
370
-     *
371
-     * @param string Name of the class
372
-     */
373
-    public function setTemplateFile($tempateFileClass)
374
-    {
375
-        $this->_templateFileClass = $tempateFileClass;
376
-    }
377
-
378
-    /**
379
-     * Passes data to Dwoo_Data object.
380
-     *
381
-     * @see Dwoo_Data::assign()
382
-     *
383
-     * @param array|string $name
384
-     * @param mixed        $val
385
-     *
386
-     * @return Dwoo_Adapters_ZendFramework_View
387
-     */
388
-    public function assign($name, $val = null)
389
-    {
390
-        $this->getDataProvider()->assign($name, $val);
391
-
392
-        return $this;
393
-    }
394
-
395
-    /**
396
-     * Return list of all assigned variables.
397
-     *
398
-     * @return array
399
-     */
400
-    public function getVars()
401
-    {
402
-        return $this->getDataProvider()->getData();
403
-    }
404
-
405
-    /**
406
-     * Clear all assigned variables.
407
-     *
408
-     * Clears all variables assigned to Zend_View either via {@link assign()} or
409
-     * property overloading ({@link __get()}/{@link __set()}).
410
-     *
411
-     * @return Dwoo_Adapters_ZendFramework_View
412
-     */
413
-    public function clearVars()
414
-    {
415
-        $this->getDataProvider()->clear();
416
-
417
-        return $this;
418
-    }
419
-
420
-    /**
421
-     * Wraper for parent's render method so preRender method
422
-     * can be called (that will bind the plugin proxy to the
423
-     * engine.
424
-     *
425
-     * @see Zend_View_Abstract::render
426
-     *
427
-     * @return string The script output
428
-     */
429
-    public function render($name)
430
-    {
431
-        $this->preRender();
432
-
433
-        return parent::render($name);
434
-    }
435
-
436
-    /**
437
-     * Processes a view script and outputs it. Output is then
438
-     * passed through filters.
439
-     *
440
-     * @param string $name The script script name to process
441
-     *
442
-     * @return string The script output
443
-     */
444
-    public function _run()
445
-    {
446
-        echo $this->_engine->get(
447
-            $this->getTemplateFile(func_get_arg(0)),
448
-            $this->getDataProvider(),
449
-            $this->getCompiler()
450
-        );
451
-    }
452
-
453
-    /**
454
-     * Add plugin path.
455
-     *
456
-     * @param string $dir Directory
457
-     *
458
-     * @return Dwoo_Adapters_ZendFramework_View
459
-     */
460
-    public function addPluginDir($dir)
461
-    {
462
-        $this->getEngine()->getLoader()->addDirectory($dir);
463
-
464
-        return $this;
465
-    }
466
-
467
-    /**
468
-     * Set compile path.
469
-     *
470
-     * @param string $dir Directory
471
-     *
472
-     * @return Dwoo_Adapters_ZendFramework_View
473
-     */
474
-    public function setCompileDir($dir)
475
-    {
476
-        $this->getEngine()->setCompileDir($dir);
477
-
478
-        return $this;
479
-    }
480
-
481
-    /**
482
-     * Set cache path.
483
-     *
484
-     * @param string $dir Directory
485
-     *
486
-     * @return Dwoo_Adapters_ZendFramework_View
487
-     */
488
-    public function setCacheDir($dir)
489
-    {
490
-        $this->getEngine()->setCacheDir($dir);
491
-
492
-        return $this;
493
-    }
494
-
495
-    /**
496
-     * Set cache lifetime.
497
-     *
498
-     * @param string $seconds Lifetime in seconds
499
-     *
500
-     * @return Dwoo_Adapters_ZendFramework_View
501
-     */
502
-    public function setCacheLifetime($seconds)
503
-    {
504
-        $this->getEngine()->setCacheTime($seconds);
505
-
506
-        return $this;
507
-    }
508
-
509
-    /**
510
-     * Set charset.
511
-     *
512
-     * @param string $charset
513
-     *
514
-     * @return Dwoo_Adapters_ZendFramework_View
515
-     */
516
-    public function setCharset($charset)
517
-    {
518
-        $this->_engine->setCharset($charset);
519
-
520
-        return $this;
521
-    }
19
+	/**
20
+	 * @var Core
21
+	 */
22
+	protected $_engine = null;
23
+
24
+	/**
25
+	 * @var Dwoo_Data
26
+	 */
27
+	protected $_dataProvider = null;
28
+
29
+	/**
30
+	 * @var Dwoo_Compiler
31
+	 */
32
+	protected $_compiler = null;
33
+
34
+	/**
35
+	 * Changing Filter's scope to play nicely.
36
+	 *
37
+	 * @var array
38
+	 */
39
+	protected $_filter = array();
40
+
41
+	/**
42
+	 * @var string
43
+	 */
44
+	protected $_templateFileClass = 'Dwoo_Template_File';
45
+
46
+	/**
47
+	 * @var array
48
+	 */
49
+	protected $_templateFileSettings = array();
50
+
51
+	/**
52
+	 * @var Dwoo_IPluginProxy
53
+	 */
54
+	protected $_pluginProxy = null;
55
+
56
+	/**
57
+	 * Constructor method.
58
+	 * See setOptions for $opt details.
59
+	 *
60
+	 * @see setOptions
61
+	 *
62
+	 * @param array|Zend_Config List of options or Zend_Config instance
63
+	 */
64
+	public function __construct($opt = array())
65
+	{
66
+		if (is_array($opt)) {
67
+			$this->setOptions($opt);
68
+		} elseif ($opt instanceof Zend_Config) {
69
+			$this->setConfig($opt);
70
+		}
71
+
72
+		$this->init();
73
+	}
74
+
75
+	/**
76
+	 * Set object state from options array
77
+	 *  - engine        = engine class name|engine object|array of options for engine
78
+	 *  - dataProvider  = data provider class name|data provider object|array of options for data provider
79
+	 *  - compiler      = compiler class name|compiler object|array of options for compiler
80
+	 *  - templateFile  =.
81
+	 *
82
+	 *  Array of options:
83
+	 *  - type class name or object for engine, dataProvider or compiler
84
+	 *  - any set* method (compileDir for setCompileDir ...)
85
+	 *
86
+	 * @param array $options
87
+	 *
88
+	 * @return Dwoo_Adapters_ZendFramework_View
89
+	 */
90
+	public function setOptions(array $opt = array())
91
+	{
92
+		// Making sure that everything is loaded.
93
+		$classes = array('engine', 'dataProvider', 'compiler');
94
+
95
+		// Setting options to Dwoo objects...
96
+		foreach ($opt as $type => $settings) {
97
+			if (!method_exists($this, 'set'.$type)) {
98
+				throw new Dwoo_Exception("Unknown type $type");
99
+			}
100
+
101
+			if (is_string($settings) || is_object($settings)) {
102
+				call_user_func(array($this, 'set'.$type), $settings);
103
+			} elseif (is_array($settings)) {
104
+				// Set requested class
105
+				if (array_key_exists('type', $settings)) {
106
+					call_user_func(array($this, 'set'.$type), $settings['type']);
107
+				}
108
+
109
+				if (in_array($type, $classes)) {
110
+					// Call get so that the class is initialized
111
+					$rel = call_user_func(array($this, 'get'.$type));
112
+
113
+					// Call set*() methods so that all the settings are set.
114
+					foreach ($settings as $method => $value) {
115
+						if (method_exists($rel, 'set'.$method)) {
116
+							call_user_func(array($rel, 'set'.$method), $value);
117
+						}
118
+					}
119
+				} elseif ('templateFile' == $type) {
120
+					// Remember the settings for the templateFile
121
+					$this->_templateFileSettings = $settings;
122
+				}
123
+			}
124
+		}
125
+	}
126
+
127
+	/**
128
+	 * Set object state from Zend_Config object.
129
+	 *
130
+	 * @param Zend_Config $config
131
+	 *
132
+	 * @return Dwoo_Adapters_ZendFramework_View
133
+	 */
134
+	public function setConfig(Zend_Config $config)
135
+	{
136
+		return $this->setOptions($config->toArray());
137
+	}
138
+
139
+	/**
140
+	 * Called before template rendering.
141
+	 *
142
+	 * Binds plugin proxy to the Dwoo.
143
+	 *
144
+	 * @see Dwoo_Adapters_ZendFramework_View::getPluginProxy();
145
+	 * @see Dwoo_Core::setPluginProxy();
146
+	 */
147
+	protected function preRender()
148
+	{
149
+		$this->getEngine()->setPluginProxy($this->getPluginProxy());
150
+	}
151
+
152
+	/**
153
+	 * Wraper for Dwoo_Data::__set()
154
+	 * allows to assign variables using the object syntax.
155
+	 *
156
+	 * @see Dwoo_Data::__set()
157
+	 *
158
+	 * @param string $name  the variable name
159
+	 * @param string $value the value to assign to it
160
+	 */
161
+	public function __set($name, $value)
162
+	{
163
+		$this->getDataProvider()->__set($name, $value);
164
+	}
165
+
166
+	/**
167
+	 * Sraper for Dwoo_Data::__get() allows to read variables using the object
168
+	 * syntax.
169
+	 *
170
+	 * @see Dwoo_Data::__get()
171
+	 *
172
+	 * @param string $name the variable name
173
+	 *
174
+	 * @return mixed
175
+	 */
176
+	public function __get($name)
177
+	{
178
+		return $this->getDataProvider()->__get($name);
179
+	}
180
+
181
+	/**
182
+	 * Wraper for Dwoo_Data::__isset()
183
+	 * supports calls to isset($dwooData->var).
184
+	 *
185
+	 * @see Dwoo_Data::__isset()
186
+	 *
187
+	 * @param string $name the variable name
188
+	 */
189
+	public function __isset($name)
190
+	{
191
+		return $this->getDataProvider()->__isset($name);
192
+	}
193
+
194
+	/**
195
+	 * Wraper for Dwoo_Data::_unset()
196
+	 * supports unsetting variables using the object syntax.
197
+	 *
198
+	 * @see Dwoo_Data::__unset()
199
+	 *
200
+	 * @param string $name the variable name
201
+	 */
202
+	public function __unset($name)
203
+	{
204
+		$this->getDataProvider()->__unset($name);
205
+	}
206
+
207
+	/**
208
+	 * Catches clone request and clones data provider.
209
+	 */
210
+	public function __clone()
211
+	{
212
+		$this->setDataProvider(clone $this->getDataProvider());
213
+	}
214
+
215
+	/**
216
+	 * Returns plugin proxy interface.
217
+	 *
218
+	 * @return Dwoo_IPluginProxy
219
+	 */
220
+	public function getPluginProxy()
221
+	{
222
+		if (!$this->_pluginProxy) {
223
+			$this->_pluginProxy = new Dwoo_Adapters_ZendFramework_PluginProxy($this);
224
+		}
225
+
226
+		return $this->_pluginProxy;
227
+	}
228
+
229
+	/**
230
+	 * Sets plugin proxy.
231
+	 *
232
+	 * @param Dwoo_IPluginProxy
233
+	 *
234
+	 * @return Dwoo_Adapters_ZendFramework_View
235
+	 */
236
+	public function setPluginProxy(Dwoo_IPluginProxy $pluginProxy)
237
+	{
238
+		$this->_pluginProxy = $pluginProxy;
239
+
240
+		return $this;
241
+	}
242
+
243
+	/**
244
+	 * Sets template engine.
245
+	 *
246
+	 * @param string|Dwoo Object or name of the class
247
+	 */
248
+	public function setEngine($engine)
249
+	{
250
+		// if param given as an object
251
+		if ($engine instanceof Dwoo_Core) {
252
+			$this->_engine = $engine;
253
+		} elseif (is_subclass_of($engine, 'Dwoo') || 'Dwoo' === $engine) {
254
+			$this->_engine = new $engine();
255
+		} else {
256
+			throw new Dwoo_Exception('Custom engine must be a subclass of Dwoo');
257
+		}
258
+	}
259
+
260
+	/**
261
+	 * Return the Dwoo template engine object.
262
+	 *
263
+	 * @return Dwoo
264
+	 */
265
+	public function getEngine()
266
+	{
267
+		if (null === $this->_engine) {
268
+			$this->_engine = new Dwoo_Adapters_ZendFramework_Dwoo();
269
+		}
270
+
271
+		return $this->_engine;
272
+	}
273
+
274
+	/**
275
+	 * Sets Dwoo data object.
276
+	 *
277
+	 * @param string|Dwoo_Data Object or name of the class
278
+	 */
279
+	public function setDataProvider($data)
280
+	{
281
+		if ($data instanceof Dwoo_IDataProvider) {
282
+			$this->_dataProvider = $data;
283
+		} elseif (is_subclass_of($data, 'Dwoo_Data') || 'Dwoo_Data' == $data) {
284
+			$this->_dataProvider = new $data();
285
+		} else {
286
+			throw new Dwoo_Exception('Custom data provider must be a subclass of Dwoo_Data or instance of Dwoo_IDataProvider');
287
+		}
288
+	}
289
+
290
+	/**
291
+	 * Return the Dwoo data object.
292
+	 *
293
+	 * @return Dwoo_Data
294
+	 */
295
+	public function getDataProvider()
296
+	{
297
+		if (null === $this->_dataProvider) {
298
+			$this->_dataProvider = new Dwoo_Data();
299
+
300
+			// Satisfy Zend_View_Abstract wishes to access this unexisting property
301
+			// by setting it to empty array (see Zend_View_Abstract::_filter)
302
+			$this->_dataProvider->_filter = array();
303
+		}
304
+
305
+		return $this->_dataProvider;
306
+	}
307
+
308
+	/**
309
+	 * Sets Dwoo compiler.
310
+	 *
311
+	 * @param string|Dwoo_Compiler Object or name of the class
312
+	 */
313
+	public function setCompiler($compiler)
314
+	{
315
+
316
+		// if param given as an object
317
+		if ($compiler instanceof Dwoo_ICompiler) {
318
+			$this->_compiler = $compiler;
319
+		}
320
+		// if param given as a string
321
+		elseif (is_subclass_of($compiler, 'Dwoo_Compiler') || 'Dwoo_Compiler' == $compiler) {
322
+			$this->_compiler = new $compiler();
323
+		} else {
324
+			throw new Dwoo_Exception('Custom compiler must be a subclass of Dwoo_Compiler or instance of Dwoo_ICompiler');
325
+		}
326
+	}
327
+
328
+	/**
329
+	 * Return the Dwoo compiler object.
330
+	 *
331
+	 * @return Dwoo_Compiler
332
+	 */
333
+	public function getCompiler()
334
+	{
335
+		if (null === $this->_compiler) {
336
+			$this->_compiler = Dwoo_Compiler::compilerFactory();
337
+		}
338
+
339
+		return $this->_compiler;
340
+	}
341
+
342
+	/**
343
+	 * Initializes Dwoo_ITemplate type of class and sets properties from _templateFileSettings.
344
+	 *
345
+	 * @param string Dwoo_ITemplate $template
346
+	 *
347
+	 * @return Dwoo_ITemplate
348
+	 */
349
+	public function getTemplateFile($template)
350
+	{
351
+		$templateFileClass = $this->_templateFileClass;
352
+
353
+		$dwooTemplateFile = new $templateFileClass($template);
354
+
355
+		if (!($dwooTemplateFile instanceof Dwoo_ITemplate)) {
356
+			throw new Dwoo_Exception('Custom templateFile class must be a subclass of Dwoo_ITemplate');
357
+		}
358
+
359
+		foreach ($this->_templateFileSettings as $method => $value) {
360
+			if (method_exists($dwooTemplateFile, 'set'.$method)) {
361
+				call_user_func(array($dwooTemplateFile, 'set'.$method), $value);
362
+			}
363
+		}
364
+
365
+		return $dwooTemplateFile;
366
+	}
367
+
368
+	/**
369
+	 * Dwoo_ITemplate type of class.
370
+	 *
371
+	 * @param string Name of the class
372
+	 */
373
+	public function setTemplateFile($tempateFileClass)
374
+	{
375
+		$this->_templateFileClass = $tempateFileClass;
376
+	}
377
+
378
+	/**
379
+	 * Passes data to Dwoo_Data object.
380
+	 *
381
+	 * @see Dwoo_Data::assign()
382
+	 *
383
+	 * @param array|string $name
384
+	 * @param mixed        $val
385
+	 *
386
+	 * @return Dwoo_Adapters_ZendFramework_View
387
+	 */
388
+	public function assign($name, $val = null)
389
+	{
390
+		$this->getDataProvider()->assign($name, $val);
391
+
392
+		return $this;
393
+	}
394
+
395
+	/**
396
+	 * Return list of all assigned variables.
397
+	 *
398
+	 * @return array
399
+	 */
400
+	public function getVars()
401
+	{
402
+		return $this->getDataProvider()->getData();
403
+	}
404
+
405
+	/**
406
+	 * Clear all assigned variables.
407
+	 *
408
+	 * Clears all variables assigned to Zend_View either via {@link assign()} or
409
+	 * property overloading ({@link __get()}/{@link __set()}).
410
+	 *
411
+	 * @return Dwoo_Adapters_ZendFramework_View
412
+	 */
413
+	public function clearVars()
414
+	{
415
+		$this->getDataProvider()->clear();
416
+
417
+		return $this;
418
+	}
419
+
420
+	/**
421
+	 * Wraper for parent's render method so preRender method
422
+	 * can be called (that will bind the plugin proxy to the
423
+	 * engine.
424
+	 *
425
+	 * @see Zend_View_Abstract::render
426
+	 *
427
+	 * @return string The script output
428
+	 */
429
+	public function render($name)
430
+	{
431
+		$this->preRender();
432
+
433
+		return parent::render($name);
434
+	}
435
+
436
+	/**
437
+	 * Processes a view script and outputs it. Output is then
438
+	 * passed through filters.
439
+	 *
440
+	 * @param string $name The script script name to process
441
+	 *
442
+	 * @return string The script output
443
+	 */
444
+	public function _run()
445
+	{
446
+		echo $this->_engine->get(
447
+			$this->getTemplateFile(func_get_arg(0)),
448
+			$this->getDataProvider(),
449
+			$this->getCompiler()
450
+		);
451
+	}
452
+
453
+	/**
454
+	 * Add plugin path.
455
+	 *
456
+	 * @param string $dir Directory
457
+	 *
458
+	 * @return Dwoo_Adapters_ZendFramework_View
459
+	 */
460
+	public function addPluginDir($dir)
461
+	{
462
+		$this->getEngine()->getLoader()->addDirectory($dir);
463
+
464
+		return $this;
465
+	}
466
+
467
+	/**
468
+	 * Set compile path.
469
+	 *
470
+	 * @param string $dir Directory
471
+	 *
472
+	 * @return Dwoo_Adapters_ZendFramework_View
473
+	 */
474
+	public function setCompileDir($dir)
475
+	{
476
+		$this->getEngine()->setCompileDir($dir);
477
+
478
+		return $this;
479
+	}
480
+
481
+	/**
482
+	 * Set cache path.
483
+	 *
484
+	 * @param string $dir Directory
485
+	 *
486
+	 * @return Dwoo_Adapters_ZendFramework_View
487
+	 */
488
+	public function setCacheDir($dir)
489
+	{
490
+		$this->getEngine()->setCacheDir($dir);
491
+
492
+		return $this;
493
+	}
494
+
495
+	/**
496
+	 * Set cache lifetime.
497
+	 *
498
+	 * @param string $seconds Lifetime in seconds
499
+	 *
500
+	 * @return Dwoo_Adapters_ZendFramework_View
501
+	 */
502
+	public function setCacheLifetime($seconds)
503
+	{
504
+		$this->getEngine()->setCacheTime($seconds);
505
+
506
+		return $this;
507
+	}
508
+
509
+	/**
510
+	 * Set charset.
511
+	 *
512
+	 * @param string $charset
513
+	 *
514
+	 * @return Dwoo_Adapters_ZendFramework_View
515
+	 */
516
+	public function setCharset($charset)
517
+	{
518
+		$this->_engine->setCharset($charset);
519
+
520
+		return $this;
521
+	}
522 522
 }
Please login to merge, or discard this patch.
lib/Dwoo/Compiler.php 2 patches
Doc Comments   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -277,7 +277,7 @@  discard block
 block discarded – undo
277 277
     /**
278 278
      * Returns the left and right template delimiters.
279 279
      *
280
-     * @return array containing the left and the right delimiters
280
+     * @return string[] containing the left and the right delimiters
281 281
      */
282 282
     public function getDelimiters()
283 283
     {
@@ -362,7 +362,7 @@  discard block
 block discarded – undo
362 362
      * Adds a preprocessor to the compiler, it will be called
363 363
      * before the template is compiled.
364 364
      *
365
-     * @param mixed $callback either a valid callback to the preprocessor or a simple name if the autoload is set to
365
+     * @param string $callback either a valid callback to the preprocessor or a simple name if the autoload is set to
366 366
      *                        true
367 367
      * @param bool  $autoload if set to true, the preprocessor is auto-loaded from one of the plugin directories, else
368 368
      *                        you must provide a valid callback
@@ -1321,7 +1321,7 @@  discard block
 block discarded – undo
1321 1321
      *
1322 1322
      * @param array $params parameter array
1323 1323
      *
1324
-     * @return array tokens
1324
+     * @return Compiler tokens
1325 1325
      */
1326 1326
     public function getParamTokens(array $params)
1327 1327
     {
Please login to merge, or discard this patch.
Indentation   +3599 added lines, -3599 removed lines patch added patch discarded remove patch
@@ -31,3605 +31,3605 @@
 block discarded – undo
31 31
  */
32 32
 class Compiler implements ICompiler
33 33
 {
34
-    /**
35
-     * Constant that represents a php opening tag.
36
-     * use it in case it needs to be adjusted
37
-     *
38
-     * @var string
39
-     */
40
-    const PHP_OPEN = '<?php ';
41
-
42
-    /**
43
-     * Constant that represents a php closing tag.
44
-     * use it in case it needs to be adjusted
45
-     *
46
-     * @var string
47
-     */
48
-    const PHP_CLOSE = '?>';
49
-
50
-    /**
51
-     * Boolean flag to enable or disable debugging output.
52
-     *
53
-     * @var bool
54
-     */
55
-    public $debug = false;
56
-
57
-    /**
58
-     * Left script delimiter.
59
-     *
60
-     * @var string
61
-     */
62
-    protected $ld = '{';
63
-
64
-    /**
65
-     * Left script delimiter with escaped regex meta characters.
66
-     *
67
-     * @var string
68
-     */
69
-    protected $ldr = '\\{';
70
-
71
-    /**
72
-     * Right script delimiter.
73
-     *
74
-     * @var string
75
-     */
76
-    protected $rd = '}';
77
-
78
-    /**
79
-     * Right script delimiter with escaped regex meta characters.
80
-     *
81
-     * @var string
82
-     */
83
-    protected $rdr = '\\}';
84
-
85
-    /**
86
-     * Defines whether the nested comments should be parsed as nested or not.
87
-     * defaults to false (classic block comment parsing as in all languages)
88
-     *
89
-     * @var bool
90
-     */
91
-    protected $allowNestedComments = false;
92
-
93
-    /**
94
-     * Defines whether opening and closing tags can contain spaces before valid data or not.
95
-     * turn to true if you want to be sloppy with the syntax, but when set to false it allows
96
-     * to skip javascript and css tags as long as they are in the form "{ something", which is
97
-     * nice. default is false.
98
-     *
99
-     * @var bool
100
-     */
101
-    protected $allowLooseOpenings = false;
102
-
103
-    /**
104
-     * Defines whether the compiler will automatically html-escape variables or not.
105
-     * default is false
106
-     *
107
-     * @var bool
108
-     */
109
-    protected $autoEscape = false;
110
-
111
-    /**
112
-     * Security policy object.
113
-     *
114
-     * @var SecurityPolicy
115
-     */
116
-    protected $securityPolicy;
117
-
118
-    /**
119
-     * Stores the custom plugins registered with this compiler.
120
-     *
121
-     * @var array
122
-     */
123
-    protected $customPlugins = array();
124
-
125
-    /**
126
-     * Stores the template plugins registered with this compiler.
127
-     *
128
-     * @var array
129
-     */
130
-    protected $templatePlugins = array();
131
-
132
-    /**
133
-     * Stores the pre- and post-processors callbacks.
134
-     *
135
-     * @var array
136
-     */
137
-    protected $processors = array('pre' => array(), 'post' => array());
138
-
139
-    /**
140
-     * Stores a list of plugins that are used in the currently compiled
141
-     * template, and that are not compilable. these plugins will be loaded
142
-     * during the template's runtime if required.
143
-     * it is a 1D array formatted as key:pluginName value:pluginType
144
-     *
145
-     * @var array
146
-     */
147
-    protected $usedPlugins;
148
-
149
-    /**
150
-     * Stores the template undergoing compilation.
151
-     *
152
-     * @var string
153
-     */
154
-    protected $template;
155
-
156
-    /**
157
-     * Stores the current pointer position inside the template.
158
-     *
159
-     * @var int
160
-     */
161
-    protected $pointer;
162
-
163
-    /**
164
-     * Stores the current line count inside the template for debugging purposes.
165
-     *
166
-     * @var int
167
-     */
168
-    protected $line;
169
-
170
-    /**
171
-     * Stores the current template source while compiling it.
172
-     *
173
-     * @var string
174
-     */
175
-    protected $templateSource;
176
-
177
-    /**
178
-     * Stores the data within which the scope moves.
179
-     *
180
-     * @var array
181
-     */
182
-    protected $data;
183
-
184
-    /**
185
-     * Variable scope of the compiler, set to null if
186
-     * it can not be resolved to a static string (i.e. if some
187
-     * plugin defines a new scope based on a variable array key).
188
-     *
189
-     * @var mixed
190
-     */
191
-    protected $scope;
192
-
193
-    /**
194
-     * Variable scope tree, that allows to rebuild the current
195
-     * scope if required, i.e. when going to a parent level.
196
-     *
197
-     * @var array
198
-     */
199
-    protected $scopeTree;
200
-
201
-    /**
202
-     * Block plugins stack, accessible through some methods.
203
-     *
204
-     * @see findBlock
205
-     * @see getCurrentBlock
206
-     * @see addBlock
207
-     * @see addCustomBlock
208
-     * @see injectBlock
209
-     * @see removeBlock
210
-     * @see removeTopBlock
211
-     * @var array
212
-     */
213
-    protected $stack = array();
214
-
215
-    /**
216
-     * Current block at the top of the block plugins stack,
217
-     * accessible through getCurrentBlock.
218
-     *
219
-     * @see getCurrentBlock
220
-     * @var array
221
-     */
222
-    protected $curBlock;
223
-
224
-    /**
225
-     * Current dwoo object that uses this compiler, or null.
226
-     *
227
-     * @var Core
228
-     */
229
-    public $dwoo;
230
-
231
-    /**
232
-     * Holds an instance of this class, used by getInstance when you don't
233
-     * provide a custom compiler in order to save resources.
234
-     *
235
-     * @var Compiler
236
-     */
237
-    protected static $instance;
238
-
239
-    /**
240
-     * Token types.
241
-     *
242
-     * @var int
243
-     */
244
-    const T_UNQUOTED_STRING = 1;
245
-    const T_NUMERIC         = 2;
246
-    const T_NULL            = 4;
247
-    const T_BOOL            = 8;
248
-    const T_MATH            = 16;
249
-    const T_BREAKCHAR       = 32;
250
-
251
-    /**
252
-     * Compiler constructor.
253
-     * saves the created instance so that child templates get the same one
254
-     */
255
-    public function __construct()
256
-    {
257
-        self::$instance = $this;
258
-    }
259
-
260
-    /**
261
-     * Sets the delimiters to use in the templates.
262
-     * delimiters can be multi-character strings but should not be one of those as they will
263
-     * make it very hard to work with templates or might even break the compiler entirely : "\", "$", "|", ":" and
264
-     * finally "#" only if you intend to use config-vars with the #var# syntax.
265
-     *
266
-     * @param string $left  left delimiter
267
-     * @param string $right right delimiter
268
-     */
269
-    public function setDelimiters($left, $right)
270
-    {
271
-        $this->ld  = $left;
272
-        $this->rd  = $right;
273
-        $this->ldr = preg_quote($left, '/');
274
-        $this->rdr = preg_quote($right, '/');
275
-    }
276
-
277
-    /**
278
-     * Returns the left and right template delimiters.
279
-     *
280
-     * @return array containing the left and the right delimiters
281
-     */
282
-    public function getDelimiters()
283
-    {
284
-        return array($this->ld, $this->rd);
285
-    }
286
-
287
-    /**
288
-     * Sets the way to handle nested comments, if set to true
289
-     * {* foo {* some other *} comment *} will be stripped correctly.
290
-     * if false it will remove {* foo {* some other *} and leave "comment *}" alone,
291
-     * this is the default behavior
292
-     *
293
-     * @param bool $allow allow nested comments or not, defaults to true (but the default internal value is false)
294
-     */
295
-    public function setNestedCommentsHandling($allow = true)
296
-    {
297
-        $this->allowNestedComments = (bool)$allow;
298
-    }
299
-
300
-    /**
301
-     * Returns the nested comments handling setting.
302
-     *
303
-     * @see    setNestedCommentsHandling
304
-     * @return bool true if nested comments are allowed
305
-     */
306
-    public function getNestedCommentsHandling()
307
-    {
308
-        return $this->allowNestedComments;
309
-    }
310
-
311
-    /**
312
-     * Sets the tag openings handling strictness, if set to true, template tags can
313
-     * contain spaces before the first function/string/variable such as { $foo} is valid.
314
-     * if set to false (default setting), { $foo} is invalid but that is however a good thing
315
-     * as it allows css (i.e. #foo { color:red; }) to be parsed silently without triggering
316
-     * an error, same goes for javascript.
317
-     *
318
-     * @param bool $allow true to allow loose handling, false to restore default setting
319
-     */
320
-    public function setLooseOpeningHandling($allow = false)
321
-    {
322
-        $this->allowLooseOpenings = (bool)$allow;
323
-    }
324
-
325
-    /**
326
-     * Returns the tag openings handling strictness setting.
327
-     *
328
-     * @see    setLooseOpeningHandling
329
-     * @return bool true if loose tags are allowed
330
-     */
331
-    public function getLooseOpeningHandling()
332
-    {
333
-        return $this->allowLooseOpenings;
334
-    }
335
-
336
-    /**
337
-     * Changes the auto escape setting.
338
-     * if enabled, the compiler will automatically html-escape variables,
339
-     * unless they are passed through the safe function such as {$var|safe}
340
-     * or {safe $var}
341
-     * default setting is disabled/false
342
-     *
343
-     * @param bool $enabled set to true to enable, false to disable
344
-     */
345
-    public function setAutoEscape($enabled)
346
-    {
347
-        $this->autoEscape = (bool)$enabled;
348
-    }
349
-
350
-    /**
351
-     * Returns the auto escape setting.
352
-     * default setting is disabled/false
353
-     *
354
-     * @return bool
355
-     */
356
-    public function getAutoEscape()
357
-    {
358
-        return $this->autoEscape;
359
-    }
360
-
361
-    /**
362
-     * Adds a preprocessor to the compiler, it will be called
363
-     * before the template is compiled.
364
-     *
365
-     * @param mixed $callback either a valid callback to the preprocessor or a simple name if the autoload is set to
366
-     *                        true
367
-     * @param bool  $autoload if set to true, the preprocessor is auto-loaded from one of the plugin directories, else
368
-     *                        you must provide a valid callback
369
-     */
370
-    public function addPreProcessor($callback, $autoload = false)
371
-    {
372
-        if ($autoload) {
373
-            $name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', Core::toCamelCase($callback));
374
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . $name;
375
-
376
-            if (class_exists($class)) {
377
-                $callback = array(new $class($this), 'process');
378
-            } elseif (function_exists($class)) {
379
-                $callback = $class;
380
-            } else {
381
-                $callback = array('autoload' => true, 'class' => $class, 'name' => $name);
382
-            }
383
-
384
-            $this->processors['pre'][] = $callback;
385
-        } else {
386
-            $this->processors['pre'][] = $callback;
387
-        }
388
-    }
389
-
390
-    /**
391
-     * Removes a preprocessor from the compiler.
392
-     *
393
-     * @param mixed $callback either a valid callback to the preprocessor or a simple name if it was autoloaded
394
-     */
395
-    public function removePreProcessor($callback)
396
-    {
397
-        if (($index = array_search($callback, $this->processors['pre'], true)) !== false) {
398
-            unset($this->processors['pre'][$index]);
399
-        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
400
-                    $callback),
401
-                $this->processors['pre'], true)) !== false) {
402
-            unset($this->processors['pre'][$index]);
403
-        } else {
404
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
405
-            foreach ($this->processors['pre'] as $index => $proc) {
406
-                if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
407
-                    unset($this->processors['pre'][$index]);
408
-                    break;
409
-                }
410
-            }
411
-        }
412
-    }
413
-
414
-    /**
415
-     * Adds a postprocessor to the compiler, it will be called
416
-     * before the template is compiled.
417
-     *
418
-     * @param mixed $callback either a valid callback to the postprocessor or a simple name if the autoload is set to
419
-     *                        true
420
-     * @param bool  $autoload if set to true, the postprocessor is auto-loaded from one of the plugin directories, else
421
-     *                        you must provide a valid callback
422
-     */
423
-    public function addPostProcessor($callback, $autoload = false)
424
-    {
425
-        if ($autoload) {
426
-            $name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
427
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . Core::toCamelCase($name);
428
-
429
-            if (class_exists($class)) {
430
-                $callback = array(new $class($this), 'process');
431
-            } elseif (function_exists($class)) {
432
-                $callback = $class;
433
-            } else {
434
-                $callback = array('autoload' => true, 'class' => $class, 'name' => $name);
435
-            }
436
-
437
-            $this->processors['post'][] = $callback;
438
-        } else {
439
-            $this->processors['post'][] = $callback;
440
-        }
441
-    }
442
-
443
-    /**
444
-     * Removes a postprocessor from the compiler.
445
-     *
446
-     * @param mixed $callback either a valid callback to the postprocessor or a simple name if it was autoloaded
447
-     */
448
-    public function removePostProcessor($callback)
449
-    {
450
-        if (($index = array_search($callback, $this->processors['post'], true)) !== false) {
451
-            unset($this->processors['post'][$index]);
452
-        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
453
-                    $callback),
454
-                $this->processors['post'], true)) !== false) {
455
-            unset($this->processors['post'][$index]);
456
-        } else {
457
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
458
-            foreach ($this->processors['post'] as $index => $proc) {
459
-                if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
460
-                    unset($this->processors['post'][$index]);
461
-                    break;
462
-                }
463
-            }
464
-        }
465
-    }
466
-
467
-    /**
468
-     * Internal function to autoload processors at runtime if required.
469
-     *
470
-     * @param string $class the class/function name
471
-     * @param string $name  the plugin name (without Dwoo_Plugin_ prefix)
472
-     *
473
-     * @return array|string
474
-     * @throws Exception
475
-     */
476
-    protected function loadProcessor($class, $name)
477
-    {
478
-        if (!class_exists($class) && !function_exists($class)) {
479
-            try {
480
-                $this->getDwoo()->getLoader()->loadPlugin($name);
481
-            }
482
-            catch (Exception $e) {
483
-                throw new Exception('Processor ' . $name . ' could not be found in your plugin directories, please ensure it is in a file named ' . $name . '.php in the plugin directory');
484
-            }
485
-        }
486
-
487
-        if (class_exists($class)) {
488
-            return array(new $class($this), 'process');
489
-        }
490
-
491
-        if (function_exists($class)) {
492
-            return $class;
493
-        }
494
-
495
-        throw new Exception('Wrong processor name, when using autoload the processor must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Processor_name"');
496
-    }
497
-
498
-    /**
499
-     * Adds an used plugin, this is reserved for use by the {template} plugin.
500
-     * this is required so that plugin loading bubbles up from loaded
501
-     * template files to the current one
502
-     *
503
-     * @private
504
-     *
505
-     * @param string $name function name
506
-     * @param int    $type plugin type (Core::*_PLUGIN)
507
-     */
508
-    public function addUsedPlugin($name, $type)
509
-    {
510
-        $this->usedPlugins[$name] = $type;
511
-    }
512
-
513
-    /**
514
-     * Returns all the plugins this template uses.
515
-     *
516
-     * @private
517
-     * @return  array the list of used plugins in the parsed template
518
-     */
519
-    public function getUsedPlugins()
520
-    {
521
-        return $this->usedPlugins;
522
-    }
523
-
524
-    /**
525
-     * Adds a template plugin, this is reserved for use by the {template} plugin.
526
-     * this is required because the template functions are not declared yet
527
-     * during compilation, so we must have a way of validating their argument
528
-     * signature without using the reflection api
529
-     *
530
-     * @private
531
-     *
532
-     * @param string $name   function name
533
-     * @param array  $params parameter array to help validate the function call
534
-     * @param string $uuid   unique id of the function
535
-     * @param string $body   function php code
536
-     */
537
-    public function addTemplatePlugin($name, array $params, $uuid, $body = null)
538
-    {
539
-        $this->templatePlugins[$name] = array('params' => $params, 'body' => $body, 'uuid' => $uuid);
540
-    }
541
-
542
-    /**
543
-     * Returns all the parsed sub-templates.
544
-     *
545
-     * @private
546
-     * @return  array the parsed sub-templates
547
-     */
548
-    public function getTemplatePlugins()
549
-    {
550
-        return $this->templatePlugins;
551
-    }
552
-
553
-    /**
554
-     * Marks a template plugin as being called, which means its source must be included in the compiled template.
555
-     *
556
-     * @param string $name function name
557
-     */
558
-    public function useTemplatePlugin($name)
559
-    {
560
-        $this->templatePlugins[$name]['called'] = true;
561
-    }
562
-
563
-    /**
564
-     * Adds the custom plugins loaded into Dwoo to the compiler so it can load them.
565
-     *
566
-     * @see Core::addPlugin
567
-     *
568
-     * @param array $customPlugins an array of custom plugins
569
-     */
570
-    public function setCustomPlugins(array $customPlugins)
571
-    {
572
-        $this->customPlugins = $customPlugins;
573
-    }
574
-
575
-    /**
576
-     * Sets the security policy object to enforce some php security settings.
577
-     * use this if untrusted persons can modify templates,
578
-     * set it on the Dwoo object as it will be passed onto the compiler automatically
579
-     *
580
-     * @param SecurityPolicy $policy the security policy object
581
-     */
582
-    public function setSecurityPolicy(SecurityPolicy $policy = null)
583
-    {
584
-        $this->securityPolicy = $policy;
585
-    }
586
-
587
-    /**
588
-     * Returns the current security policy object or null by default.
589
-     *
590
-     * @return SecurityPolicy|null the security policy object if any
591
-     */
592
-    public function getSecurityPolicy()
593
-    {
594
-        return $this->securityPolicy;
595
-    }
596
-
597
-    /**
598
-     * Sets the pointer position.
599
-     *
600
-     * @param int  $position the new pointer position
601
-     * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
602
-     */
603
-    public function setPointer($position, $isOffset = false)
604
-    {
605
-        if ($isOffset) {
606
-            $this->pointer += $position;
607
-        } else {
608
-            $this->pointer = $position;
609
-        }
610
-    }
611
-
612
-    /**
613
-     * Returns the current pointer position, only available during compilation of a template.
614
-     *
615
-     * @return int
616
-     */
617
-    public function getPointer()
618
-    {
619
-        return $this->pointer;
620
-    }
621
-
622
-    /**
623
-     * Sets the line number.
624
-     *
625
-     * @param int  $number   the new line number
626
-     * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
627
-     */
628
-    public function setLine($number, $isOffset = false)
629
-    {
630
-        if ($isOffset) {
631
-            $this->line += $number;
632
-        } else {
633
-            $this->line = $number;
634
-        }
635
-    }
636
-
637
-    /**
638
-     * Returns the current line number, only available during compilation of a template.
639
-     *
640
-     * @return int
641
-     */
642
-    public function getLine()
643
-    {
644
-        return $this->line;
645
-    }
646
-
647
-    /**
648
-     * Returns the dwoo object that initiated this template compilation, only available during compilation of a
649
-     * template.
650
-     *
651
-     * @return Core
652
-     */
653
-    public function getDwoo()
654
-    {
655
-        return $this->dwoo;
656
-    }
657
-
658
-    /**
659
-     * Overwrites the template that is being compiled.
660
-     *
661
-     * @param string $newSource   the template source that must replace the current one
662
-     * @param bool   $fromPointer if set to true, only the source from the current pointer position is replaced
663
-     *
664
-     * @return void
665
-     */
666
-    public function setTemplateSource($newSource, $fromPointer = false)
667
-    {
668
-        if ($fromPointer === true) {
669
-            $this->templateSource = substr($this->templateSource, 0, $this->pointer) . $newSource;
670
-        } else {
671
-            $this->templateSource = $newSource;
672
-        }
673
-    }
674
-
675
-    /**
676
-     * Returns the template that is being compiled.
677
-     *
678
-     * @param mixed $fromPointer if set to true, only the source from the current pointer
679
-     *                           position is returned, if a number is given it overrides the current pointer
680
-     *
681
-     * @return string the template or partial template
682
-     */
683
-    public function getTemplateSource($fromPointer = false)
684
-    {
685
-        if ($fromPointer === true) {
686
-            return substr($this->templateSource, $this->pointer);
687
-        } elseif (is_numeric($fromPointer)) {
688
-            return substr($this->templateSource, $fromPointer);
689
-        } else {
690
-            return $this->templateSource;
691
-        }
692
-    }
693
-
694
-    /**
695
-     * Resets the compilation pointer, effectively restarting the compilation process.
696
-     * this is useful if a plugin modifies the template source since it might need to be recompiled
697
-     */
698
-    public function recompile()
699
-    {
700
-        $this->setPointer(0);
701
-    }
702
-
703
-    /**
704
-     * Compiles the provided string down to php code.
705
-     *
706
-     * @param Core      $dwoo
707
-     * @param ITemplate $template the template to compile
708
-     *
709
-     * @return string a compiled php string
710
-     * @throws CompilationException
711
-     */
712
-    public function compile(Core $dwoo, ITemplate $template)
713
-    {
714
-        // init vars
715
-        //		$compiled = '';
716
-        $tpl                  = $template->getSource();
717
-        $ptr                  = 0;
718
-        $this->dwoo           = $dwoo;
719
-        $this->template       = $template;
720
-        $this->templateSource = &$tpl;
721
-        $this->pointer        = &$ptr;
722
-
723
-        while (true) {
724
-            // if pointer is at the beginning, reset everything, that allows a plugin to externally reset the compiler if everything must be reparsed
725
-            if ($ptr === 0) {
726
-                // resets variables
727
-                $this->usedPlugins     = array();
728
-                $this->data            = array();
729
-                $this->scope           = &$this->data;
730
-                $this->scopeTree       = array();
731
-                $this->stack           = array();
732
-                $this->line            = 1;
733
-                $this->templatePlugins = array();
734
-                // add top level block
735
-                $compiled                 = $this->addBlock('TopLevelBlock', array(), 0);
736
-                $this->stack[0]['buffer'] = '';
737
-
738
-                if ($this->debug) {
739
-                    echo "\n";
740
-                    echo 'COMPILER INIT' . "\n";
741
-                }
742
-
743
-                if ($this->debug) {
744
-                    echo 'PROCESSING PREPROCESSORS (' . count($this->processors['pre']) . ')' . "\n";
745
-                }
746
-
747
-                // runs preprocessors
748
-                foreach ($this->processors['pre'] as $preProc) {
749
-                    if (is_array($preProc) && isset($preProc['autoload'])) {
750
-                        $preProc = $this->loadProcessor($preProc['class'], $preProc['name']);
751
-                    }
752
-                    if (is_array($preProc) && $preProc[0] instanceof Processor) {
753
-                        $tpl = call_user_func($preProc, $tpl);
754
-                    } else {
755
-                        $tpl = call_user_func($preProc, $this, $tpl);
756
-                    }
757
-                }
758
-                unset($preProc);
759
-
760
-                // show template source if debug
761
-                if ($this->debug) {
762
-                    echo '<pre>'.print_r(htmlentities($tpl), true).'</pre>'."\n";
763
-                }
764
-
765
-                // strips php tags if required by the security policy
766
-                if ($this->securityPolicy !== null) {
767
-                    $search = array('{<\?php.*?\?>}');
768
-                    if (ini_get('short_open_tags')) {
769
-                        $search = array('{<\?.*?\?>}', '{<%.*?%>}');
770
-                    }
771
-                    switch ($this->securityPolicy->getPhpHandling()) {
772
-                        case SecurityPolicy::PHP_ALLOW:
773
-                            break;
774
-                        case SecurityPolicy::PHP_ENCODE:
775
-                            $tpl = preg_replace_callback($search, array($this, 'phpTagEncodingHelper'), $tpl);
776
-                            break;
777
-                        case SecurityPolicy::PHP_REMOVE:
778
-                            $tpl = preg_replace($search, '', $tpl);
779
-                    }
780
-                }
781
-            }
782
-
783
-            $pos = strpos($tpl, $this->ld, $ptr);
784
-
785
-            if ($pos === false) {
786
-                $this->push(substr($tpl, $ptr), 0);
787
-                break;
788
-            } elseif (substr($tpl, $pos - 1, 1) === '\\' && substr($tpl, $pos - 2, 1) !== '\\') {
789
-                $this->push(substr($tpl, $ptr, $pos - $ptr - 1) . $this->ld);
790
-                $ptr = $pos + strlen($this->ld);
791
-            } elseif (preg_match('/^' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . 'literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', substr($tpl, $pos), $litOpen)) {
792
-                if (!preg_match('/' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . '\/literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', $tpl, $litClose, PREG_OFFSET_CAPTURE, $pos)) {
793
-                    throw new CompilationException($this, 'The {literal} blocks must be closed explicitly with {/literal}');
794
-                }
795
-                $endpos = $litClose[0][1];
796
-                $this->push(substr($tpl, $ptr, $pos - $ptr) . substr($tpl, $pos + strlen($litOpen[0]), $endpos - $pos - strlen($litOpen[0])));
797
-                $ptr = $endpos + strlen($litClose[0][0]);
798
-            } else {
799
-                if (substr($tpl, $pos - 2, 1) === '\\' && substr($tpl, $pos - 1, 1) === '\\') {
800
-                    $this->push(substr($tpl, $ptr, $pos - $ptr - 1));
801
-                    $ptr = $pos;
802
-                }
803
-
804
-                $this->push(substr($tpl, $ptr, $pos - $ptr));
805
-                $ptr = $pos;
806
-
807
-                $pos += strlen($this->ld);
808
-                if ($this->allowLooseOpenings) {
809
-                    while (substr($tpl, $pos, 1) === ' ') {
810
-                        $pos += 1;
811
-                    }
812
-                } else {
813
-                    if (substr($tpl, $pos, 1) === ' ' || substr($tpl, $pos, 1) === "\r" || substr($tpl, $pos, 1) === "\n" || substr($tpl, $pos, 1) === "\t") {
814
-                        $ptr = $pos;
815
-                        $this->push($this->ld);
816
-                        continue;
817
-                    }
818
-                }
819
-
820
-                // check that there is an end tag present
821
-                if (strpos($tpl, $this->rd, $pos) === false) {
822
-                    throw new CompilationException($this, 'A template tag was not closed, started with "' . substr($tpl, $ptr, 30) . '"');
823
-                }
824
-
825
-                $ptr += strlen($this->ld);
826
-                $subptr = $ptr;
827
-
828
-                while (true) {
829
-                    $parsed = $this->parse($tpl, $subptr, null, false, 'root', $subptr);
830
-
831
-                    // reload loop if the compiler was reset
832
-                    if ($ptr === 0) {
833
-                        continue 2;
834
-                    }
835
-
836
-                    $len = $subptr - $ptr;
837
-                    $this->push($parsed, substr_count(substr($tpl, $ptr, $len), "\n"));
838
-                    $ptr += $len;
839
-
840
-                    if ($parsed === false) {
841
-                        break;
842
-                    }
843
-                }
844
-            }
845
-        }
846
-
847
-        $compiled .= $this->removeBlock('TopLevelBlock');
848
-
849
-        if ($this->debug) {
850
-            echo 'PROCESSING POSTPROCESSORS' . "\n";
851
-        }
852
-
853
-        foreach ($this->processors['post'] as $postProc) {
854
-            if (is_array($postProc) && isset($postProc['autoload'])) {
855
-                $postProc = $this->loadProcessor($postProc['class'], $postProc['name']);
856
-            }
857
-            if (is_array($postProc) && $postProc[0] instanceof Processor) {
858
-                $compiled = call_user_func($postProc, $compiled);
859
-            } else {
860
-                $compiled = call_user_func($postProc, $this, $compiled);
861
-            }
862
-        }
863
-        unset($postProc);
864
-
865
-        if ($this->debug) {
866
-            echo 'COMPILATION COMPLETE : MEM USAGE : ' . memory_get_usage() . "\n";
867
-        }
868
-
869
-        $output = "<?php\n/* template head */\n";
870
-
871
-        // build plugin preloader
872
-        foreach ($this->getUsedPlugins() as $plugin => $type) {
873
-            if ($type & Core::CUSTOM_PLUGIN) {
874
-                continue;
875
-            }
876
-
877
-            switch ($type) {
878
-                case Core::BLOCK_PLUGIN:
879
-                case Core::CLASS_PLUGIN:
880
-                    if (class_exists('Plugin' . $plugin) !== false) {
881
-                        $output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
882
-                        "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
883
-                    } else {
884
-                        $output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_BLOCKS . "Plugin" . $plugin . "')===false)".
885
-                        "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
886
-                    }
887
-                    break;
888
-                case Core::FUNC_PLUGIN:
889
-                    if (function_exists('Plugin' . $plugin) !== false) {
890
-                        $output .= "if (function_exists('" . "Plugin" . $plugin . "')===false)".
891
-                        "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
892
-                    } else {
893
-                        $output .= "if (function_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
894
-                        "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
895
-                    }
896
-                    break;
897
-                case Core::SMARTY_MODIFIER:
898
-                    $output .= "if (function_exists('smarty_modifier_$plugin')===false)".
899
-                    "\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
900
-                    break;
901
-                case Core::SMARTY_FUNCTION:
902
-                    $output .= "if (function_exists('smarty_function_$plugin')===false)".
903
-                    "\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
904
-                    break;
905
-                case Core::SMARTY_BLOCK:
906
-                    $output .= "if (function_exists('smarty_block_$plugin')===false)".
907
-                    "\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
908
-                    break;
909
-                case Core::PROXY_PLUGIN:
910
-                    $output .= $this->getDwoo()->getPluginProxy()->getLoader($plugin);
911
-                    break;
912
-                default:
913
-                    throw new CompilationException($this, 'Type error for ' . $plugin . ' with type' . $type);
914
-            }
915
-        }
916
-
917
-        foreach ($this->templatePlugins as $function => $attr) {
918
-            if (isset($attr['called']) && $attr['called'] === true && !isset($attr['checked'])) {
919
-                $this->resolveSubTemplateDependencies($function);
920
-            }
921
-        }
922
-        foreach ($this->templatePlugins as $function) {
923
-            if (isset($function['called']) && $function['called'] === true) {
924
-                $output .= $function['body'] . PHP_EOL;
925
-            }
926
-        }
927
-
928
-        $output .= $compiled . "\n?>";
929
-
930
-        $output = preg_replace('/(?<!;|\}|\*\/|\n|\{)(\s*' . preg_quote(self::PHP_CLOSE, '/') . preg_quote(self::PHP_OPEN, '/') . ')/', ";\n", $output);
931
-        $output = str_replace(self::PHP_CLOSE . self::PHP_OPEN, "\n", $output);
932
-
933
-        // handle <?xml tag at the beginning
934
-        $output = preg_replace('#(/\* template body \*/ \?>\s*)<\?xml#is', '$1<?php echo \'<?xml\'; ?>', $output);
935
-
936
-        // add another line break after PHP closing tags that have a line break following,
937
-        // as we do not know whether it's intended, and PHP will strip it otherwise
938
-        $output = preg_replace('/(?<!"|<\?xml)\s*\?>\n/', '$0' . "\n", $output);
939
-
940
-        if ($this->debug) {
941
-            echo '=============================================================================================' . "\n";
942
-            $lines = preg_split('{\r\n|\n|<br />}', $output);
943
-            array_shift($lines);
944
-            foreach ($lines as $i => $line) {
945
-                echo ($i + 1) . '. ' . $line . "\r\n";
946
-            }
947
-            echo '=============================================================================================' . "\n";
948
-        }
949
-
950
-        $this->template = $this->dwoo = null;
951
-        $tpl            = null;
952
-
953
-        return $output;
954
-    }
955
-
956
-    /**
957
-     * Checks what sub-templates are used in every sub-template so that we're sure they are all compiled.
958
-     *
959
-     * @param string $function the sub-template name
960
-     */
961
-    protected function resolveSubTemplateDependencies($function)
962
-    {
963
-        if ($this->debug) {
964
-            echo 'Compiler::' . __FUNCTION__ . "\n";
965
-        }
966
-
967
-        $body = $this->templatePlugins[$function]['body'];
968
-        foreach ($this->templatePlugins as $func => $attr) {
969
-            if ($func !== $function && !isset($attr['called']) && strpos($body, Core::NAMESPACE_PLUGINS_FUNCTIONS .
970
-            'Plugin' . Core::toCamelCase($func)) !== false) {
971
-                $this->templatePlugins[$func]['called'] = true;
972
-                $this->resolveSubTemplateDependencies($func);
973
-            }
974
-        }
975
-        $this->templatePlugins[$function]['checked'] = true;
976
-    }
977
-
978
-    /**
979
-     * Adds compiled content to the current block.
980
-     *
981
-     * @param string $content   the content to push
982
-     * @param int    $lineCount newlines count in content, optional
983
-     *
984
-     * @throws CompilationException
985
-     */
986
-    public function push($content, $lineCount = null)
987
-    {
988
-        if ($lineCount === null) {
989
-            $lineCount = substr_count($content, "\n");
990
-        }
991
-
992
-        if ($this->curBlock['buffer'] === null && count($this->stack) > 1) {
993
-            // buffer is not initialized yet (the block has just been created)
994
-            $this->stack[count($this->stack) - 2]['buffer'] .= (string)$content;
995
-            $this->curBlock['buffer'] = '';
996
-        } else {
997
-            if (!isset($this->curBlock['buffer'])) {
998
-                throw new CompilationException($this, 'The template has been closed too early, you probably have an extra block-closing tag somewhere');
999
-            }
1000
-            // append current content to current block's buffer
1001
-            $this->curBlock['buffer'] .= (string)$content;
1002
-        }
1003
-        $this->line += $lineCount;
1004
-    }
1005
-
1006
-    /**
1007
-     * Sets the scope.
1008
-     * set to null if the scope becomes "unstable" (i.e. too variable or unknown) so that
1009
-     * variables are compiled in a more evaluative way than just $this->scope['key']
1010
-     *
1011
-     * @param mixed $scope    a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1012
-     * @param bool  $absolute if true, the scope is set from the top level scope and not from the current scope
1013
-     *
1014
-     * @return array the current scope tree
1015
-     */
1016
-    public function setScope($scope, $absolute = false)
1017
-    {
1018
-        $old = $this->scopeTree;
1019
-
1020
-        if ($scope === null) {
1021
-            unset($this->scope);
1022
-            $this->scope = null;
1023
-        }
1024
-
1025
-        if (is_array($scope) === false) {
1026
-            $scope = explode('.', $scope);
1027
-        }
1028
-
1029
-        if ($absolute === true) {
1030
-            $this->scope     = &$this->data;
1031
-            $this->scopeTree = array();
1032
-        }
1033
-
1034
-        while (($bit = array_shift($scope)) !== null) {
1035
-            if ($bit === '_parent' || $bit === '_') {
1036
-                array_pop($this->scopeTree);
1037
-                reset($this->scopeTree);
1038
-                $this->scope = &$this->data;
1039
-                $cnt         = count($this->scopeTree);
1040
-                for ($i = 0; $i < $cnt; ++ $i) {
1041
-                    $this->scope = &$this->scope[$this->scopeTree[$i]];
1042
-                }
1043
-            } elseif ($bit === '_root' || $bit === '__') {
1044
-                $this->scope     = &$this->data;
1045
-                $this->scopeTree = array();
1046
-            } elseif (isset($this->scope[$bit])) {
1047
-                $this->scope       = &$this->scope[$bit];
1048
-                $this->scopeTree[] = $bit;
1049
-            } else {
1050
-                $this->scope[$bit] = array();
1051
-                $this->scope       = &$this->scope[$bit];
1052
-                $this->scopeTree[] = $bit;
1053
-            }
1054
-        }
1055
-
1056
-        return $old;
1057
-    }
1058
-
1059
-    /**
1060
-     * Adds a block to the top of the block stack.
1061
-     *
1062
-     * @param string $type      block type (name)
1063
-     * @param array  $params    the parameters array
1064
-     * @param int    $paramtype the parameters type (see mapParams), 0, 1 or 2
1065
-     *
1066
-     * @return string the preProcessing() method's output
1067
-     */
1068
-    public function addBlock($type, array $params, $paramtype)
1069
-    {
1070
-        if ($this->debug) {
1071
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1072
-        }
1073
-
1074
-        $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type);
1075
-        if (class_exists($class) === false) {
1076
-            $this->getDwoo()->getLoader()->loadPlugin($type);
1077
-        }
1078
-        $params = $this->mapParams($params, array($class, 'init'), $paramtype);
1079
-
1080
-        $this->stack[]  = array(
1081
-            'type'   => $type,
1082
-            'params' => $params,
1083
-            'custom' => false,
1084
-            'class'  => $class,
1085
-            'buffer' => null
1086
-        );
1087
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1088
-
1089
-        return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1090
-    }
1091
-
1092
-    /**
1093
-     * Adds a custom block to the top of the block stack.
1094
-     *
1095
-     * @param string $type      block type (name)
1096
-     * @param array  $params    the parameters array
1097
-     * @param int    $paramtype the parameters type (see mapParams), 0, 1 or 2
1098
-     *
1099
-     * @return string the preProcessing() method's output
1100
-     */
1101
-    public function addCustomBlock($type, array $params, $paramtype)
1102
-    {
1103
-        $callback = $this->customPlugins[$type]['callback'];
1104
-        if (is_array($callback)) {
1105
-            $class = is_object($callback[0]) ? get_class($callback[0]) : $callback[0];
1106
-        } else {
1107
-            $class = $callback;
1108
-        }
1109
-
1110
-        $params = $this->mapParams($params, array($class, 'init'), $paramtype);
1111
-
1112
-        $this->stack[]  = array(
1113
-            'type'   => $type,
1114
-            'params' => $params,
1115
-            'custom' => true,
1116
-            'class'  => $class,
1117
-            'buffer' => null
1118
-        );
1119
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1120
-
1121
-        return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1122
-    }
1123
-
1124
-    /**
1125
-     * Injects a block at the top of the plugin stack without calling its preProcessing method.
1126
-     * used by {else} blocks to re-add themselves after having closed everything up to their parent
1127
-     *
1128
-     * @param string $type   block type (name)
1129
-     * @param array  $params parameters array
1130
-     */
1131
-    public function injectBlock($type, array $params)
1132
-    {
1133
-        if ($this->debug) {
1134
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1135
-        }
1136
-
1137
-        $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type);
1138
-        if (class_exists($class) === false) {
1139
-            $this->getDwoo()->getLoader()->loadPlugin($type);
1140
-        }
1141
-        $this->stack[]  = array(
1142
-            'type'   => $type,
1143
-            'params' => $params,
1144
-            'custom' => false,
1145
-            'class'  => $class,
1146
-            'buffer' => null
1147
-        );
1148
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1149
-    }
1150
-
1151
-    /**
1152
-     * Removes the closest-to-top block of the given type and all other
1153
-     * blocks encountered while going down the block stack.
1154
-     *
1155
-     * @param string $type block type (name)
1156
-     *
1157
-     * @return string the output of all postProcessing() method's return values of the closed blocks
1158
-     * @throws CompilationException
1159
-     */
1160
-    public function removeBlock($type)
1161
-    {
1162
-        if ($this->debug) {
1163
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1164
-        }
1165
-
1166
-        $output = '';
1167
-
1168
-        $pluginType = $this->getPluginType($type);
1169
-        if ($pluginType & Core::SMARTY_BLOCK) {
1170
-            $type = 'Smartyinterface';
1171
-        }
1172
-        while (true) {
1173
-            while ($top = array_pop($this->stack)) {
1174
-                if ($top['custom']) {
1175
-                    $class = $top['class'];
1176
-                } else {
1177
-                    $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($top['type']);
1178
-                }
1179
-                if (count($this->stack)) {
1180
-                    $this->curBlock = &$this->stack[count($this->stack) - 1];
1181
-                    $this->push(call_user_func(array(
1182
-                        $class,
1183
-                        'postProcessing'
1184
-                    ), $this, $top['params'], '', '', $top['buffer']), 0);
1185
-                } else {
1186
-                    $null           = null;
1187
-                    $this->curBlock = &$null;
1188
-                    $output         = call_user_func(
1189
-                        array(
1190
-                        $class,
1191
-                        'postProcessing'
1192
-                        ), $this, $top['params'], '', '', $top['buffer']
1193
-                    );
1194
-                }
1195
-
1196
-                if ($top['type'] === $type) {
1197
-                    break 2;
1198
-                }
1199
-            }
1200
-
1201
-            throw new CompilationException($this, 'Syntax malformation, a block of type "' . $type . '" was closed but was not opened');
1202
-            break;
1203
-        }
1204
-
1205
-        return $output;
1206
-    }
1207
-
1208
-    /**
1209
-     * Returns a reference to the first block of the given type encountered and
1210
-     * optionally closes all blocks until it finds it
1211
-     * this is mainly used by {else} plugins to close everything that was opened
1212
-     * between their parent and themselves.
1213
-     *
1214
-     * @param string $type       the block type (name)
1215
-     * @param bool   $closeAlong whether to close all blocks encountered while going down the block stack or not
1216
-     *
1217
-     * @return mixed &array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
1218
-     *               'custom'=>bool defining whether it's a custom plugin or not, for internal use)
1219
-     * @throws CompilationException
1220
-     */
1221
-    public function &findBlock($type, $closeAlong = false)
1222
-    {
1223
-        if ($closeAlong === true) {
1224
-            while ($b = end($this->stack)) {
1225
-                if ($b['type'] === $type) {
1226
-                    return $this->stack[key($this->stack)];
1227
-                }
1228
-                $this->push($this->removeTopBlock(), 0);
1229
-            }
1230
-        } else {
1231
-            end($this->stack);
1232
-            while ($b = current($this->stack)) {
1233
-                if ($b['type'] === $type) {
1234
-                    return $this->stack[key($this->stack)];
1235
-                }
1236
-                prev($this->stack);
1237
-            }
1238
-        }
1239
-
1240
-        throw new CompilationException($this, 'A parent block of type "' . $type . '" is required and can not be found');
1241
-    }
1242
-
1243
-    /**
1244
-     * Returns a reference to the current block array.
1245
-     *
1246
-     * @return array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
1247
-     *                'custom'=>bool defining whether it's a custom plugin or not, for internal use)
1248
-     */
1249
-    public function &getCurrentBlock()
1250
-    {
1251
-        return $this->curBlock;
1252
-    }
1253
-
1254
-    /**
1255
-     * Removes the block at the top of the stack and calls its postProcessing() method.
1256
-     *
1257
-     * @return string the postProcessing() method's output
1258
-     * @throws CompilationException
1259
-     */
1260
-    public function removeTopBlock()
1261
-    {
1262
-        if ($this->debug) {
1263
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1264
-        }
1265
-
1266
-        $o = array_pop($this->stack);
1267
-        if ($o === null) {
1268
-            throw new CompilationException($this, 'Syntax malformation, a block of unknown type was closed but was not opened.');
1269
-        }
1270
-        if ($o['custom']) {
1271
-            $class = $o['class'];
1272
-        } else {
1273
-            $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($o['type']);
1274
-        }
1275
-
1276
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1277
-
1278
-        return call_user_func(array($class, 'postProcessing'), $this, $o['params'], '', '', $o['buffer']);
1279
-    }
1280
-
1281
-    /**
1282
-     * Returns the compiled parameters (for example a variable's compiled parameter will be "$this->scope['key']") out
1283
-     * of the given parameter array.
1284
-     *
1285
-     * @param array $params parameter array
1286
-     *
1287
-     * @return array filtered parameters
1288
-     */
1289
-    public function getCompiledParams(array $params)
1290
-    {
1291
-        foreach ($params as $k => $p) {
1292
-            if (is_array($p)) {
1293
-                $params[$k] = $p[0];
1294
-            }
1295
-        }
1296
-
1297
-        return $params;
1298
-    }
1299
-
1300
-    /**
1301
-     * Returns the real parameters (for example a variable's real parameter will be its key, etc) out of the given
1302
-     * parameter array.
1303
-     *
1304
-     * @param array $params parameter array
1305
-     *
1306
-     * @return array filtered parameters
1307
-     */
1308
-    public function getRealParams(array $params)
1309
-    {
1310
-        foreach ($params as $k => $p) {
1311
-            if (is_array($p)) {
1312
-                $params[$k] = $p[1];
1313
-            }
1314
-        }
1315
-
1316
-        return $params;
1317
-    }
1318
-
1319
-    /**
1320
-     * Returns the token of each parameter out of the given parameter array.
1321
-     *
1322
-     * @param array $params parameter array
1323
-     *
1324
-     * @return array tokens
1325
-     */
1326
-    public function getParamTokens(array $params)
1327
-    {
1328
-        foreach ($params as $k => $p) {
1329
-            if (is_array($p)) {
1330
-                $params[$k] = isset($p[2]) ? $p[2] : 0;
1331
-            }
1332
-        }
1333
-
1334
-        return $params;
1335
-    }
1336
-
1337
-    /**
1338
-     * Entry point of the parser, it redirects calls to other parse* functions.
1339
-     *
1340
-     * @param string $in            the string within which we must parse something
1341
-     * @param int    $from          the starting offset of the parsed area
1342
-     * @param int    $to            the ending offset of the parsed area
1343
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
1344
-     *                              default
1345
-     * @param string $curBlock      the current parser-block being processed
1346
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
1347
-     *                              or null by default
1348
-     *
1349
-     * @return string parsed values
1350
-     * @throws CompilationException
1351
-     */
1352
-    protected function parse($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1353
-    {
1354
-        if ($this->debug) {
1355
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1356
-        }
1357
-
1358
-        if ($to === null) {
1359
-            $to = strlen($in);
1360
-        }
1361
-        $first = substr($in, $from, 1);
1362
-
1363
-        if ($first === false) {
1364
-            throw new CompilationException($this, 'Unexpected EOF, a template tag was not closed');
1365
-        }
1366
-
1367
-        while ($first === ' ' || $first === "\n" || $first === "\t" || $first === "\r") {
1368
-            if ($curBlock === 'root' && substr($in, $from, strlen($this->rd)) === $this->rd) {
1369
-                // end template tag
1370
-                $pointer += strlen($this->rd);
1371
-                if ($this->debug) {
1372
-                    echo 'TEMPLATE PARSING ENDED' . "\n";
1373
-                }
1374
-
1375
-                return false;
1376
-            }
1377
-            ++ $from;
1378
-            if ($pointer !== null) {
1379
-                ++ $pointer;
1380
-            }
1381
-            if ($from >= $to) {
1382
-                if (is_array($parsingParams)) {
1383
-                    return $parsingParams;
1384
-                } else {
1385
-                    return '';
1386
-                }
1387
-            }
1388
-            $first = $in[$from];
1389
-        }
1390
-
1391
-        $substr = substr($in, $from, $to - $from);
1392
-
1393
-        if ($this->debug) {
1394
-            echo 'PARSE CALL : PARSING "' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . '" @ ' . $from . ':' . $to . ' in ' . $curBlock . ' : pointer=' . $pointer . "\n";
1395
-        }
1396
-        $parsed = '';
1397
-
1398
-        if ($curBlock === 'root' && $first === '*') {
1399
-            $src      = $this->getTemplateSource();
1400
-            $startpos = $this->getPointer() - strlen($this->ld);
1401
-            if (substr($src, $startpos, strlen($this->ld)) === $this->ld) {
1402
-                if ($startpos > 0) {
1403
-                    do {
1404
-                        $char = substr($src, -- $startpos, 1);
1405
-                        if ($char == "\n") {
1406
-                            ++ $startpos;
1407
-                            $whitespaceStart = true;
1408
-                            break;
1409
-                        }
1410
-                    }
1411
-                    while ($startpos > 0 && ($char == ' ' || $char == "\t"));
1412
-                }
1413
-
1414
-                if (!isset($whitespaceStart)) {
1415
-                    $startpos = $this->getPointer();
1416
-                } else {
1417
-                    $pointer -= $this->getPointer() - $startpos;
1418
-                }
1419
-
1420
-                if ($this->allowNestedComments && strpos($src, $this->ld . '*', $this->getPointer()) !== false) {
1421
-                    $comOpen  = $this->ld . '*';
1422
-                    $comClose = '*' . $this->rd;
1423
-                    $level    = 1;
1424
-                    $ptr      = $this->getPointer();
1425
-
1426
-                    while ($level > 0 && $ptr < strlen($src)) {
1427
-                        $open  = strpos($src, $comOpen, $ptr);
1428
-                        $close = strpos($src, $comClose, $ptr);
1429
-
1430
-                        if ($open !== false && $close !== false) {
1431
-                            if ($open < $close) {
1432
-                                $ptr = $open + strlen($comOpen);
1433
-                                ++ $level;
1434
-                            } else {
1435
-                                $ptr = $close + strlen($comClose);
1436
-                                -- $level;
1437
-                            }
1438
-                        } elseif ($open !== false) {
1439
-                            $ptr = $open + strlen($comOpen);
1440
-                            ++ $level;
1441
-                        } elseif ($close !== false) {
1442
-                            $ptr = $close + strlen($comClose);
1443
-                            -- $level;
1444
-                        } else {
1445
-                            $ptr = strlen($src);
1446
-                        }
1447
-                    }
1448
-                    $endpos = $ptr - strlen('*' . $this->rd);
1449
-                } else {
1450
-                    $endpos = strpos($src, '*' . $this->rd, $startpos);
1451
-                    if ($endpos == false) {
1452
-                        throw new CompilationException($this, 'Un-ended comment');
1453
-                    }
1454
-                }
1455
-                $pointer += $endpos - $startpos + strlen('*' . $this->rd);
1456
-                if (isset($whitespaceStart) && preg_match('#^[\t ]*\r?\n#', substr($src, $endpos + strlen('*' . $this->rd)), $m)) {
1457
-                    $pointer += strlen($m[0]);
1458
-                    $this->curBlock['buffer'] = substr($this->curBlock['buffer'], 0, strlen($this->curBlock['buffer']) - ($this->getPointer() - $startpos - strlen($this->ld)));
1459
-                }
1460
-
1461
-                return false;
1462
-            }
1463
-        }
1464
-
1465
-        if ($first === '$') {
1466
-            // var
1467
-            $out    = $this->parseVar($in, $from, $to, $parsingParams, $curBlock, $pointer);
1468
-            $parsed = 'var';
1469
-        } elseif ($first === '%' && preg_match('#^%[a-z_\\\\]#i', $substr)) {
1470
-            // Short constant
1471
-            $out = $this->parseConst($in, $from, $to, $parsingParams, $curBlock, $pointer);
1472
-        } elseif (($first === '"' || $first === "'") && !(is_array($parsingParams) && preg_match('#^([\'"])[a-z0-9_]+\1\s*=>?(?:\s+|[^=])#i', $substr))) {
1473
-            // string
1474
-            $out = $this->parseString($in, $from, $to, $parsingParams, $curBlock, $pointer);
1475
-        } elseif (preg_match('/^\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?(' . (is_array($parsingParams) || $curBlock != 'root' ? '' : '\s+[^(]|') . '\s*\(|\s*' . $this->rdr . '|\s*;)/i', $substr)) {
1476
-            // func
1477
-            $out    = $this->parseFunction($in, $from, $to, $parsingParams, $curBlock, $pointer);
1478
-            $parsed = 'func';
1479
-        } elseif ($first === ';') {
1480
-            // instruction end
1481
-            if ($this->debug) {
1482
-                echo 'END OF INSTRUCTION' . "\n";
1483
-            }
1484
-            if ($pointer !== null) {
1485
-                ++ $pointer;
1486
-            }
1487
-
1488
-            return $this->parse($in, $from + 1, $to, false, 'root', $pointer);
1489
-        } elseif ($curBlock === 'root' && preg_match('#^/([a-z_][a-z0-9_]*)?#i', $substr, $match)) {
1490
-            // close block
1491
-            if (!empty($match[1]) && $match[1] == 'else') {
1492
-                throw new CompilationException($this, 'Else blocks must not be closed explicitly, they are automatically closed when their parent block is closed');
1493
-            }
1494
-            if (!empty($match[1]) && $match[1] == 'elseif') {
1495
-                throw new CompilationException($this, 'Elseif blocks must not be closed explicitly, they are automatically closed when their parent block is closed or a new else/elseif block is declared after them');
1496
-            }
1497
-            if ($pointer !== null) {
1498
-                $pointer += strlen($match[0]);
1499
-            }
1500
-            if (empty($match[1])) {
1501
-                if ($this->curBlock['type'] == 'else' || $this->curBlock['type'] == 'elseif') {
1502
-                    $pointer -= strlen($match[0]);
1503
-                }
1504
-                if ($this->debug) {
1505
-                    echo 'TOP BLOCK CLOSED' . "\n";
1506
-                }
1507
-
1508
-                return $this->removeTopBlock();
1509
-            } else {
1510
-                if ($this->debug) {
1511
-                    echo 'BLOCK OF TYPE ' . $match[1] . ' CLOSED' . "\n";
1512
-                }
1513
-
1514
-                return $this->removeBlock($match[1]);
1515
-            }
1516
-        } elseif ($curBlock === 'root' && substr($substr, 0, strlen($this->rd)) === $this->rd) {
1517
-            // end template tag
1518
-            if ($this->debug) {
1519
-                echo 'TAG PARSING ENDED' . "\n";
1520
-            }
1521
-            $pointer += strlen($this->rd);
1522
-
1523
-            return false;
1524
-        } elseif (is_array($parsingParams) && preg_match('#^(([\'"]?)[a-z0-9_]+\2\s*=' . ($curBlock === 'array' ? '>?' : '') . ')(?:\s+|[^=]).*#i', $substr, $match)) {
1525
-            // named parameter
1526
-            if ($this->debug) {
1527
-                echo 'NAMED PARAM FOUND' . "\n";
1528
-            }
1529
-            $len = strlen($match[1]);
1530
-            while (substr($in, $from + $len, 1) === ' ') {
1531
-                ++ $len;
1532
-            }
1533
-            if ($pointer !== null) {
1534
-                $pointer += $len;
1535
-            }
1536
-
1537
-            $output = array(
1538
-                trim($match[1], " \t\r\n=>'\""),
1539
-                $this->parse($in, $from + $len, $to, false, 'namedparam', $pointer)
1540
-            );
1541
-
1542
-            $parsingParams[] = $output;
1543
-
1544
-            return $parsingParams;
1545
-        } elseif (preg_match('#^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*::\$[a-z0-9_]+)#i', $substr, $match)) {
1546
-            // static member access
1547
-            $parsed = 'var';
1548
-            if (is_array($parsingParams)) {
1549
-                $parsingParams[] = array($match[1], $match[1]);
1550
-                $out             = $parsingParams;
1551
-            } else {
1552
-                $out = $match[1];
1553
-            }
1554
-            $pointer += strlen($match[1]);
1555
-        } elseif ($substr !== '' && (is_array($parsingParams) || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'expression')) {
1556
-            // unquoted string, bool or number
1557
-            $out = $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1558
-        } else {
1559
-            // parse error
1560
-            throw new CompilationException($this, 'Parse error in "' . substr($in, $from, $to - $from) . '"');
1561
-        }
1562
-
1563
-        if (empty($out)) {
1564
-            return '';
1565
-        }
1566
-
1567
-        $substr = substr($in, $pointer, $to - $pointer);
1568
-
1569
-        // var parsed, check if any var-extension applies
1570
-        if ($parsed === 'var') {
1571
-            if (preg_match('#^\s*([/%+*-])\s*([a-z0-9]|\$)#i', $substr, $match)) {
1572
-                if ($this->debug) {
1573
-                    echo 'PARSING POST-VAR EXPRESSION ' . $substr . "\n";
1574
-                }
1575
-                // parse expressions
1576
-                $pointer += strlen($match[0]) - 1;
1577
-                if (is_array($parsingParams)) {
1578
-                    if ($match[2] == '$') {
1579
-                        $expr = $this->parseVar($in, $pointer, $to, array(), $curBlock, $pointer);
1580
-                    } else {
1581
-                        $expr = $this->parse($in, $pointer, $to, array(), 'expression', $pointer);
1582
-                    }
1583
-                    $out[count($out) - 1][0] .= $match[1] . $expr[0][0];
1584
-                    $out[count($out) - 1][1] .= $match[1] . $expr[0][1];
1585
-                } else {
1586
-                    if ($match[2] == '$') {
1587
-                        $expr = $this->parseVar($in, $pointer, $to, false, $curBlock, $pointer);
1588
-                    } else {
1589
-                        $expr = $this->parse($in, $pointer, $to, false, 'expression', $pointer);
1590
-                    }
1591
-                    if (is_array($out) && is_array($expr)) {
1592
-                        $out[0] .= $match[1] . $expr[0];
1593
-                        $out[1] .= $match[1] . $expr[1];
1594
-                    } elseif (is_array($out)) {
1595
-                        $out[0] .= $match[1] . $expr;
1596
-                        $out[1] .= $match[1] . $expr;
1597
-                    } elseif (is_array($expr)) {
1598
-                        $out .= $match[1] . $expr[0];
1599
-                    } else {
1600
-                        $out .= $match[1] . $expr;
1601
-                    }
1602
-                }
1603
-            } elseif ($curBlock === 'root' && preg_match('#^(\s*(?:[+/*%-.]=|=|\+\+|--)\s*)(.*)#s', $substr, $match)) {
1604
-                if ($this->debug) {
1605
-                    echo 'PARSING POST-VAR ASSIGNMENT ' . $substr . "\n";
1606
-                }
1607
-                // parse assignment
1608
-                $value    = $match[2];
1609
-                $operator = trim($match[1]);
1610
-                if (substr($value, 0, 1) == '=') {
1611
-                    throw new CompilationException($this, 'Unexpected "=" in <em>' . $substr . '</em>');
1612
-                }
1613
-
1614
-                if ($pointer !== null) {
1615
-                    $pointer += strlen($match[1]);
1616
-                }
1617
-
1618
-                if ($operator !== '++' && $operator !== '--') {
1619
-                    $parts = array();
1620
-                    $ptr   = 0;
1621
-                    $parts = $this->parse($value, 0, strlen($value), $parts, 'condition', $ptr);
1622
-                    $pointer += $ptr;
1623
-
1624
-                    // load if plugin
1625
-                    try {
1626
-                        $this->getPluginType('if');
1627
-                    }
1628
-                    catch (Exception $e) {
1629
-                        throw new CompilationException($this, 'Assignments require the "if" plugin to be accessible');
1630
-                    }
1631
-
1632
-                    $parts  = $this->mapParams($parts, array(Core::NAMESPACE_PLUGINS_BLOCKS . 'PluginIf', 'init'), 1);
1633
-                    $tokens = $this->getParamTokens($parts);
1634
-                    $parts  = $this->getCompiledParams($parts);
1635
-
1636
-                    $value = PluginIf::replaceKeywords($parts['*'], $tokens['*'], $this);
1637
-                    $echo  = '';
1638
-                } else {
1639
-                    $value = array();
1640
-                    $echo  = 'echo ';
1641
-                }
1642
-
1643
-                if ($this->autoEscape) {
1644
-                    $out = preg_replace('#\(is_string\(\$tmp=(.+?)\) \? htmlspecialchars\(\$tmp, ENT_QUOTES, \$this->charset\) : \$tmp\)#', '$1', $out);
1645
-                }
1646
-                $out = self::PHP_OPEN . $echo . $out . $operator . implode(' ', $value) . self::PHP_CLOSE;
1647
-            } elseif ($curBlock === 'array' && is_array($parsingParams) && preg_match('#^(\s*=>?\s*)#', $substr, $match)) {
1648
-                // parse namedparam with var as name (only for array)
1649
-                if ($this->debug) {
1650
-                    echo 'VARIABLE NAMED PARAM (FOR ARRAY) FOUND' . "\n";
1651
-                }
1652
-                $len = strlen($match[1]);
1653
-                $var = $out[count($out) - 1];
1654
-                $pointer += $len;
1655
-
1656
-                $output = array($var[0], $this->parse($substr, $len, null, false, 'namedparam', $pointer));
1657
-
1658
-                $parsingParams[] = $output;
1659
-
1660
-                return $parsingParams;
1661
-            }
1662
-        }
1663
-
1664
-        if ($curBlock !== 'modifier' && ($parsed === 'func' || $parsed === 'var') && preg_match('#^(\|@?[a-z0-9_]+(:.*)?)+#i', $substr, $match)) {
1665
-            // parse modifier on funcs or vars
1666
-            $srcPointer = $pointer;
1667
-            if (is_array($parsingParams)) {
1668
-                $tmp                     = $this->replaceModifiers(
1669
-                    array(
1670
-                    null,
1671
-                    null,
1672
-                    $out[count($out) - 1][0],
1673
-                    $match[0]
1674
-                    ), $curBlock, $pointer
1675
-                );
1676
-                $out[count($out) - 1][0] = $tmp;
1677
-                $out[count($out) - 1][1] .= substr($substr, $srcPointer, $srcPointer - $pointer);
1678
-            } else {
1679
-                $out = $this->replaceModifiers(array(null, null, $out, $match[0]), $curBlock, $pointer);
1680
-            }
1681
-        }
1682
-
1683
-        // func parsed, check if any func-extension applies
1684
-        if ($parsed === 'func' && preg_match('#^->[a-z0-9_]+(\s*\(.+|->[a-z_].*)?#is', $substr, $match)) {
1685
-            // parse method call or property read
1686
-            $ptr = 0;
1687
-
1688
-            if (is_array($parsingParams)) {
1689
-                $output = $this->parseMethodCall($out[count($out) - 1][1], $match[0], $curBlock, $ptr);
1690
-
1691
-                $out[count($out) - 1][0] = $output;
1692
-                $out[count($out) - 1][1] .= substr($match[0], 0, $ptr);
1693
-            } else {
1694
-                $out = $this->parseMethodCall($out, $match[0], $curBlock, $ptr);
1695
-            }
1696
-
1697
-            $pointer += $ptr;
1698
-        }
1699
-
1700
-        if ($curBlock === 'root' && substr($out, 0, strlen(self::PHP_OPEN)) !== self::PHP_OPEN) {
1701
-            return self::PHP_OPEN . 'echo ' . $out . ';' . self::PHP_CLOSE;
1702
-        } else {
1703
-            return $out;
1704
-        }
1705
-    }
1706
-
1707
-    /**
1708
-     * Parses a function call.
1709
-     *
1710
-     * @param string $in            the string within which we must parse something
1711
-     * @param int    $from          the starting offset of the parsed area
1712
-     * @param int    $to            the ending offset of the parsed area
1713
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
1714
-     *                              default
1715
-     * @param string $curBlock      the current parser-block being processed
1716
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
1717
-     *                              or null by default
1718
-     *
1719
-     * @return string parsed values
1720
-     * @throws CompilationException
1721
-     * @throws Exception
1722
-     * @throws SecurityException
1723
-     */
1724
-    protected function parseFunction($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1725
-    {
1726
-        $output = '';
1727
-        $cmdstr = substr($in, $from, $to - $from);
1728
-        preg_match('/^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?)(\s*' . $this->rdr . '|\s*;)?/i', $cmdstr, $match);
1729
-
1730
-        if (empty($match[1])) {
1731
-            throw new CompilationException($this, 'Parse error, invalid function name : ' . substr($cmdstr, 0, 15));
1732
-        }
1733
-
1734
-        $func = $match[1];
1735
-
1736
-        if (!empty($match[2])) {
1737
-            $cmdstr = $match[1];
1738
-        }
1739
-
1740
-        if ($this->debug) {
1741
-            echo 'FUNC FOUND (' . $func . ')' . "\n";
1742
-        }
1743
-
1744
-        $paramsep = '';
1745
-
1746
-        if (is_array($parsingParams) || $curBlock != 'root') {
1747
-            $paramspos = strpos($cmdstr, '(');
1748
-            $paramsep  = ')';
1749
-        } elseif (preg_match_all('#^\s*[\\\\:a-z0-9_]+(\s*\(|\s+[^(])#i', $cmdstr, $match, PREG_OFFSET_CAPTURE)) {
1750
-            $paramspos = $match[1][0][1];
1751
-            $paramsep  = substr($match[1][0][0], - 1) === '(' ? ')' : '';
1752
-            if ($paramsep === ')') {
1753
-                $paramspos += strlen($match[1][0][0]) - 1;
1754
-                if (substr($cmdstr, 0, 2) === 'if' || substr($cmdstr, 0, 6) === 'elseif') {
1755
-                    $paramsep = '';
1756
-                    if (strlen($match[1][0][0]) > 1) {
1757
-                        -- $paramspos;
1758
-                    }
1759
-                }
1760
-            }
1761
-        } else {
1762
-            $paramspos = false;
1763
-        }
1764
-
1765
-        $state = 0;
1766
-
1767
-        if ($paramspos === false) {
1768
-            $params = array();
1769
-
1770
-            if ($curBlock !== 'root') {
1771
-                return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1772
-            }
1773
-        } else {
1774
-            if ($curBlock === 'condition') {
1775
-                // load if plugin
1776
-                $this->getPluginType('if');
1777
-
1778
-                if (PluginIf::replaceKeywords(array($func), array(self::T_UNQUOTED_STRING), $this) !== array($func)) {
1779
-                    return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1780
-                }
1781
-            }
1782
-            $whitespace = strlen(substr($cmdstr, strlen($func), $paramspos - strlen($func)));
1783
-            $paramstr   = substr($cmdstr, $paramspos + 1);
1784
-            if (substr($paramstr, - 1, 1) === $paramsep) {
1785
-                $paramstr = substr($paramstr, 0, - 1);
1786
-            }
1787
-
1788
-            if (strlen($paramstr) === 0) {
1789
-                $params   = array();
1790
-                $paramstr = '';
1791
-            } else {
1792
-                $ptr    = 0;
1793
-                $params = array();
1794
-                if ($func === 'empty') {
1795
-                    $params = $this->parseVar($paramstr, $ptr, strlen($paramstr), $params, 'root', $ptr);
1796
-                } else {
1797
-                    while ($ptr < strlen($paramstr)) {
1798
-                        while (true) {
1799
-                            if ($ptr >= strlen($paramstr)) {
1800
-                                break 2;
1801
-                            }
1802
-
1803
-                            if ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === ')') {
1804
-                                if ($this->debug) {
1805
-                                    echo 'PARAM PARSING ENDED, ")" FOUND, POINTER AT ' . $ptr . "\n";
1806
-                                }
1807
-                                break 2;
1808
-                            } elseif ($paramstr[$ptr] === ';') {
1809
-                                ++ $ptr;
1810
-                                if ($this->debug) {
1811
-                                    echo 'PARAM PARSING ENDED, ";" FOUND, POINTER AT ' . $ptr . "\n";
1812
-                                }
1813
-                                break 2;
1814
-                            } elseif ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === '/') {
1815
-                                if ($this->debug) {
1816
-                                    echo 'PARAM PARSING ENDED, "/" FOUND, POINTER AT ' . $ptr . "\n";
1817
-                                }
1818
-                                break 2;
1819
-                            } elseif (substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
1820
-                                if ($this->debug) {
1821
-                                    echo 'PARAM PARSING ENDED, RIGHT DELIMITER FOUND, POINTER AT ' . $ptr . "\n";
1822
-                                }
1823
-                                break 2;
1824
-                            }
1825
-
1826
-                            if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === ',' || $paramstr[$ptr] === "\r" || $paramstr[$ptr] === "\n" || $paramstr[$ptr] === "\t") {
1827
-                                ++ $ptr;
1828
-                            } else {
1829
-                                break;
1830
-                            }
1831
-                        }
1832
-
1833
-                        if ($this->debug) {
1834
-                            echo 'FUNC START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
1835
-                        }
1836
-
1837
-                        if ($func === 'if' || $func === 'elseif' || $func === 'tif') {
1838
-                            $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'condition', $ptr);
1839
-                        } elseif ($func === 'array') {
1840
-                            $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'array', $ptr);
1841
-                        } else {
1842
-                            $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'function', $ptr);
1843
-                        }
1844
-
1845
-                        if ($this->debug) {
1846
-                            echo 'PARAM PARSED, POINTER AT ' . $ptr . ' (' . substr($paramstr, $ptr - 1, 3) . ')' . "\n";
1847
-                        }
1848
-                    }
1849
-                }
1850
-                $paramstr = substr($paramstr, 0, $ptr);
1851
-                $state    = 0;
1852
-                foreach ($params as $k => $p) {
1853
-                    if (is_array($p) && is_array($p[1])) {
1854
-                        $state |= 2;
1855
-                    } else {
1856
-                        if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m) && $func !== 'array') {
1857
-                            $params[$k] = array($m[2], array('true', 'true'));
1858
-                        } else {
1859
-                            if ($state & 2 && $func !== 'array') {
1860
-                                throw new CompilationException($this, 'You can not use an unnamed parameter after a named one');
1861
-                            }
1862
-                            $state |= 1;
1863
-                        }
1864
-                    }
1865
-                }
1866
-            }
1867
-        }
1868
-
1869
-        if ($pointer !== null) {
1870
-            $pointer += (isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func) + (isset($whitespace) ? $whitespace : 0);
1871
-            if ($this->debug) {
1872
-                echo 'FUNC ADDS ' . ((isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func)) . ' TO POINTER' . "\n";
1873
-            }
1874
-        }
1875
-
1876
-        if ($curBlock === 'method' || $func === 'do' || strstr($func, '::') !== false) {
1877
-            // handle static method calls with security policy
1878
-            if (strstr($func, '::') !== false && $this->securityPolicy !== null && $this->securityPolicy->isMethodAllowed(explode('::', strtolower($func))) !== true) {
1879
-                throw new SecurityException('Call to a disallowed php function : ' . $func);
1880
-            }
1881
-            $pluginType = Core::NATIVE_PLUGIN;
1882
-        } else {
1883
-            $pluginType = $this->getPluginType($func);
1884
-        }
1885
-
1886
-        // Blocks plugin
1887
-        if ($pluginType & Core::BLOCK_PLUGIN) {
1888
-            if ($curBlock !== 'root' || is_array($parsingParams)) {
1889
-                throw new CompilationException($this, 'Block plugins can not be used as other plugin\'s arguments');
1890
-            }
1891
-            if ($pluginType & Core::CUSTOM_PLUGIN) {
1892
-                return $this->addCustomBlock($func, $params, $state);
1893
-            } else {
1894
-                return $this->addBlock($func, $params, $state);
1895
-            }
1896
-        } elseif ($pluginType & Core::SMARTY_BLOCK) {
1897
-            if ($curBlock !== 'root' || is_array($parsingParams)) {
1898
-                throw new CompilationException($this, 'Block plugins can not be used as other plugin\'s arguments');
1899
-            }
1900
-
1901
-            if ($state & 2) {
1902
-                array_unshift($params, array('__functype', array($pluginType, $pluginType)));
1903
-                array_unshift($params, array('__funcname', array($func, $func)));
1904
-            } else {
1905
-                array_unshift($params, array($pluginType, $pluginType));
1906
-                array_unshift($params, array($func, $func));
1907
-            }
1908
-
1909
-            return $this->addBlock('smartyinterface', $params, $state);
1910
-        }
1911
-
1912
-        // Functions plugin
1913
-        if ($pluginType & Core::NATIVE_PLUGIN || $pluginType & Core::SMARTY_FUNCTION || $pluginType & Core::SMARTY_BLOCK) {
1914
-            $params = $this->mapParams($params, null, $state);
1915
-        } elseif ($pluginType & Core::CLASS_PLUGIN) {
1916
-            if ($pluginType & Core::CUSTOM_PLUGIN) {
1917
-                $params = $this->mapParams(
1918
-                    $params, array(
1919
-                    $this->customPlugins[$func]['class'],
1920
-                    $this->customPlugins[$func]['function']
1921
-                ), $state);
1922
-            } else {
1923
-                if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
1924
-                    $params = $this->mapParams($params, array(
1925
-                        'Plugin' . Core::toCamelCase($func),
1926
-                        ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1927
-                    ), $state);
1928
-                } else {
1929
-                    $params = $this->mapParams($params, array(
1930
-                        Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
1931
-                        ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1932
-                    ), $state);
1933
-                }
1934
-            }
1935
-        } elseif ($pluginType & Core::FUNC_PLUGIN) {
1936
-            if ($pluginType & Core::CUSTOM_PLUGIN) {
1937
-                $params = $this->mapParams($params, $this->customPlugins[$func]['callback'], $state);
1938
-            } else {
1939
-                // Custom plugin
1940
-                if (function_exists('Plugin' . Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ?
1941
-                        'Compile' : '')) !== false) {
1942
-                    $params = $this->mapParams($params, 'Plugin' . Core::toCamelCase($func) . (($pluginType &
1943
-                            Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1944
-                } // Builtin helper plugin
1945
-                elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . (
1946
-                    ($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '')) !== false) {
1947
-                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase
1948
-                        ($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1949
-                } // Builtin function plugin
1950
-                else {
1951
-                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase
1952
-                        ($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1953
-                }
1954
-            }
1955
-        } elseif ($pluginType & Core::SMARTY_MODIFIER) {
1956
-            $output = 'smarty_modifier_' . $func . '(' . implode(', ', $params) . ')';
1957
-        } elseif ($pluginType & Core::PROXY_PLUGIN) {
1958
-            $params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state);
1959
-        } elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
1960
-            // transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values))
1961
-            $map = array();
1962
-            foreach ($this->templatePlugins[$func]['params'] as $param => $defValue) {
1963
-                if ($param == 'rest') {
1964
-                    $param = '*';
1965
-                }
1966
-                $hasDefault = $defValue !== null;
1967
-                if ($defValue === 'null') {
1968
-                    $defValue = null;
1969
-                } elseif ($defValue === 'false') {
1970
-                    $defValue = false;
1971
-                } elseif ($defValue === 'true') {
1972
-                    $defValue = true;
1973
-                } elseif (preg_match('#^([\'"]).*?\1$#', $defValue)) {
1974
-                    $defValue = substr($defValue, 1, - 1);
1975
-                }
1976
-                $map[] = array($param, $hasDefault, $defValue);
1977
-            }
1978
-
1979
-            $params = $this->mapParams($params, null, $state, $map);
1980
-        }
1981
-
1982
-        // only keep php-syntax-safe values for non-block plugins
1983
-        $tokens = array();
1984
-        foreach ($params as $k => $p) {
1985
-            $tokens[$k] = isset($p[2]) ? $p[2] : 0;
1986
-            $params[$k] = $p[0];
1987
-        }
1988
-        if ($pluginType & Core::NATIVE_PLUGIN) {
1989
-            if ($func === 'do') {
1990
-                if (isset($params['*'])) {
1991
-                    $output = implode(';', $params['*']) . ';';
1992
-                } else {
1993
-                    $output = '';
1994
-                }
1995
-
1996
-                if (is_array($parsingParams) || $curBlock !== 'root') {
1997
-                    throw new CompilationException($this, 'Do can not be used inside another function or block');
1998
-                } else {
1999
-                    return self::PHP_OPEN . $output . self::PHP_CLOSE;
2000
-                }
2001
-            } else {
2002
-                if (isset($params['*'])) {
2003
-                    $output = $func . '(' . implode(', ', $params['*']) . ')';
2004
-                } else {
2005
-                    $output = $func . '()';
2006
-                }
2007
-            }
2008
-        } elseif ($pluginType & Core::FUNC_PLUGIN) {
2009
-            if ($pluginType & Core::COMPILABLE_PLUGIN) {
2010
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
2011
-                    $funcCompiler = $this->customPlugins[$func]['callback'];
2012
-                } else {
2013
-                    // Custom plugin
2014
-                    if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2015
-                        $funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
2016
-                    } // Builtin helper plugin
2017
-                    elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) .
2018
-                            'Compile') !== false) {
2019
-                        $funcCompiler = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) .
2020
-                            'Compile';
2021
-                    } // Builtin function plugin
2022
-                    else {
2023
-                        $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
2024
-                            'Compile';
2025
-                    }
2026
-                }
2027
-                array_unshift($params, $this);
2028
-                if ($func === 'tif') {
2029
-                    $params[] = $tokens;
2030
-                }
2031
-                $output = call_user_func_array($funcCompiler, $params);
2032
-            } else {
2033
-                array_unshift($params, '$this');
2034
-                $params = self::implode_r($params);
2035
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
2036
-                    $callback = $this->customPlugins[$func]['callback'];
2037
-                    if ($callback instanceof Closure) {
2038
-                        $output = 'call_user_func($this->getCustomPlugin(\'' . $func . '\'), ' . $params . ')';
2039
-                    } else {
2040
-                        $output = 'call_user_func(\'' . $callback . '\', ' . $params . ')';
2041
-                    }
2042
-                } else {
2043
-                    // Custom plugin
2044
-                    if (function_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2045
-                        $output = 'Plugin' . Core::toCamelCase($func) . '(' . $params .
2046
-                            ')';
2047
-                    } // Builtin helper plugin
2048
-                    elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !==
2049
-                        false) {
2050
-                        $output = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . '(' .
2051
-                            $params . ')';
2052
-                    } // Builtin function plugin
2053
-                    else {
2054
-                        $output = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '(' .
2055
-                            $params . ')';
2056
-                    }
2057
-                }
2058
-            }
2059
-        } elseif ($pluginType & Core::CLASS_PLUGIN) {
2060
-            if ($pluginType & Core::COMPILABLE_PLUGIN) {
2061
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
2062
-                    $callback = $this->customPlugins[$func]['callback'];
2063
-                    if (!is_array($callback)) {
2064
-                        if (!method_exists($callback, 'compile')) {
2065
-                            throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
2066
-                        }
2067
-                        if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
2068
-                            $funcCompiler = array($callback, 'compile');
2069
-                        } else {
2070
-                            $funcCompiler = array(new $callback(), 'compile');
2071
-                        }
2072
-                    } else {
2073
-                        $funcCompiler = $callback;
2074
-                    }
2075
-                } else {
2076
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2077
-                        $funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
2078
-                    } else {
2079
-                        $funcCompiler = array(
2080
-                            Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
2081
-                            'compile'
2082
-                        );
2083
-                    }
2084
-                    array_unshift($params, $this);
2085
-                }
2086
-                $output = call_user_func_array($funcCompiler, $params);
2087
-            } else {
2088
-                $params = self::implode_r($params);
2089
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
2090
-                    $callback = $this->customPlugins[$func]['callback'];
2091
-                    if (!is_array($callback)) {
2092
-                        if (!method_exists($callback, 'process')) {
2093
-                            throw new Exception('Custom plugin ' . $func . ' must implement the "process" method to be usable, or you should provide a full callback to the method to use');
2094
-                        }
2095
-                        if (($ref = new ReflectionMethod($callback, 'process')) && $ref->isStatic()) {
2096
-                            $output = 'call_user_func(array(\'' . $callback . '\', \'process\'), ' . $params . ')';
2097
-                        } else {
2098
-                            $output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback . '\'), \'process\'), ' . $params . ')';
2099
-                        }
2100
-                    } elseif (is_object($callback[0])) {
2101
-                        $output = 'call_user_func(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), ' . $params . ')';
2102
-                    } elseif (($ref = new ReflectionMethod($callback[0], $callback[1])) && $ref->isStatic()) {
2103
-                        $output = 'call_user_func(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), ' . $params . ')';
2104
-                    } else {
2105
-                        $output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback[0] . '\'), \'' . $callback[1] . '\'), ' . $params . ')';
2106
-                    }
2107
-                    if (empty($params)) {
2108
-                        $output = substr($output, 0, - 3) . ')';
2109
-                    }
2110
-                } else {
2111
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2112
-                        $output = '$this->classCall(\'Plugin' . $func . '\', array(' . $params . '))';
2113
-                    } elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !==
2114
-                    false) {
2115
-                        $output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\', 
34
+	/**
35
+	 * Constant that represents a php opening tag.
36
+	 * use it in case it needs to be adjusted
37
+	 *
38
+	 * @var string
39
+	 */
40
+	const PHP_OPEN = '<?php ';
41
+
42
+	/**
43
+	 * Constant that represents a php closing tag.
44
+	 * use it in case it needs to be adjusted
45
+	 *
46
+	 * @var string
47
+	 */
48
+	const PHP_CLOSE = '?>';
49
+
50
+	/**
51
+	 * Boolean flag to enable or disable debugging output.
52
+	 *
53
+	 * @var bool
54
+	 */
55
+	public $debug = false;
56
+
57
+	/**
58
+	 * Left script delimiter.
59
+	 *
60
+	 * @var string
61
+	 */
62
+	protected $ld = '{';
63
+
64
+	/**
65
+	 * Left script delimiter with escaped regex meta characters.
66
+	 *
67
+	 * @var string
68
+	 */
69
+	protected $ldr = '\\{';
70
+
71
+	/**
72
+	 * Right script delimiter.
73
+	 *
74
+	 * @var string
75
+	 */
76
+	protected $rd = '}';
77
+
78
+	/**
79
+	 * Right script delimiter with escaped regex meta characters.
80
+	 *
81
+	 * @var string
82
+	 */
83
+	protected $rdr = '\\}';
84
+
85
+	/**
86
+	 * Defines whether the nested comments should be parsed as nested or not.
87
+	 * defaults to false (classic block comment parsing as in all languages)
88
+	 *
89
+	 * @var bool
90
+	 */
91
+	protected $allowNestedComments = false;
92
+
93
+	/**
94
+	 * Defines whether opening and closing tags can contain spaces before valid data or not.
95
+	 * turn to true if you want to be sloppy with the syntax, but when set to false it allows
96
+	 * to skip javascript and css tags as long as they are in the form "{ something", which is
97
+	 * nice. default is false.
98
+	 *
99
+	 * @var bool
100
+	 */
101
+	protected $allowLooseOpenings = false;
102
+
103
+	/**
104
+	 * Defines whether the compiler will automatically html-escape variables or not.
105
+	 * default is false
106
+	 *
107
+	 * @var bool
108
+	 */
109
+	protected $autoEscape = false;
110
+
111
+	/**
112
+	 * Security policy object.
113
+	 *
114
+	 * @var SecurityPolicy
115
+	 */
116
+	protected $securityPolicy;
117
+
118
+	/**
119
+	 * Stores the custom plugins registered with this compiler.
120
+	 *
121
+	 * @var array
122
+	 */
123
+	protected $customPlugins = array();
124
+
125
+	/**
126
+	 * Stores the template plugins registered with this compiler.
127
+	 *
128
+	 * @var array
129
+	 */
130
+	protected $templatePlugins = array();
131
+
132
+	/**
133
+	 * Stores the pre- and post-processors callbacks.
134
+	 *
135
+	 * @var array
136
+	 */
137
+	protected $processors = array('pre' => array(), 'post' => array());
138
+
139
+	/**
140
+	 * Stores a list of plugins that are used in the currently compiled
141
+	 * template, and that are not compilable. these plugins will be loaded
142
+	 * during the template's runtime if required.
143
+	 * it is a 1D array formatted as key:pluginName value:pluginType
144
+	 *
145
+	 * @var array
146
+	 */
147
+	protected $usedPlugins;
148
+
149
+	/**
150
+	 * Stores the template undergoing compilation.
151
+	 *
152
+	 * @var string
153
+	 */
154
+	protected $template;
155
+
156
+	/**
157
+	 * Stores the current pointer position inside the template.
158
+	 *
159
+	 * @var int
160
+	 */
161
+	protected $pointer;
162
+
163
+	/**
164
+	 * Stores the current line count inside the template for debugging purposes.
165
+	 *
166
+	 * @var int
167
+	 */
168
+	protected $line;
169
+
170
+	/**
171
+	 * Stores the current template source while compiling it.
172
+	 *
173
+	 * @var string
174
+	 */
175
+	protected $templateSource;
176
+
177
+	/**
178
+	 * Stores the data within which the scope moves.
179
+	 *
180
+	 * @var array
181
+	 */
182
+	protected $data;
183
+
184
+	/**
185
+	 * Variable scope of the compiler, set to null if
186
+	 * it can not be resolved to a static string (i.e. if some
187
+	 * plugin defines a new scope based on a variable array key).
188
+	 *
189
+	 * @var mixed
190
+	 */
191
+	protected $scope;
192
+
193
+	/**
194
+	 * Variable scope tree, that allows to rebuild the current
195
+	 * scope if required, i.e. when going to a parent level.
196
+	 *
197
+	 * @var array
198
+	 */
199
+	protected $scopeTree;
200
+
201
+	/**
202
+	 * Block plugins stack, accessible through some methods.
203
+	 *
204
+	 * @see findBlock
205
+	 * @see getCurrentBlock
206
+	 * @see addBlock
207
+	 * @see addCustomBlock
208
+	 * @see injectBlock
209
+	 * @see removeBlock
210
+	 * @see removeTopBlock
211
+	 * @var array
212
+	 */
213
+	protected $stack = array();
214
+
215
+	/**
216
+	 * Current block at the top of the block plugins stack,
217
+	 * accessible through getCurrentBlock.
218
+	 *
219
+	 * @see getCurrentBlock
220
+	 * @var array
221
+	 */
222
+	protected $curBlock;
223
+
224
+	/**
225
+	 * Current dwoo object that uses this compiler, or null.
226
+	 *
227
+	 * @var Core
228
+	 */
229
+	public $dwoo;
230
+
231
+	/**
232
+	 * Holds an instance of this class, used by getInstance when you don't
233
+	 * provide a custom compiler in order to save resources.
234
+	 *
235
+	 * @var Compiler
236
+	 */
237
+	protected static $instance;
238
+
239
+	/**
240
+	 * Token types.
241
+	 *
242
+	 * @var int
243
+	 */
244
+	const T_UNQUOTED_STRING = 1;
245
+	const T_NUMERIC         = 2;
246
+	const T_NULL            = 4;
247
+	const T_BOOL            = 8;
248
+	const T_MATH            = 16;
249
+	const T_BREAKCHAR       = 32;
250
+
251
+	/**
252
+	 * Compiler constructor.
253
+	 * saves the created instance so that child templates get the same one
254
+	 */
255
+	public function __construct()
256
+	{
257
+		self::$instance = $this;
258
+	}
259
+
260
+	/**
261
+	 * Sets the delimiters to use in the templates.
262
+	 * delimiters can be multi-character strings but should not be one of those as they will
263
+	 * make it very hard to work with templates or might even break the compiler entirely : "\", "$", "|", ":" and
264
+	 * finally "#" only if you intend to use config-vars with the #var# syntax.
265
+	 *
266
+	 * @param string $left  left delimiter
267
+	 * @param string $right right delimiter
268
+	 */
269
+	public function setDelimiters($left, $right)
270
+	{
271
+		$this->ld  = $left;
272
+		$this->rd  = $right;
273
+		$this->ldr = preg_quote($left, '/');
274
+		$this->rdr = preg_quote($right, '/');
275
+	}
276
+
277
+	/**
278
+	 * Returns the left and right template delimiters.
279
+	 *
280
+	 * @return array containing the left and the right delimiters
281
+	 */
282
+	public function getDelimiters()
283
+	{
284
+		return array($this->ld, $this->rd);
285
+	}
286
+
287
+	/**
288
+	 * Sets the way to handle nested comments, if set to true
289
+	 * {* foo {* some other *} comment *} will be stripped correctly.
290
+	 * if false it will remove {* foo {* some other *} and leave "comment *}" alone,
291
+	 * this is the default behavior
292
+	 *
293
+	 * @param bool $allow allow nested comments or not, defaults to true (but the default internal value is false)
294
+	 */
295
+	public function setNestedCommentsHandling($allow = true)
296
+	{
297
+		$this->allowNestedComments = (bool)$allow;
298
+	}
299
+
300
+	/**
301
+	 * Returns the nested comments handling setting.
302
+	 *
303
+	 * @see    setNestedCommentsHandling
304
+	 * @return bool true if nested comments are allowed
305
+	 */
306
+	public function getNestedCommentsHandling()
307
+	{
308
+		return $this->allowNestedComments;
309
+	}
310
+
311
+	/**
312
+	 * Sets the tag openings handling strictness, if set to true, template tags can
313
+	 * contain spaces before the first function/string/variable such as { $foo} is valid.
314
+	 * if set to false (default setting), { $foo} is invalid but that is however a good thing
315
+	 * as it allows css (i.e. #foo { color:red; }) to be parsed silently without triggering
316
+	 * an error, same goes for javascript.
317
+	 *
318
+	 * @param bool $allow true to allow loose handling, false to restore default setting
319
+	 */
320
+	public function setLooseOpeningHandling($allow = false)
321
+	{
322
+		$this->allowLooseOpenings = (bool)$allow;
323
+	}
324
+
325
+	/**
326
+	 * Returns the tag openings handling strictness setting.
327
+	 *
328
+	 * @see    setLooseOpeningHandling
329
+	 * @return bool true if loose tags are allowed
330
+	 */
331
+	public function getLooseOpeningHandling()
332
+	{
333
+		return $this->allowLooseOpenings;
334
+	}
335
+
336
+	/**
337
+	 * Changes the auto escape setting.
338
+	 * if enabled, the compiler will automatically html-escape variables,
339
+	 * unless they are passed through the safe function such as {$var|safe}
340
+	 * or {safe $var}
341
+	 * default setting is disabled/false
342
+	 *
343
+	 * @param bool $enabled set to true to enable, false to disable
344
+	 */
345
+	public function setAutoEscape($enabled)
346
+	{
347
+		$this->autoEscape = (bool)$enabled;
348
+	}
349
+
350
+	/**
351
+	 * Returns the auto escape setting.
352
+	 * default setting is disabled/false
353
+	 *
354
+	 * @return bool
355
+	 */
356
+	public function getAutoEscape()
357
+	{
358
+		return $this->autoEscape;
359
+	}
360
+
361
+	/**
362
+	 * Adds a preprocessor to the compiler, it will be called
363
+	 * before the template is compiled.
364
+	 *
365
+	 * @param mixed $callback either a valid callback to the preprocessor or a simple name if the autoload is set to
366
+	 *                        true
367
+	 * @param bool  $autoload if set to true, the preprocessor is auto-loaded from one of the plugin directories, else
368
+	 *                        you must provide a valid callback
369
+	 */
370
+	public function addPreProcessor($callback, $autoload = false)
371
+	{
372
+		if ($autoload) {
373
+			$name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', Core::toCamelCase($callback));
374
+			$class = Core::NAMESPACE_PLUGINS_PROCESSORS . $name;
375
+
376
+			if (class_exists($class)) {
377
+				$callback = array(new $class($this), 'process');
378
+			} elseif (function_exists($class)) {
379
+				$callback = $class;
380
+			} else {
381
+				$callback = array('autoload' => true, 'class' => $class, 'name' => $name);
382
+			}
383
+
384
+			$this->processors['pre'][] = $callback;
385
+		} else {
386
+			$this->processors['pre'][] = $callback;
387
+		}
388
+	}
389
+
390
+	/**
391
+	 * Removes a preprocessor from the compiler.
392
+	 *
393
+	 * @param mixed $callback either a valid callback to the preprocessor or a simple name if it was autoloaded
394
+	 */
395
+	public function removePreProcessor($callback)
396
+	{
397
+		if (($index = array_search($callback, $this->processors['pre'], true)) !== false) {
398
+			unset($this->processors['pre'][$index]);
399
+		} elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
400
+					$callback),
401
+				$this->processors['pre'], true)) !== false) {
402
+			unset($this->processors['pre'][$index]);
403
+		} else {
404
+			$class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
405
+			foreach ($this->processors['pre'] as $index => $proc) {
406
+				if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
407
+					unset($this->processors['pre'][$index]);
408
+					break;
409
+				}
410
+			}
411
+		}
412
+	}
413
+
414
+	/**
415
+	 * Adds a postprocessor to the compiler, it will be called
416
+	 * before the template is compiled.
417
+	 *
418
+	 * @param mixed $callback either a valid callback to the postprocessor or a simple name if the autoload is set to
419
+	 *                        true
420
+	 * @param bool  $autoload if set to true, the postprocessor is auto-loaded from one of the plugin directories, else
421
+	 *                        you must provide a valid callback
422
+	 */
423
+	public function addPostProcessor($callback, $autoload = false)
424
+	{
425
+		if ($autoload) {
426
+			$name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
427
+			$class = Core::NAMESPACE_PLUGINS_PROCESSORS . Core::toCamelCase($name);
428
+
429
+			if (class_exists($class)) {
430
+				$callback = array(new $class($this), 'process');
431
+			} elseif (function_exists($class)) {
432
+				$callback = $class;
433
+			} else {
434
+				$callback = array('autoload' => true, 'class' => $class, 'name' => $name);
435
+			}
436
+
437
+			$this->processors['post'][] = $callback;
438
+		} else {
439
+			$this->processors['post'][] = $callback;
440
+		}
441
+	}
442
+
443
+	/**
444
+	 * Removes a postprocessor from the compiler.
445
+	 *
446
+	 * @param mixed $callback either a valid callback to the postprocessor or a simple name if it was autoloaded
447
+	 */
448
+	public function removePostProcessor($callback)
449
+	{
450
+		if (($index = array_search($callback, $this->processors['post'], true)) !== false) {
451
+			unset($this->processors['post'][$index]);
452
+		} elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
453
+					$callback),
454
+				$this->processors['post'], true)) !== false) {
455
+			unset($this->processors['post'][$index]);
456
+		} else {
457
+			$class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
458
+			foreach ($this->processors['post'] as $index => $proc) {
459
+				if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
460
+					unset($this->processors['post'][$index]);
461
+					break;
462
+				}
463
+			}
464
+		}
465
+	}
466
+
467
+	/**
468
+	 * Internal function to autoload processors at runtime if required.
469
+	 *
470
+	 * @param string $class the class/function name
471
+	 * @param string $name  the plugin name (without Dwoo_Plugin_ prefix)
472
+	 *
473
+	 * @return array|string
474
+	 * @throws Exception
475
+	 */
476
+	protected function loadProcessor($class, $name)
477
+	{
478
+		if (!class_exists($class) && !function_exists($class)) {
479
+			try {
480
+				$this->getDwoo()->getLoader()->loadPlugin($name);
481
+			}
482
+			catch (Exception $e) {
483
+				throw new Exception('Processor ' . $name . ' could not be found in your plugin directories, please ensure it is in a file named ' . $name . '.php in the plugin directory');
484
+			}
485
+		}
486
+
487
+		if (class_exists($class)) {
488
+			return array(new $class($this), 'process');
489
+		}
490
+
491
+		if (function_exists($class)) {
492
+			return $class;
493
+		}
494
+
495
+		throw new Exception('Wrong processor name, when using autoload the processor must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Processor_name"');
496
+	}
497
+
498
+	/**
499
+	 * Adds an used plugin, this is reserved for use by the {template} plugin.
500
+	 * this is required so that plugin loading bubbles up from loaded
501
+	 * template files to the current one
502
+	 *
503
+	 * @private
504
+	 *
505
+	 * @param string $name function name
506
+	 * @param int    $type plugin type (Core::*_PLUGIN)
507
+	 */
508
+	public function addUsedPlugin($name, $type)
509
+	{
510
+		$this->usedPlugins[$name] = $type;
511
+	}
512
+
513
+	/**
514
+	 * Returns all the plugins this template uses.
515
+	 *
516
+	 * @private
517
+	 * @return  array the list of used plugins in the parsed template
518
+	 */
519
+	public function getUsedPlugins()
520
+	{
521
+		return $this->usedPlugins;
522
+	}
523
+
524
+	/**
525
+	 * Adds a template plugin, this is reserved for use by the {template} plugin.
526
+	 * this is required because the template functions are not declared yet
527
+	 * during compilation, so we must have a way of validating their argument
528
+	 * signature without using the reflection api
529
+	 *
530
+	 * @private
531
+	 *
532
+	 * @param string $name   function name
533
+	 * @param array  $params parameter array to help validate the function call
534
+	 * @param string $uuid   unique id of the function
535
+	 * @param string $body   function php code
536
+	 */
537
+	public function addTemplatePlugin($name, array $params, $uuid, $body = null)
538
+	{
539
+		$this->templatePlugins[$name] = array('params' => $params, 'body' => $body, 'uuid' => $uuid);
540
+	}
541
+
542
+	/**
543
+	 * Returns all the parsed sub-templates.
544
+	 *
545
+	 * @private
546
+	 * @return  array the parsed sub-templates
547
+	 */
548
+	public function getTemplatePlugins()
549
+	{
550
+		return $this->templatePlugins;
551
+	}
552
+
553
+	/**
554
+	 * Marks a template plugin as being called, which means its source must be included in the compiled template.
555
+	 *
556
+	 * @param string $name function name
557
+	 */
558
+	public function useTemplatePlugin($name)
559
+	{
560
+		$this->templatePlugins[$name]['called'] = true;
561
+	}
562
+
563
+	/**
564
+	 * Adds the custom plugins loaded into Dwoo to the compiler so it can load them.
565
+	 *
566
+	 * @see Core::addPlugin
567
+	 *
568
+	 * @param array $customPlugins an array of custom plugins
569
+	 */
570
+	public function setCustomPlugins(array $customPlugins)
571
+	{
572
+		$this->customPlugins = $customPlugins;
573
+	}
574
+
575
+	/**
576
+	 * Sets the security policy object to enforce some php security settings.
577
+	 * use this if untrusted persons can modify templates,
578
+	 * set it on the Dwoo object as it will be passed onto the compiler automatically
579
+	 *
580
+	 * @param SecurityPolicy $policy the security policy object
581
+	 */
582
+	public function setSecurityPolicy(SecurityPolicy $policy = null)
583
+	{
584
+		$this->securityPolicy = $policy;
585
+	}
586
+
587
+	/**
588
+	 * Returns the current security policy object or null by default.
589
+	 *
590
+	 * @return SecurityPolicy|null the security policy object if any
591
+	 */
592
+	public function getSecurityPolicy()
593
+	{
594
+		return $this->securityPolicy;
595
+	}
596
+
597
+	/**
598
+	 * Sets the pointer position.
599
+	 *
600
+	 * @param int  $position the new pointer position
601
+	 * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
602
+	 */
603
+	public function setPointer($position, $isOffset = false)
604
+	{
605
+		if ($isOffset) {
606
+			$this->pointer += $position;
607
+		} else {
608
+			$this->pointer = $position;
609
+		}
610
+	}
611
+
612
+	/**
613
+	 * Returns the current pointer position, only available during compilation of a template.
614
+	 *
615
+	 * @return int
616
+	 */
617
+	public function getPointer()
618
+	{
619
+		return $this->pointer;
620
+	}
621
+
622
+	/**
623
+	 * Sets the line number.
624
+	 *
625
+	 * @param int  $number   the new line number
626
+	 * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
627
+	 */
628
+	public function setLine($number, $isOffset = false)
629
+	{
630
+		if ($isOffset) {
631
+			$this->line += $number;
632
+		} else {
633
+			$this->line = $number;
634
+		}
635
+	}
636
+
637
+	/**
638
+	 * Returns the current line number, only available during compilation of a template.
639
+	 *
640
+	 * @return int
641
+	 */
642
+	public function getLine()
643
+	{
644
+		return $this->line;
645
+	}
646
+
647
+	/**
648
+	 * Returns the dwoo object that initiated this template compilation, only available during compilation of a
649
+	 * template.
650
+	 *
651
+	 * @return Core
652
+	 */
653
+	public function getDwoo()
654
+	{
655
+		return $this->dwoo;
656
+	}
657
+
658
+	/**
659
+	 * Overwrites the template that is being compiled.
660
+	 *
661
+	 * @param string $newSource   the template source that must replace the current one
662
+	 * @param bool   $fromPointer if set to true, only the source from the current pointer position is replaced
663
+	 *
664
+	 * @return void
665
+	 */
666
+	public function setTemplateSource($newSource, $fromPointer = false)
667
+	{
668
+		if ($fromPointer === true) {
669
+			$this->templateSource = substr($this->templateSource, 0, $this->pointer) . $newSource;
670
+		} else {
671
+			$this->templateSource = $newSource;
672
+		}
673
+	}
674
+
675
+	/**
676
+	 * Returns the template that is being compiled.
677
+	 *
678
+	 * @param mixed $fromPointer if set to true, only the source from the current pointer
679
+	 *                           position is returned, if a number is given it overrides the current pointer
680
+	 *
681
+	 * @return string the template or partial template
682
+	 */
683
+	public function getTemplateSource($fromPointer = false)
684
+	{
685
+		if ($fromPointer === true) {
686
+			return substr($this->templateSource, $this->pointer);
687
+		} elseif (is_numeric($fromPointer)) {
688
+			return substr($this->templateSource, $fromPointer);
689
+		} else {
690
+			return $this->templateSource;
691
+		}
692
+	}
693
+
694
+	/**
695
+	 * Resets the compilation pointer, effectively restarting the compilation process.
696
+	 * this is useful if a plugin modifies the template source since it might need to be recompiled
697
+	 */
698
+	public function recompile()
699
+	{
700
+		$this->setPointer(0);
701
+	}
702
+
703
+	/**
704
+	 * Compiles the provided string down to php code.
705
+	 *
706
+	 * @param Core      $dwoo
707
+	 * @param ITemplate $template the template to compile
708
+	 *
709
+	 * @return string a compiled php string
710
+	 * @throws CompilationException
711
+	 */
712
+	public function compile(Core $dwoo, ITemplate $template)
713
+	{
714
+		// init vars
715
+		//		$compiled = '';
716
+		$tpl                  = $template->getSource();
717
+		$ptr                  = 0;
718
+		$this->dwoo           = $dwoo;
719
+		$this->template       = $template;
720
+		$this->templateSource = &$tpl;
721
+		$this->pointer        = &$ptr;
722
+
723
+		while (true) {
724
+			// if pointer is at the beginning, reset everything, that allows a plugin to externally reset the compiler if everything must be reparsed
725
+			if ($ptr === 0) {
726
+				// resets variables
727
+				$this->usedPlugins     = array();
728
+				$this->data            = array();
729
+				$this->scope           = &$this->data;
730
+				$this->scopeTree       = array();
731
+				$this->stack           = array();
732
+				$this->line            = 1;
733
+				$this->templatePlugins = array();
734
+				// add top level block
735
+				$compiled                 = $this->addBlock('TopLevelBlock', array(), 0);
736
+				$this->stack[0]['buffer'] = '';
737
+
738
+				if ($this->debug) {
739
+					echo "\n";
740
+					echo 'COMPILER INIT' . "\n";
741
+				}
742
+
743
+				if ($this->debug) {
744
+					echo 'PROCESSING PREPROCESSORS (' . count($this->processors['pre']) . ')' . "\n";
745
+				}
746
+
747
+				// runs preprocessors
748
+				foreach ($this->processors['pre'] as $preProc) {
749
+					if (is_array($preProc) && isset($preProc['autoload'])) {
750
+						$preProc = $this->loadProcessor($preProc['class'], $preProc['name']);
751
+					}
752
+					if (is_array($preProc) && $preProc[0] instanceof Processor) {
753
+						$tpl = call_user_func($preProc, $tpl);
754
+					} else {
755
+						$tpl = call_user_func($preProc, $this, $tpl);
756
+					}
757
+				}
758
+				unset($preProc);
759
+
760
+				// show template source if debug
761
+				if ($this->debug) {
762
+					echo '<pre>'.print_r(htmlentities($tpl), true).'</pre>'."\n";
763
+				}
764
+
765
+				// strips php tags if required by the security policy
766
+				if ($this->securityPolicy !== null) {
767
+					$search = array('{<\?php.*?\?>}');
768
+					if (ini_get('short_open_tags')) {
769
+						$search = array('{<\?.*?\?>}', '{<%.*?%>}');
770
+					}
771
+					switch ($this->securityPolicy->getPhpHandling()) {
772
+						case SecurityPolicy::PHP_ALLOW:
773
+							break;
774
+						case SecurityPolicy::PHP_ENCODE:
775
+							$tpl = preg_replace_callback($search, array($this, 'phpTagEncodingHelper'), $tpl);
776
+							break;
777
+						case SecurityPolicy::PHP_REMOVE:
778
+							$tpl = preg_replace($search, '', $tpl);
779
+					}
780
+				}
781
+			}
782
+
783
+			$pos = strpos($tpl, $this->ld, $ptr);
784
+
785
+			if ($pos === false) {
786
+				$this->push(substr($tpl, $ptr), 0);
787
+				break;
788
+			} elseif (substr($tpl, $pos - 1, 1) === '\\' && substr($tpl, $pos - 2, 1) !== '\\') {
789
+				$this->push(substr($tpl, $ptr, $pos - $ptr - 1) . $this->ld);
790
+				$ptr = $pos + strlen($this->ld);
791
+			} elseif (preg_match('/^' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . 'literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', substr($tpl, $pos), $litOpen)) {
792
+				if (!preg_match('/' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . '\/literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', $tpl, $litClose, PREG_OFFSET_CAPTURE, $pos)) {
793
+					throw new CompilationException($this, 'The {literal} blocks must be closed explicitly with {/literal}');
794
+				}
795
+				$endpos = $litClose[0][1];
796
+				$this->push(substr($tpl, $ptr, $pos - $ptr) . substr($tpl, $pos + strlen($litOpen[0]), $endpos - $pos - strlen($litOpen[0])));
797
+				$ptr = $endpos + strlen($litClose[0][0]);
798
+			} else {
799
+				if (substr($tpl, $pos - 2, 1) === '\\' && substr($tpl, $pos - 1, 1) === '\\') {
800
+					$this->push(substr($tpl, $ptr, $pos - $ptr - 1));
801
+					$ptr = $pos;
802
+				}
803
+
804
+				$this->push(substr($tpl, $ptr, $pos - $ptr));
805
+				$ptr = $pos;
806
+
807
+				$pos += strlen($this->ld);
808
+				if ($this->allowLooseOpenings) {
809
+					while (substr($tpl, $pos, 1) === ' ') {
810
+						$pos += 1;
811
+					}
812
+				} else {
813
+					if (substr($tpl, $pos, 1) === ' ' || substr($tpl, $pos, 1) === "\r" || substr($tpl, $pos, 1) === "\n" || substr($tpl, $pos, 1) === "\t") {
814
+						$ptr = $pos;
815
+						$this->push($this->ld);
816
+						continue;
817
+					}
818
+				}
819
+
820
+				// check that there is an end tag present
821
+				if (strpos($tpl, $this->rd, $pos) === false) {
822
+					throw new CompilationException($this, 'A template tag was not closed, started with "' . substr($tpl, $ptr, 30) . '"');
823
+				}
824
+
825
+				$ptr += strlen($this->ld);
826
+				$subptr = $ptr;
827
+
828
+				while (true) {
829
+					$parsed = $this->parse($tpl, $subptr, null, false, 'root', $subptr);
830
+
831
+					// reload loop if the compiler was reset
832
+					if ($ptr === 0) {
833
+						continue 2;
834
+					}
835
+
836
+					$len = $subptr - $ptr;
837
+					$this->push($parsed, substr_count(substr($tpl, $ptr, $len), "\n"));
838
+					$ptr += $len;
839
+
840
+					if ($parsed === false) {
841
+						break;
842
+					}
843
+				}
844
+			}
845
+		}
846
+
847
+		$compiled .= $this->removeBlock('TopLevelBlock');
848
+
849
+		if ($this->debug) {
850
+			echo 'PROCESSING POSTPROCESSORS' . "\n";
851
+		}
852
+
853
+		foreach ($this->processors['post'] as $postProc) {
854
+			if (is_array($postProc) && isset($postProc['autoload'])) {
855
+				$postProc = $this->loadProcessor($postProc['class'], $postProc['name']);
856
+			}
857
+			if (is_array($postProc) && $postProc[0] instanceof Processor) {
858
+				$compiled = call_user_func($postProc, $compiled);
859
+			} else {
860
+				$compiled = call_user_func($postProc, $this, $compiled);
861
+			}
862
+		}
863
+		unset($postProc);
864
+
865
+		if ($this->debug) {
866
+			echo 'COMPILATION COMPLETE : MEM USAGE : ' . memory_get_usage() . "\n";
867
+		}
868
+
869
+		$output = "<?php\n/* template head */\n";
870
+
871
+		// build plugin preloader
872
+		foreach ($this->getUsedPlugins() as $plugin => $type) {
873
+			if ($type & Core::CUSTOM_PLUGIN) {
874
+				continue;
875
+			}
876
+
877
+			switch ($type) {
878
+				case Core::BLOCK_PLUGIN:
879
+				case Core::CLASS_PLUGIN:
880
+					if (class_exists('Plugin' . $plugin) !== false) {
881
+						$output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
882
+						"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
883
+					} else {
884
+						$output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_BLOCKS . "Plugin" . $plugin . "')===false)".
885
+						"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
886
+					}
887
+					break;
888
+				case Core::FUNC_PLUGIN:
889
+					if (function_exists('Plugin' . $plugin) !== false) {
890
+						$output .= "if (function_exists('" . "Plugin" . $plugin . "')===false)".
891
+						"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
892
+					} else {
893
+						$output .= "if (function_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
894
+						"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
895
+					}
896
+					break;
897
+				case Core::SMARTY_MODIFIER:
898
+					$output .= "if (function_exists('smarty_modifier_$plugin')===false)".
899
+					"\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
900
+					break;
901
+				case Core::SMARTY_FUNCTION:
902
+					$output .= "if (function_exists('smarty_function_$plugin')===false)".
903
+					"\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
904
+					break;
905
+				case Core::SMARTY_BLOCK:
906
+					$output .= "if (function_exists('smarty_block_$plugin')===false)".
907
+					"\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
908
+					break;
909
+				case Core::PROXY_PLUGIN:
910
+					$output .= $this->getDwoo()->getPluginProxy()->getLoader($plugin);
911
+					break;
912
+				default:
913
+					throw new CompilationException($this, 'Type error for ' . $plugin . ' with type' . $type);
914
+			}
915
+		}
916
+
917
+		foreach ($this->templatePlugins as $function => $attr) {
918
+			if (isset($attr['called']) && $attr['called'] === true && !isset($attr['checked'])) {
919
+				$this->resolveSubTemplateDependencies($function);
920
+			}
921
+		}
922
+		foreach ($this->templatePlugins as $function) {
923
+			if (isset($function['called']) && $function['called'] === true) {
924
+				$output .= $function['body'] . PHP_EOL;
925
+			}
926
+		}
927
+
928
+		$output .= $compiled . "\n?>";
929
+
930
+		$output = preg_replace('/(?<!;|\}|\*\/|\n|\{)(\s*' . preg_quote(self::PHP_CLOSE, '/') . preg_quote(self::PHP_OPEN, '/') . ')/', ";\n", $output);
931
+		$output = str_replace(self::PHP_CLOSE . self::PHP_OPEN, "\n", $output);
932
+
933
+		// handle <?xml tag at the beginning
934
+		$output = preg_replace('#(/\* template body \*/ \?>\s*)<\?xml#is', '$1<?php echo \'<?xml\'; ?>', $output);
935
+
936
+		// add another line break after PHP closing tags that have a line break following,
937
+		// as we do not know whether it's intended, and PHP will strip it otherwise
938
+		$output = preg_replace('/(?<!"|<\?xml)\s*\?>\n/', '$0' . "\n", $output);
939
+
940
+		if ($this->debug) {
941
+			echo '=============================================================================================' . "\n";
942
+			$lines = preg_split('{\r\n|\n|<br />}', $output);
943
+			array_shift($lines);
944
+			foreach ($lines as $i => $line) {
945
+				echo ($i + 1) . '. ' . $line . "\r\n";
946
+			}
947
+			echo '=============================================================================================' . "\n";
948
+		}
949
+
950
+		$this->template = $this->dwoo = null;
951
+		$tpl            = null;
952
+
953
+		return $output;
954
+	}
955
+
956
+	/**
957
+	 * Checks what sub-templates are used in every sub-template so that we're sure they are all compiled.
958
+	 *
959
+	 * @param string $function the sub-template name
960
+	 */
961
+	protected function resolveSubTemplateDependencies($function)
962
+	{
963
+		if ($this->debug) {
964
+			echo 'Compiler::' . __FUNCTION__ . "\n";
965
+		}
966
+
967
+		$body = $this->templatePlugins[$function]['body'];
968
+		foreach ($this->templatePlugins as $func => $attr) {
969
+			if ($func !== $function && !isset($attr['called']) && strpos($body, Core::NAMESPACE_PLUGINS_FUNCTIONS .
970
+			'Plugin' . Core::toCamelCase($func)) !== false) {
971
+				$this->templatePlugins[$func]['called'] = true;
972
+				$this->resolveSubTemplateDependencies($func);
973
+			}
974
+		}
975
+		$this->templatePlugins[$function]['checked'] = true;
976
+	}
977
+
978
+	/**
979
+	 * Adds compiled content to the current block.
980
+	 *
981
+	 * @param string $content   the content to push
982
+	 * @param int    $lineCount newlines count in content, optional
983
+	 *
984
+	 * @throws CompilationException
985
+	 */
986
+	public function push($content, $lineCount = null)
987
+	{
988
+		if ($lineCount === null) {
989
+			$lineCount = substr_count($content, "\n");
990
+		}
991
+
992
+		if ($this->curBlock['buffer'] === null && count($this->stack) > 1) {
993
+			// buffer is not initialized yet (the block has just been created)
994
+			$this->stack[count($this->stack) - 2]['buffer'] .= (string)$content;
995
+			$this->curBlock['buffer'] = '';
996
+		} else {
997
+			if (!isset($this->curBlock['buffer'])) {
998
+				throw new CompilationException($this, 'The template has been closed too early, you probably have an extra block-closing tag somewhere');
999
+			}
1000
+			// append current content to current block's buffer
1001
+			$this->curBlock['buffer'] .= (string)$content;
1002
+		}
1003
+		$this->line += $lineCount;
1004
+	}
1005
+
1006
+	/**
1007
+	 * Sets the scope.
1008
+	 * set to null if the scope becomes "unstable" (i.e. too variable or unknown) so that
1009
+	 * variables are compiled in a more evaluative way than just $this->scope['key']
1010
+	 *
1011
+	 * @param mixed $scope    a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1012
+	 * @param bool  $absolute if true, the scope is set from the top level scope and not from the current scope
1013
+	 *
1014
+	 * @return array the current scope tree
1015
+	 */
1016
+	public function setScope($scope, $absolute = false)
1017
+	{
1018
+		$old = $this->scopeTree;
1019
+
1020
+		if ($scope === null) {
1021
+			unset($this->scope);
1022
+			$this->scope = null;
1023
+		}
1024
+
1025
+		if (is_array($scope) === false) {
1026
+			$scope = explode('.', $scope);
1027
+		}
1028
+
1029
+		if ($absolute === true) {
1030
+			$this->scope     = &$this->data;
1031
+			$this->scopeTree = array();
1032
+		}
1033
+
1034
+		while (($bit = array_shift($scope)) !== null) {
1035
+			if ($bit === '_parent' || $bit === '_') {
1036
+				array_pop($this->scopeTree);
1037
+				reset($this->scopeTree);
1038
+				$this->scope = &$this->data;
1039
+				$cnt         = count($this->scopeTree);
1040
+				for ($i = 0; $i < $cnt; ++ $i) {
1041
+					$this->scope = &$this->scope[$this->scopeTree[$i]];
1042
+				}
1043
+			} elseif ($bit === '_root' || $bit === '__') {
1044
+				$this->scope     = &$this->data;
1045
+				$this->scopeTree = array();
1046
+			} elseif (isset($this->scope[$bit])) {
1047
+				$this->scope       = &$this->scope[$bit];
1048
+				$this->scopeTree[] = $bit;
1049
+			} else {
1050
+				$this->scope[$bit] = array();
1051
+				$this->scope       = &$this->scope[$bit];
1052
+				$this->scopeTree[] = $bit;
1053
+			}
1054
+		}
1055
+
1056
+		return $old;
1057
+	}
1058
+
1059
+	/**
1060
+	 * Adds a block to the top of the block stack.
1061
+	 *
1062
+	 * @param string $type      block type (name)
1063
+	 * @param array  $params    the parameters array
1064
+	 * @param int    $paramtype the parameters type (see mapParams), 0, 1 or 2
1065
+	 *
1066
+	 * @return string the preProcessing() method's output
1067
+	 */
1068
+	public function addBlock($type, array $params, $paramtype)
1069
+	{
1070
+		if ($this->debug) {
1071
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1072
+		}
1073
+
1074
+		$class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type);
1075
+		if (class_exists($class) === false) {
1076
+			$this->getDwoo()->getLoader()->loadPlugin($type);
1077
+		}
1078
+		$params = $this->mapParams($params, array($class, 'init'), $paramtype);
1079
+
1080
+		$this->stack[]  = array(
1081
+			'type'   => $type,
1082
+			'params' => $params,
1083
+			'custom' => false,
1084
+			'class'  => $class,
1085
+			'buffer' => null
1086
+		);
1087
+		$this->curBlock = &$this->stack[count($this->stack) - 1];
1088
+
1089
+		return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1090
+	}
1091
+
1092
+	/**
1093
+	 * Adds a custom block to the top of the block stack.
1094
+	 *
1095
+	 * @param string $type      block type (name)
1096
+	 * @param array  $params    the parameters array
1097
+	 * @param int    $paramtype the parameters type (see mapParams), 0, 1 or 2
1098
+	 *
1099
+	 * @return string the preProcessing() method's output
1100
+	 */
1101
+	public function addCustomBlock($type, array $params, $paramtype)
1102
+	{
1103
+		$callback = $this->customPlugins[$type]['callback'];
1104
+		if (is_array($callback)) {
1105
+			$class = is_object($callback[0]) ? get_class($callback[0]) : $callback[0];
1106
+		} else {
1107
+			$class = $callback;
1108
+		}
1109
+
1110
+		$params = $this->mapParams($params, array($class, 'init'), $paramtype);
1111
+
1112
+		$this->stack[]  = array(
1113
+			'type'   => $type,
1114
+			'params' => $params,
1115
+			'custom' => true,
1116
+			'class'  => $class,
1117
+			'buffer' => null
1118
+		);
1119
+		$this->curBlock = &$this->stack[count($this->stack) - 1];
1120
+
1121
+		return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1122
+	}
1123
+
1124
+	/**
1125
+	 * Injects a block at the top of the plugin stack without calling its preProcessing method.
1126
+	 * used by {else} blocks to re-add themselves after having closed everything up to their parent
1127
+	 *
1128
+	 * @param string $type   block type (name)
1129
+	 * @param array  $params parameters array
1130
+	 */
1131
+	public function injectBlock($type, array $params)
1132
+	{
1133
+		if ($this->debug) {
1134
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1135
+		}
1136
+
1137
+		$class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type);
1138
+		if (class_exists($class) === false) {
1139
+			$this->getDwoo()->getLoader()->loadPlugin($type);
1140
+		}
1141
+		$this->stack[]  = array(
1142
+			'type'   => $type,
1143
+			'params' => $params,
1144
+			'custom' => false,
1145
+			'class'  => $class,
1146
+			'buffer' => null
1147
+		);
1148
+		$this->curBlock = &$this->stack[count($this->stack) - 1];
1149
+	}
1150
+
1151
+	/**
1152
+	 * Removes the closest-to-top block of the given type and all other
1153
+	 * blocks encountered while going down the block stack.
1154
+	 *
1155
+	 * @param string $type block type (name)
1156
+	 *
1157
+	 * @return string the output of all postProcessing() method's return values of the closed blocks
1158
+	 * @throws CompilationException
1159
+	 */
1160
+	public function removeBlock($type)
1161
+	{
1162
+		if ($this->debug) {
1163
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1164
+		}
1165
+
1166
+		$output = '';
1167
+
1168
+		$pluginType = $this->getPluginType($type);
1169
+		if ($pluginType & Core::SMARTY_BLOCK) {
1170
+			$type = 'Smartyinterface';
1171
+		}
1172
+		while (true) {
1173
+			while ($top = array_pop($this->stack)) {
1174
+				if ($top['custom']) {
1175
+					$class = $top['class'];
1176
+				} else {
1177
+					$class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($top['type']);
1178
+				}
1179
+				if (count($this->stack)) {
1180
+					$this->curBlock = &$this->stack[count($this->stack) - 1];
1181
+					$this->push(call_user_func(array(
1182
+						$class,
1183
+						'postProcessing'
1184
+					), $this, $top['params'], '', '', $top['buffer']), 0);
1185
+				} else {
1186
+					$null           = null;
1187
+					$this->curBlock = &$null;
1188
+					$output         = call_user_func(
1189
+						array(
1190
+						$class,
1191
+						'postProcessing'
1192
+						), $this, $top['params'], '', '', $top['buffer']
1193
+					);
1194
+				}
1195
+
1196
+				if ($top['type'] === $type) {
1197
+					break 2;
1198
+				}
1199
+			}
1200
+
1201
+			throw new CompilationException($this, 'Syntax malformation, a block of type "' . $type . '" was closed but was not opened');
1202
+			break;
1203
+		}
1204
+
1205
+		return $output;
1206
+	}
1207
+
1208
+	/**
1209
+	 * Returns a reference to the first block of the given type encountered and
1210
+	 * optionally closes all blocks until it finds it
1211
+	 * this is mainly used by {else} plugins to close everything that was opened
1212
+	 * between their parent and themselves.
1213
+	 *
1214
+	 * @param string $type       the block type (name)
1215
+	 * @param bool   $closeAlong whether to close all blocks encountered while going down the block stack or not
1216
+	 *
1217
+	 * @return mixed &array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
1218
+	 *               'custom'=>bool defining whether it's a custom plugin or not, for internal use)
1219
+	 * @throws CompilationException
1220
+	 */
1221
+	public function &findBlock($type, $closeAlong = false)
1222
+	{
1223
+		if ($closeAlong === true) {
1224
+			while ($b = end($this->stack)) {
1225
+				if ($b['type'] === $type) {
1226
+					return $this->stack[key($this->stack)];
1227
+				}
1228
+				$this->push($this->removeTopBlock(), 0);
1229
+			}
1230
+		} else {
1231
+			end($this->stack);
1232
+			while ($b = current($this->stack)) {
1233
+				if ($b['type'] === $type) {
1234
+					return $this->stack[key($this->stack)];
1235
+				}
1236
+				prev($this->stack);
1237
+			}
1238
+		}
1239
+
1240
+		throw new CompilationException($this, 'A parent block of type "' . $type . '" is required and can not be found');
1241
+	}
1242
+
1243
+	/**
1244
+	 * Returns a reference to the current block array.
1245
+	 *
1246
+	 * @return array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
1247
+	 *                'custom'=>bool defining whether it's a custom plugin or not, for internal use)
1248
+	 */
1249
+	public function &getCurrentBlock()
1250
+	{
1251
+		return $this->curBlock;
1252
+	}
1253
+
1254
+	/**
1255
+	 * Removes the block at the top of the stack and calls its postProcessing() method.
1256
+	 *
1257
+	 * @return string the postProcessing() method's output
1258
+	 * @throws CompilationException
1259
+	 */
1260
+	public function removeTopBlock()
1261
+	{
1262
+		if ($this->debug) {
1263
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1264
+		}
1265
+
1266
+		$o = array_pop($this->stack);
1267
+		if ($o === null) {
1268
+			throw new CompilationException($this, 'Syntax malformation, a block of unknown type was closed but was not opened.');
1269
+		}
1270
+		if ($o['custom']) {
1271
+			$class = $o['class'];
1272
+		} else {
1273
+			$class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($o['type']);
1274
+		}
1275
+
1276
+		$this->curBlock = &$this->stack[count($this->stack) - 1];
1277
+
1278
+		return call_user_func(array($class, 'postProcessing'), $this, $o['params'], '', '', $o['buffer']);
1279
+	}
1280
+
1281
+	/**
1282
+	 * Returns the compiled parameters (for example a variable's compiled parameter will be "$this->scope['key']") out
1283
+	 * of the given parameter array.
1284
+	 *
1285
+	 * @param array $params parameter array
1286
+	 *
1287
+	 * @return array filtered parameters
1288
+	 */
1289
+	public function getCompiledParams(array $params)
1290
+	{
1291
+		foreach ($params as $k => $p) {
1292
+			if (is_array($p)) {
1293
+				$params[$k] = $p[0];
1294
+			}
1295
+		}
1296
+
1297
+		return $params;
1298
+	}
1299
+
1300
+	/**
1301
+	 * Returns the real parameters (for example a variable's real parameter will be its key, etc) out of the given
1302
+	 * parameter array.
1303
+	 *
1304
+	 * @param array $params parameter array
1305
+	 *
1306
+	 * @return array filtered parameters
1307
+	 */
1308
+	public function getRealParams(array $params)
1309
+	{
1310
+		foreach ($params as $k => $p) {
1311
+			if (is_array($p)) {
1312
+				$params[$k] = $p[1];
1313
+			}
1314
+		}
1315
+
1316
+		return $params;
1317
+	}
1318
+
1319
+	/**
1320
+	 * Returns the token of each parameter out of the given parameter array.
1321
+	 *
1322
+	 * @param array $params parameter array
1323
+	 *
1324
+	 * @return array tokens
1325
+	 */
1326
+	public function getParamTokens(array $params)
1327
+	{
1328
+		foreach ($params as $k => $p) {
1329
+			if (is_array($p)) {
1330
+				$params[$k] = isset($p[2]) ? $p[2] : 0;
1331
+			}
1332
+		}
1333
+
1334
+		return $params;
1335
+	}
1336
+
1337
+	/**
1338
+	 * Entry point of the parser, it redirects calls to other parse* functions.
1339
+	 *
1340
+	 * @param string $in            the string within which we must parse something
1341
+	 * @param int    $from          the starting offset of the parsed area
1342
+	 * @param int    $to            the ending offset of the parsed area
1343
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
1344
+	 *                              default
1345
+	 * @param string $curBlock      the current parser-block being processed
1346
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
1347
+	 *                              or null by default
1348
+	 *
1349
+	 * @return string parsed values
1350
+	 * @throws CompilationException
1351
+	 */
1352
+	protected function parse($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1353
+	{
1354
+		if ($this->debug) {
1355
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1356
+		}
1357
+
1358
+		if ($to === null) {
1359
+			$to = strlen($in);
1360
+		}
1361
+		$first = substr($in, $from, 1);
1362
+
1363
+		if ($first === false) {
1364
+			throw new CompilationException($this, 'Unexpected EOF, a template tag was not closed');
1365
+		}
1366
+
1367
+		while ($first === ' ' || $first === "\n" || $first === "\t" || $first === "\r") {
1368
+			if ($curBlock === 'root' && substr($in, $from, strlen($this->rd)) === $this->rd) {
1369
+				// end template tag
1370
+				$pointer += strlen($this->rd);
1371
+				if ($this->debug) {
1372
+					echo 'TEMPLATE PARSING ENDED' . "\n";
1373
+				}
1374
+
1375
+				return false;
1376
+			}
1377
+			++ $from;
1378
+			if ($pointer !== null) {
1379
+				++ $pointer;
1380
+			}
1381
+			if ($from >= $to) {
1382
+				if (is_array($parsingParams)) {
1383
+					return $parsingParams;
1384
+				} else {
1385
+					return '';
1386
+				}
1387
+			}
1388
+			$first = $in[$from];
1389
+		}
1390
+
1391
+		$substr = substr($in, $from, $to - $from);
1392
+
1393
+		if ($this->debug) {
1394
+			echo 'PARSE CALL : PARSING "' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . '" @ ' . $from . ':' . $to . ' in ' . $curBlock . ' : pointer=' . $pointer . "\n";
1395
+		}
1396
+		$parsed = '';
1397
+
1398
+		if ($curBlock === 'root' && $first === '*') {
1399
+			$src      = $this->getTemplateSource();
1400
+			$startpos = $this->getPointer() - strlen($this->ld);
1401
+			if (substr($src, $startpos, strlen($this->ld)) === $this->ld) {
1402
+				if ($startpos > 0) {
1403
+					do {
1404
+						$char = substr($src, -- $startpos, 1);
1405
+						if ($char == "\n") {
1406
+							++ $startpos;
1407
+							$whitespaceStart = true;
1408
+							break;
1409
+						}
1410
+					}
1411
+					while ($startpos > 0 && ($char == ' ' || $char == "\t"));
1412
+				}
1413
+
1414
+				if (!isset($whitespaceStart)) {
1415
+					$startpos = $this->getPointer();
1416
+				} else {
1417
+					$pointer -= $this->getPointer() - $startpos;
1418
+				}
1419
+
1420
+				if ($this->allowNestedComments && strpos($src, $this->ld . '*', $this->getPointer()) !== false) {
1421
+					$comOpen  = $this->ld . '*';
1422
+					$comClose = '*' . $this->rd;
1423
+					$level    = 1;
1424
+					$ptr      = $this->getPointer();
1425
+
1426
+					while ($level > 0 && $ptr < strlen($src)) {
1427
+						$open  = strpos($src, $comOpen, $ptr);
1428
+						$close = strpos($src, $comClose, $ptr);
1429
+
1430
+						if ($open !== false && $close !== false) {
1431
+							if ($open < $close) {
1432
+								$ptr = $open + strlen($comOpen);
1433
+								++ $level;
1434
+							} else {
1435
+								$ptr = $close + strlen($comClose);
1436
+								-- $level;
1437
+							}
1438
+						} elseif ($open !== false) {
1439
+							$ptr = $open + strlen($comOpen);
1440
+							++ $level;
1441
+						} elseif ($close !== false) {
1442
+							$ptr = $close + strlen($comClose);
1443
+							-- $level;
1444
+						} else {
1445
+							$ptr = strlen($src);
1446
+						}
1447
+					}
1448
+					$endpos = $ptr - strlen('*' . $this->rd);
1449
+				} else {
1450
+					$endpos = strpos($src, '*' . $this->rd, $startpos);
1451
+					if ($endpos == false) {
1452
+						throw new CompilationException($this, 'Un-ended comment');
1453
+					}
1454
+				}
1455
+				$pointer += $endpos - $startpos + strlen('*' . $this->rd);
1456
+				if (isset($whitespaceStart) && preg_match('#^[\t ]*\r?\n#', substr($src, $endpos + strlen('*' . $this->rd)), $m)) {
1457
+					$pointer += strlen($m[0]);
1458
+					$this->curBlock['buffer'] = substr($this->curBlock['buffer'], 0, strlen($this->curBlock['buffer']) - ($this->getPointer() - $startpos - strlen($this->ld)));
1459
+				}
1460
+
1461
+				return false;
1462
+			}
1463
+		}
1464
+
1465
+		if ($first === '$') {
1466
+			// var
1467
+			$out    = $this->parseVar($in, $from, $to, $parsingParams, $curBlock, $pointer);
1468
+			$parsed = 'var';
1469
+		} elseif ($first === '%' && preg_match('#^%[a-z_\\\\]#i', $substr)) {
1470
+			// Short constant
1471
+			$out = $this->parseConst($in, $from, $to, $parsingParams, $curBlock, $pointer);
1472
+		} elseif (($first === '"' || $first === "'") && !(is_array($parsingParams) && preg_match('#^([\'"])[a-z0-9_]+\1\s*=>?(?:\s+|[^=])#i', $substr))) {
1473
+			// string
1474
+			$out = $this->parseString($in, $from, $to, $parsingParams, $curBlock, $pointer);
1475
+		} elseif (preg_match('/^\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?(' . (is_array($parsingParams) || $curBlock != 'root' ? '' : '\s+[^(]|') . '\s*\(|\s*' . $this->rdr . '|\s*;)/i', $substr)) {
1476
+			// func
1477
+			$out    = $this->parseFunction($in, $from, $to, $parsingParams, $curBlock, $pointer);
1478
+			$parsed = 'func';
1479
+		} elseif ($first === ';') {
1480
+			// instruction end
1481
+			if ($this->debug) {
1482
+				echo 'END OF INSTRUCTION' . "\n";
1483
+			}
1484
+			if ($pointer !== null) {
1485
+				++ $pointer;
1486
+			}
1487
+
1488
+			return $this->parse($in, $from + 1, $to, false, 'root', $pointer);
1489
+		} elseif ($curBlock === 'root' && preg_match('#^/([a-z_][a-z0-9_]*)?#i', $substr, $match)) {
1490
+			// close block
1491
+			if (!empty($match[1]) && $match[1] == 'else') {
1492
+				throw new CompilationException($this, 'Else blocks must not be closed explicitly, they are automatically closed when their parent block is closed');
1493
+			}
1494
+			if (!empty($match[1]) && $match[1] == 'elseif') {
1495
+				throw new CompilationException($this, 'Elseif blocks must not be closed explicitly, they are automatically closed when their parent block is closed or a new else/elseif block is declared after them');
1496
+			}
1497
+			if ($pointer !== null) {
1498
+				$pointer += strlen($match[0]);
1499
+			}
1500
+			if (empty($match[1])) {
1501
+				if ($this->curBlock['type'] == 'else' || $this->curBlock['type'] == 'elseif') {
1502
+					$pointer -= strlen($match[0]);
1503
+				}
1504
+				if ($this->debug) {
1505
+					echo 'TOP BLOCK CLOSED' . "\n";
1506
+				}
1507
+
1508
+				return $this->removeTopBlock();
1509
+			} else {
1510
+				if ($this->debug) {
1511
+					echo 'BLOCK OF TYPE ' . $match[1] . ' CLOSED' . "\n";
1512
+				}
1513
+
1514
+				return $this->removeBlock($match[1]);
1515
+			}
1516
+		} elseif ($curBlock === 'root' && substr($substr, 0, strlen($this->rd)) === $this->rd) {
1517
+			// end template tag
1518
+			if ($this->debug) {
1519
+				echo 'TAG PARSING ENDED' . "\n";
1520
+			}
1521
+			$pointer += strlen($this->rd);
1522
+
1523
+			return false;
1524
+		} elseif (is_array($parsingParams) && preg_match('#^(([\'"]?)[a-z0-9_]+\2\s*=' . ($curBlock === 'array' ? '>?' : '') . ')(?:\s+|[^=]).*#i', $substr, $match)) {
1525
+			// named parameter
1526
+			if ($this->debug) {
1527
+				echo 'NAMED PARAM FOUND' . "\n";
1528
+			}
1529
+			$len = strlen($match[1]);
1530
+			while (substr($in, $from + $len, 1) === ' ') {
1531
+				++ $len;
1532
+			}
1533
+			if ($pointer !== null) {
1534
+				$pointer += $len;
1535
+			}
1536
+
1537
+			$output = array(
1538
+				trim($match[1], " \t\r\n=>'\""),
1539
+				$this->parse($in, $from + $len, $to, false, 'namedparam', $pointer)
1540
+			);
1541
+
1542
+			$parsingParams[] = $output;
1543
+
1544
+			return $parsingParams;
1545
+		} elseif (preg_match('#^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*::\$[a-z0-9_]+)#i', $substr, $match)) {
1546
+			// static member access
1547
+			$parsed = 'var';
1548
+			if (is_array($parsingParams)) {
1549
+				$parsingParams[] = array($match[1], $match[1]);
1550
+				$out             = $parsingParams;
1551
+			} else {
1552
+				$out = $match[1];
1553
+			}
1554
+			$pointer += strlen($match[1]);
1555
+		} elseif ($substr !== '' && (is_array($parsingParams) || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'expression')) {
1556
+			// unquoted string, bool or number
1557
+			$out = $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1558
+		} else {
1559
+			// parse error
1560
+			throw new CompilationException($this, 'Parse error in "' . substr($in, $from, $to - $from) . '"');
1561
+		}
1562
+
1563
+		if (empty($out)) {
1564
+			return '';
1565
+		}
1566
+
1567
+		$substr = substr($in, $pointer, $to - $pointer);
1568
+
1569
+		// var parsed, check if any var-extension applies
1570
+		if ($parsed === 'var') {
1571
+			if (preg_match('#^\s*([/%+*-])\s*([a-z0-9]|\$)#i', $substr, $match)) {
1572
+				if ($this->debug) {
1573
+					echo 'PARSING POST-VAR EXPRESSION ' . $substr . "\n";
1574
+				}
1575
+				// parse expressions
1576
+				$pointer += strlen($match[0]) - 1;
1577
+				if (is_array($parsingParams)) {
1578
+					if ($match[2] == '$') {
1579
+						$expr = $this->parseVar($in, $pointer, $to, array(), $curBlock, $pointer);
1580
+					} else {
1581
+						$expr = $this->parse($in, $pointer, $to, array(), 'expression', $pointer);
1582
+					}
1583
+					$out[count($out) - 1][0] .= $match[1] . $expr[0][0];
1584
+					$out[count($out) - 1][1] .= $match[1] . $expr[0][1];
1585
+				} else {
1586
+					if ($match[2] == '$') {
1587
+						$expr = $this->parseVar($in, $pointer, $to, false, $curBlock, $pointer);
1588
+					} else {
1589
+						$expr = $this->parse($in, $pointer, $to, false, 'expression', $pointer);
1590
+					}
1591
+					if (is_array($out) && is_array($expr)) {
1592
+						$out[0] .= $match[1] . $expr[0];
1593
+						$out[1] .= $match[1] . $expr[1];
1594
+					} elseif (is_array($out)) {
1595
+						$out[0] .= $match[1] . $expr;
1596
+						$out[1] .= $match[1] . $expr;
1597
+					} elseif (is_array($expr)) {
1598
+						$out .= $match[1] . $expr[0];
1599
+					} else {
1600
+						$out .= $match[1] . $expr;
1601
+					}
1602
+				}
1603
+			} elseif ($curBlock === 'root' && preg_match('#^(\s*(?:[+/*%-.]=|=|\+\+|--)\s*)(.*)#s', $substr, $match)) {
1604
+				if ($this->debug) {
1605
+					echo 'PARSING POST-VAR ASSIGNMENT ' . $substr . "\n";
1606
+				}
1607
+				// parse assignment
1608
+				$value    = $match[2];
1609
+				$operator = trim($match[1]);
1610
+				if (substr($value, 0, 1) == '=') {
1611
+					throw new CompilationException($this, 'Unexpected "=" in <em>' . $substr . '</em>');
1612
+				}
1613
+
1614
+				if ($pointer !== null) {
1615
+					$pointer += strlen($match[1]);
1616
+				}
1617
+
1618
+				if ($operator !== '++' && $operator !== '--') {
1619
+					$parts = array();
1620
+					$ptr   = 0;
1621
+					$parts = $this->parse($value, 0, strlen($value), $parts, 'condition', $ptr);
1622
+					$pointer += $ptr;
1623
+
1624
+					// load if plugin
1625
+					try {
1626
+						$this->getPluginType('if');
1627
+					}
1628
+					catch (Exception $e) {
1629
+						throw new CompilationException($this, 'Assignments require the "if" plugin to be accessible');
1630
+					}
1631
+
1632
+					$parts  = $this->mapParams($parts, array(Core::NAMESPACE_PLUGINS_BLOCKS . 'PluginIf', 'init'), 1);
1633
+					$tokens = $this->getParamTokens($parts);
1634
+					$parts  = $this->getCompiledParams($parts);
1635
+
1636
+					$value = PluginIf::replaceKeywords($parts['*'], $tokens['*'], $this);
1637
+					$echo  = '';
1638
+				} else {
1639
+					$value = array();
1640
+					$echo  = 'echo ';
1641
+				}
1642
+
1643
+				if ($this->autoEscape) {
1644
+					$out = preg_replace('#\(is_string\(\$tmp=(.+?)\) \? htmlspecialchars\(\$tmp, ENT_QUOTES, \$this->charset\) : \$tmp\)#', '$1', $out);
1645
+				}
1646
+				$out = self::PHP_OPEN . $echo . $out . $operator . implode(' ', $value) . self::PHP_CLOSE;
1647
+			} elseif ($curBlock === 'array' && is_array($parsingParams) && preg_match('#^(\s*=>?\s*)#', $substr, $match)) {
1648
+				// parse namedparam with var as name (only for array)
1649
+				if ($this->debug) {
1650
+					echo 'VARIABLE NAMED PARAM (FOR ARRAY) FOUND' . "\n";
1651
+				}
1652
+				$len = strlen($match[1]);
1653
+				$var = $out[count($out) - 1];
1654
+				$pointer += $len;
1655
+
1656
+				$output = array($var[0], $this->parse($substr, $len, null, false, 'namedparam', $pointer));
1657
+
1658
+				$parsingParams[] = $output;
1659
+
1660
+				return $parsingParams;
1661
+			}
1662
+		}
1663
+
1664
+		if ($curBlock !== 'modifier' && ($parsed === 'func' || $parsed === 'var') && preg_match('#^(\|@?[a-z0-9_]+(:.*)?)+#i', $substr, $match)) {
1665
+			// parse modifier on funcs or vars
1666
+			$srcPointer = $pointer;
1667
+			if (is_array($parsingParams)) {
1668
+				$tmp                     = $this->replaceModifiers(
1669
+					array(
1670
+					null,
1671
+					null,
1672
+					$out[count($out) - 1][0],
1673
+					$match[0]
1674
+					), $curBlock, $pointer
1675
+				);
1676
+				$out[count($out) - 1][0] = $tmp;
1677
+				$out[count($out) - 1][1] .= substr($substr, $srcPointer, $srcPointer - $pointer);
1678
+			} else {
1679
+				$out = $this->replaceModifiers(array(null, null, $out, $match[0]), $curBlock, $pointer);
1680
+			}
1681
+		}
1682
+
1683
+		// func parsed, check if any func-extension applies
1684
+		if ($parsed === 'func' && preg_match('#^->[a-z0-9_]+(\s*\(.+|->[a-z_].*)?#is', $substr, $match)) {
1685
+			// parse method call or property read
1686
+			$ptr = 0;
1687
+
1688
+			if (is_array($parsingParams)) {
1689
+				$output = $this->parseMethodCall($out[count($out) - 1][1], $match[0], $curBlock, $ptr);
1690
+
1691
+				$out[count($out) - 1][0] = $output;
1692
+				$out[count($out) - 1][1] .= substr($match[0], 0, $ptr);
1693
+			} else {
1694
+				$out = $this->parseMethodCall($out, $match[0], $curBlock, $ptr);
1695
+			}
1696
+
1697
+			$pointer += $ptr;
1698
+		}
1699
+
1700
+		if ($curBlock === 'root' && substr($out, 0, strlen(self::PHP_OPEN)) !== self::PHP_OPEN) {
1701
+			return self::PHP_OPEN . 'echo ' . $out . ';' . self::PHP_CLOSE;
1702
+		} else {
1703
+			return $out;
1704
+		}
1705
+	}
1706
+
1707
+	/**
1708
+	 * Parses a function call.
1709
+	 *
1710
+	 * @param string $in            the string within which we must parse something
1711
+	 * @param int    $from          the starting offset of the parsed area
1712
+	 * @param int    $to            the ending offset of the parsed area
1713
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
1714
+	 *                              default
1715
+	 * @param string $curBlock      the current parser-block being processed
1716
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
1717
+	 *                              or null by default
1718
+	 *
1719
+	 * @return string parsed values
1720
+	 * @throws CompilationException
1721
+	 * @throws Exception
1722
+	 * @throws SecurityException
1723
+	 */
1724
+	protected function parseFunction($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1725
+	{
1726
+		$output = '';
1727
+		$cmdstr = substr($in, $from, $to - $from);
1728
+		preg_match('/^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?)(\s*' . $this->rdr . '|\s*;)?/i', $cmdstr, $match);
1729
+
1730
+		if (empty($match[1])) {
1731
+			throw new CompilationException($this, 'Parse error, invalid function name : ' . substr($cmdstr, 0, 15));
1732
+		}
1733
+
1734
+		$func = $match[1];
1735
+
1736
+		if (!empty($match[2])) {
1737
+			$cmdstr = $match[1];
1738
+		}
1739
+
1740
+		if ($this->debug) {
1741
+			echo 'FUNC FOUND (' . $func . ')' . "\n";
1742
+		}
1743
+
1744
+		$paramsep = '';
1745
+
1746
+		if (is_array($parsingParams) || $curBlock != 'root') {
1747
+			$paramspos = strpos($cmdstr, '(');
1748
+			$paramsep  = ')';
1749
+		} elseif (preg_match_all('#^\s*[\\\\:a-z0-9_]+(\s*\(|\s+[^(])#i', $cmdstr, $match, PREG_OFFSET_CAPTURE)) {
1750
+			$paramspos = $match[1][0][1];
1751
+			$paramsep  = substr($match[1][0][0], - 1) === '(' ? ')' : '';
1752
+			if ($paramsep === ')') {
1753
+				$paramspos += strlen($match[1][0][0]) - 1;
1754
+				if (substr($cmdstr, 0, 2) === 'if' || substr($cmdstr, 0, 6) === 'elseif') {
1755
+					$paramsep = '';
1756
+					if (strlen($match[1][0][0]) > 1) {
1757
+						-- $paramspos;
1758
+					}
1759
+				}
1760
+			}
1761
+		} else {
1762
+			$paramspos = false;
1763
+		}
1764
+
1765
+		$state = 0;
1766
+
1767
+		if ($paramspos === false) {
1768
+			$params = array();
1769
+
1770
+			if ($curBlock !== 'root') {
1771
+				return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1772
+			}
1773
+		} else {
1774
+			if ($curBlock === 'condition') {
1775
+				// load if plugin
1776
+				$this->getPluginType('if');
1777
+
1778
+				if (PluginIf::replaceKeywords(array($func), array(self::T_UNQUOTED_STRING), $this) !== array($func)) {
1779
+					return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1780
+				}
1781
+			}
1782
+			$whitespace = strlen(substr($cmdstr, strlen($func), $paramspos - strlen($func)));
1783
+			$paramstr   = substr($cmdstr, $paramspos + 1);
1784
+			if (substr($paramstr, - 1, 1) === $paramsep) {
1785
+				$paramstr = substr($paramstr, 0, - 1);
1786
+			}
1787
+
1788
+			if (strlen($paramstr) === 0) {
1789
+				$params   = array();
1790
+				$paramstr = '';
1791
+			} else {
1792
+				$ptr    = 0;
1793
+				$params = array();
1794
+				if ($func === 'empty') {
1795
+					$params = $this->parseVar($paramstr, $ptr, strlen($paramstr), $params, 'root', $ptr);
1796
+				} else {
1797
+					while ($ptr < strlen($paramstr)) {
1798
+						while (true) {
1799
+							if ($ptr >= strlen($paramstr)) {
1800
+								break 2;
1801
+							}
1802
+
1803
+							if ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === ')') {
1804
+								if ($this->debug) {
1805
+									echo 'PARAM PARSING ENDED, ")" FOUND, POINTER AT ' . $ptr . "\n";
1806
+								}
1807
+								break 2;
1808
+							} elseif ($paramstr[$ptr] === ';') {
1809
+								++ $ptr;
1810
+								if ($this->debug) {
1811
+									echo 'PARAM PARSING ENDED, ";" FOUND, POINTER AT ' . $ptr . "\n";
1812
+								}
1813
+								break 2;
1814
+							} elseif ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === '/') {
1815
+								if ($this->debug) {
1816
+									echo 'PARAM PARSING ENDED, "/" FOUND, POINTER AT ' . $ptr . "\n";
1817
+								}
1818
+								break 2;
1819
+							} elseif (substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
1820
+								if ($this->debug) {
1821
+									echo 'PARAM PARSING ENDED, RIGHT DELIMITER FOUND, POINTER AT ' . $ptr . "\n";
1822
+								}
1823
+								break 2;
1824
+							}
1825
+
1826
+							if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === ',' || $paramstr[$ptr] === "\r" || $paramstr[$ptr] === "\n" || $paramstr[$ptr] === "\t") {
1827
+								++ $ptr;
1828
+							} else {
1829
+								break;
1830
+							}
1831
+						}
1832
+
1833
+						if ($this->debug) {
1834
+							echo 'FUNC START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
1835
+						}
1836
+
1837
+						if ($func === 'if' || $func === 'elseif' || $func === 'tif') {
1838
+							$params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'condition', $ptr);
1839
+						} elseif ($func === 'array') {
1840
+							$params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'array', $ptr);
1841
+						} else {
1842
+							$params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'function', $ptr);
1843
+						}
1844
+
1845
+						if ($this->debug) {
1846
+							echo 'PARAM PARSED, POINTER AT ' . $ptr . ' (' . substr($paramstr, $ptr - 1, 3) . ')' . "\n";
1847
+						}
1848
+					}
1849
+				}
1850
+				$paramstr = substr($paramstr, 0, $ptr);
1851
+				$state    = 0;
1852
+				foreach ($params as $k => $p) {
1853
+					if (is_array($p) && is_array($p[1])) {
1854
+						$state |= 2;
1855
+					} else {
1856
+						if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m) && $func !== 'array') {
1857
+							$params[$k] = array($m[2], array('true', 'true'));
1858
+						} else {
1859
+							if ($state & 2 && $func !== 'array') {
1860
+								throw new CompilationException($this, 'You can not use an unnamed parameter after a named one');
1861
+							}
1862
+							$state |= 1;
1863
+						}
1864
+					}
1865
+				}
1866
+			}
1867
+		}
1868
+
1869
+		if ($pointer !== null) {
1870
+			$pointer += (isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func) + (isset($whitespace) ? $whitespace : 0);
1871
+			if ($this->debug) {
1872
+				echo 'FUNC ADDS ' . ((isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func)) . ' TO POINTER' . "\n";
1873
+			}
1874
+		}
1875
+
1876
+		if ($curBlock === 'method' || $func === 'do' || strstr($func, '::') !== false) {
1877
+			// handle static method calls with security policy
1878
+			if (strstr($func, '::') !== false && $this->securityPolicy !== null && $this->securityPolicy->isMethodAllowed(explode('::', strtolower($func))) !== true) {
1879
+				throw new SecurityException('Call to a disallowed php function : ' . $func);
1880
+			}
1881
+			$pluginType = Core::NATIVE_PLUGIN;
1882
+		} else {
1883
+			$pluginType = $this->getPluginType($func);
1884
+		}
1885
+
1886
+		// Blocks plugin
1887
+		if ($pluginType & Core::BLOCK_PLUGIN) {
1888
+			if ($curBlock !== 'root' || is_array($parsingParams)) {
1889
+				throw new CompilationException($this, 'Block plugins can not be used as other plugin\'s arguments');
1890
+			}
1891
+			if ($pluginType & Core::CUSTOM_PLUGIN) {
1892
+				return $this->addCustomBlock($func, $params, $state);
1893
+			} else {
1894
+				return $this->addBlock($func, $params, $state);
1895
+			}
1896
+		} elseif ($pluginType & Core::SMARTY_BLOCK) {
1897
+			if ($curBlock !== 'root' || is_array($parsingParams)) {
1898
+				throw new CompilationException($this, 'Block plugins can not be used as other plugin\'s arguments');
1899
+			}
1900
+
1901
+			if ($state & 2) {
1902
+				array_unshift($params, array('__functype', array($pluginType, $pluginType)));
1903
+				array_unshift($params, array('__funcname', array($func, $func)));
1904
+			} else {
1905
+				array_unshift($params, array($pluginType, $pluginType));
1906
+				array_unshift($params, array($func, $func));
1907
+			}
1908
+
1909
+			return $this->addBlock('smartyinterface', $params, $state);
1910
+		}
1911
+
1912
+		// Functions plugin
1913
+		if ($pluginType & Core::NATIVE_PLUGIN || $pluginType & Core::SMARTY_FUNCTION || $pluginType & Core::SMARTY_BLOCK) {
1914
+			$params = $this->mapParams($params, null, $state);
1915
+		} elseif ($pluginType & Core::CLASS_PLUGIN) {
1916
+			if ($pluginType & Core::CUSTOM_PLUGIN) {
1917
+				$params = $this->mapParams(
1918
+					$params, array(
1919
+					$this->customPlugins[$func]['class'],
1920
+					$this->customPlugins[$func]['function']
1921
+				), $state);
1922
+			} else {
1923
+				if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
1924
+					$params = $this->mapParams($params, array(
1925
+						'Plugin' . Core::toCamelCase($func),
1926
+						($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1927
+					), $state);
1928
+				} else {
1929
+					$params = $this->mapParams($params, array(
1930
+						Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
1931
+						($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1932
+					), $state);
1933
+				}
1934
+			}
1935
+		} elseif ($pluginType & Core::FUNC_PLUGIN) {
1936
+			if ($pluginType & Core::CUSTOM_PLUGIN) {
1937
+				$params = $this->mapParams($params, $this->customPlugins[$func]['callback'], $state);
1938
+			} else {
1939
+				// Custom plugin
1940
+				if (function_exists('Plugin' . Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ?
1941
+						'Compile' : '')) !== false) {
1942
+					$params = $this->mapParams($params, 'Plugin' . Core::toCamelCase($func) . (($pluginType &
1943
+							Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1944
+				} // Builtin helper plugin
1945
+				elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . (
1946
+					($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '')) !== false) {
1947
+					$params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase
1948
+						($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1949
+				} // Builtin function plugin
1950
+				else {
1951
+					$params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase
1952
+						($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1953
+				}
1954
+			}
1955
+		} elseif ($pluginType & Core::SMARTY_MODIFIER) {
1956
+			$output = 'smarty_modifier_' . $func . '(' . implode(', ', $params) . ')';
1957
+		} elseif ($pluginType & Core::PROXY_PLUGIN) {
1958
+			$params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state);
1959
+		} elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
1960
+			// transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values))
1961
+			$map = array();
1962
+			foreach ($this->templatePlugins[$func]['params'] as $param => $defValue) {
1963
+				if ($param == 'rest') {
1964
+					$param = '*';
1965
+				}
1966
+				$hasDefault = $defValue !== null;
1967
+				if ($defValue === 'null') {
1968
+					$defValue = null;
1969
+				} elseif ($defValue === 'false') {
1970
+					$defValue = false;
1971
+				} elseif ($defValue === 'true') {
1972
+					$defValue = true;
1973
+				} elseif (preg_match('#^([\'"]).*?\1$#', $defValue)) {
1974
+					$defValue = substr($defValue, 1, - 1);
1975
+				}
1976
+				$map[] = array($param, $hasDefault, $defValue);
1977
+			}
1978
+
1979
+			$params = $this->mapParams($params, null, $state, $map);
1980
+		}
1981
+
1982
+		// only keep php-syntax-safe values for non-block plugins
1983
+		$tokens = array();
1984
+		foreach ($params as $k => $p) {
1985
+			$tokens[$k] = isset($p[2]) ? $p[2] : 0;
1986
+			$params[$k] = $p[0];
1987
+		}
1988
+		if ($pluginType & Core::NATIVE_PLUGIN) {
1989
+			if ($func === 'do') {
1990
+				if (isset($params['*'])) {
1991
+					$output = implode(';', $params['*']) . ';';
1992
+				} else {
1993
+					$output = '';
1994
+				}
1995
+
1996
+				if (is_array($parsingParams) || $curBlock !== 'root') {
1997
+					throw new CompilationException($this, 'Do can not be used inside another function or block');
1998
+				} else {
1999
+					return self::PHP_OPEN . $output . self::PHP_CLOSE;
2000
+				}
2001
+			} else {
2002
+				if (isset($params['*'])) {
2003
+					$output = $func . '(' . implode(', ', $params['*']) . ')';
2004
+				} else {
2005
+					$output = $func . '()';
2006
+				}
2007
+			}
2008
+		} elseif ($pluginType & Core::FUNC_PLUGIN) {
2009
+			if ($pluginType & Core::COMPILABLE_PLUGIN) {
2010
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
2011
+					$funcCompiler = $this->customPlugins[$func]['callback'];
2012
+				} else {
2013
+					// Custom plugin
2014
+					if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2015
+						$funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
2016
+					} // Builtin helper plugin
2017
+					elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) .
2018
+							'Compile') !== false) {
2019
+						$funcCompiler = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) .
2020
+							'Compile';
2021
+					} // Builtin function plugin
2022
+					else {
2023
+						$funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
2024
+							'Compile';
2025
+					}
2026
+				}
2027
+				array_unshift($params, $this);
2028
+				if ($func === 'tif') {
2029
+					$params[] = $tokens;
2030
+				}
2031
+				$output = call_user_func_array($funcCompiler, $params);
2032
+			} else {
2033
+				array_unshift($params, '$this');
2034
+				$params = self::implode_r($params);
2035
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
2036
+					$callback = $this->customPlugins[$func]['callback'];
2037
+					if ($callback instanceof Closure) {
2038
+						$output = 'call_user_func($this->getCustomPlugin(\'' . $func . '\'), ' . $params . ')';
2039
+					} else {
2040
+						$output = 'call_user_func(\'' . $callback . '\', ' . $params . ')';
2041
+					}
2042
+				} else {
2043
+					// Custom plugin
2044
+					if (function_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2045
+						$output = 'Plugin' . Core::toCamelCase($func) . '(' . $params .
2046
+							')';
2047
+					} // Builtin helper plugin
2048
+					elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !==
2049
+						false) {
2050
+						$output = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . '(' .
2051
+							$params . ')';
2052
+					} // Builtin function plugin
2053
+					else {
2054
+						$output = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '(' .
2055
+							$params . ')';
2056
+					}
2057
+				}
2058
+			}
2059
+		} elseif ($pluginType & Core::CLASS_PLUGIN) {
2060
+			if ($pluginType & Core::COMPILABLE_PLUGIN) {
2061
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
2062
+					$callback = $this->customPlugins[$func]['callback'];
2063
+					if (!is_array($callback)) {
2064
+						if (!method_exists($callback, 'compile')) {
2065
+							throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
2066
+						}
2067
+						if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
2068
+							$funcCompiler = array($callback, 'compile');
2069
+						} else {
2070
+							$funcCompiler = array(new $callback(), 'compile');
2071
+						}
2072
+					} else {
2073
+						$funcCompiler = $callback;
2074
+					}
2075
+				} else {
2076
+					if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2077
+						$funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
2078
+					} else {
2079
+						$funcCompiler = array(
2080
+							Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
2081
+							'compile'
2082
+						);
2083
+					}
2084
+					array_unshift($params, $this);
2085
+				}
2086
+				$output = call_user_func_array($funcCompiler, $params);
2087
+			} else {
2088
+				$params = self::implode_r($params);
2089
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
2090
+					$callback = $this->customPlugins[$func]['callback'];
2091
+					if (!is_array($callback)) {
2092
+						if (!method_exists($callback, 'process')) {
2093
+							throw new Exception('Custom plugin ' . $func . ' must implement the "process" method to be usable, or you should provide a full callback to the method to use');
2094
+						}
2095
+						if (($ref = new ReflectionMethod($callback, 'process')) && $ref->isStatic()) {
2096
+							$output = 'call_user_func(array(\'' . $callback . '\', \'process\'), ' . $params . ')';
2097
+						} else {
2098
+							$output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback . '\'), \'process\'), ' . $params . ')';
2099
+						}
2100
+					} elseif (is_object($callback[0])) {
2101
+						$output = 'call_user_func(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), ' . $params . ')';
2102
+					} elseif (($ref = new ReflectionMethod($callback[0], $callback[1])) && $ref->isStatic()) {
2103
+						$output = 'call_user_func(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), ' . $params . ')';
2104
+					} else {
2105
+						$output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback[0] . '\'), \'' . $callback[1] . '\'), ' . $params . ')';
2106
+					}
2107
+					if (empty($params)) {
2108
+						$output = substr($output, 0, - 3) . ')';
2109
+					}
2110
+				} else {
2111
+					if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2112
+						$output = '$this->classCall(\'Plugin' . $func . '\', array(' . $params . '))';
2113
+					} elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !==
2114
+					false) {
2115
+						$output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\', 
2116 2116
                         array(' . $params . '))';
2117
-                    } else{
2118
-                        $output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
2119
-                    }
2120
-                }
2121
-            }
2122
-        } elseif ($pluginType & Core::PROXY_PLUGIN) {
2123
-            $output = call_user_func(array($this->getDwoo()->getPluginProxy(), 'getCode'), $func, $params);
2124
-        } elseif ($pluginType & Core::SMARTY_FUNCTION) {
2125
-            if (isset($params['*'])) {
2126
-                $params = self::implode_r($params['*'], true);
2127
-            } else {
2128
-                $params = '';
2129
-            }
2130
-
2131
-            if ($pluginType & Core::CUSTOM_PLUGIN) {
2132
-                $callback = $this->customPlugins[$func]['callback'];
2133
-                if (is_array($callback)) {
2134
-                    if (is_object($callback[0])) {
2135
-                        $output = 'call_user_func_array(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2136
-                    } else {
2137
-                        $output = 'call_user_func_array(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2138
-                    }
2139
-                } else {
2140
-                    $output = $callback . '(array(' . $params . '), $this)';
2141
-                }
2142
-            } else {
2143
-                $output = 'smarty_function_' . $func . '(array(' . $params . '), $this)';
2144
-            }
2145
-        } elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
2146
-            array_unshift($params, '$this');
2147
-            $params                                 = self::implode_r($params);
2148
-            $output                                 = 'Plugin' . Core::toCamelCase($func) .
2149
-                $this->templatePlugins[$func]['uuid'] . '(' . $params . ')';
2150
-            $this->templatePlugins[$func]['called'] = true;
2151
-        }
2152
-
2153
-        if (is_array($parsingParams)) {
2154
-            $parsingParams[] = array($output, $output);
2155
-
2156
-            return $parsingParams;
2157
-        } elseif ($curBlock === 'namedparam') {
2158
-            return array($output, $output);
2159
-        } else {
2160
-            return $output;
2161
-        }
2162
-    }
2163
-
2164
-    /**
2165
-     * Parses a string.
2166
-     *
2167
-     * @param string $in            the string within which we must parse something
2168
-     * @param int    $from          the starting offset of the parsed area
2169
-     * @param int    $to            the ending offset of the parsed area
2170
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2171
-     *                              default
2172
-     * @param string $curBlock      the current parser-block being processed
2173
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2174
-     *                              or null by default
2175
-     *
2176
-     * @return string parsed values
2177
-     * @throws CompilationException
2178
-     */
2179
-    protected function parseString($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2180
-    {
2181
-        $substr = substr($in, $from, $to - $from);
2182
-        $first  = $substr[0];
2183
-
2184
-        if ($this->debug) {
2185
-            echo 'STRING FOUND (in ' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . ')' . "\n";
2186
-        }
2187
-        $strend = false;
2188
-        $o      = $from + 1;
2189
-        while ($strend === false) {
2190
-            $strend = strpos($in, $first, $o);
2191
-            if ($strend === false) {
2192
-                throw new CompilationException($this, 'Unfinished string, started with ' . substr($in, $from, $to - $from));
2193
-            }
2194
-            if (substr($in, $strend - 1, 1) === '\\') {
2195
-                $o      = $strend + 1;
2196
-                $strend = false;
2197
-            }
2198
-        }
2199
-        if ($this->debug) {
2200
-            echo 'STRING DELIMITED: ' . substr($in, $from, $strend + 1 - $from) . "\n";
2201
-        }
2202
-
2203
-        $srcOutput = substr($in, $from, $strend + 1 - $from);
2204
-
2205
-        if ($pointer !== null) {
2206
-            $pointer += strlen($srcOutput);
2207
-        }
2208
-
2209
-        $output = $this->replaceStringVars($srcOutput, $first);
2210
-
2211
-        // handle modifiers
2212
-        if ($curBlock !== 'modifier' && preg_match('#^((?:\|(?:@?[a-z0-9_]+(?::.*)*))+)#i', substr($substr, $strend + 1 - $from), $match)) {
2213
-            $modstr = $match[1];
2214
-
2215
-            if ($curBlock === 'root' && substr($modstr, - 1) === '}') {
2216
-                $modstr = substr($modstr, 0, - 1);
2217
-            }
2218
-            $modstr = str_replace('\\' . $first, $first, $modstr);
2219
-            $ptr    = 0;
2220
-            $output = $this->replaceModifiers(array(null, null, $output, $modstr), 'string', $ptr);
2221
-
2222
-            $strend += $ptr;
2223
-            if ($pointer !== null) {
2224
-                $pointer += $ptr;
2225
-            }
2226
-            $srcOutput .= substr($substr, $strend + 1 - $from, $ptr);
2227
-        }
2228
-
2229
-        if (is_array($parsingParams)) {
2230
-            $parsingParams[] = array($output, substr($srcOutput, 1, - 1));
2231
-
2232
-            return $parsingParams;
2233
-        } elseif ($curBlock === 'namedparam') {
2234
-            return array($output, substr($srcOutput, 1, - 1));
2235
-        } else {
2236
-            return $output;
2237
-        }
2238
-    }
2239
-
2240
-    /**
2241
-     * Parses a constant.
2242
-     *
2243
-     * @param string $in            the string within which we must parse something
2244
-     * @param int    $from          the starting offset of the parsed area
2245
-     * @param int    $to            the ending offset of the parsed area
2246
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2247
-     *                              default
2248
-     * @param string $curBlock      the current parser-block being processed
2249
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2250
-     *                              or null by default
2251
-     *
2252
-     * @return string parsed values
2253
-     * @throws CompilationException
2254
-     */
2255
-    protected function parseConst($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2256
-    {
2257
-        $substr = substr($in, $from, $to - $from);
2258
-
2259
-        if ($this->debug) {
2260
-            echo 'CONST FOUND : ' . $substr . "\n";
2261
-        }
2262
-
2263
-        if (!preg_match('#^%([\\\\a-z0-9_:]+)#i', $substr, $m)) {
2264
-            throw new CompilationException($this, 'Invalid constant');
2265
-        }
2266
-
2267
-        if ($pointer !== null) {
2268
-            $pointer += strlen($m[0]);
2269
-        }
2270
-
2271
-        $output = $this->parseConstKey($m[1], $curBlock);
2272
-
2273
-        if (is_array($parsingParams)) {
2274
-            $parsingParams[] = array($output, $m[1]);
2275
-
2276
-            return $parsingParams;
2277
-        } elseif ($curBlock === 'namedparam') {
2278
-            return array($output, $m[1]);
2279
-        } else {
2280
-            return $output;
2281
-        }
2282
-    }
2283
-
2284
-    /**
2285
-     * Parses a constant.
2286
-     *
2287
-     * @param string $key      the constant to parse
2288
-     * @param string $curBlock the current parser-block being processed
2289
-     *
2290
-     * @return string parsed constant
2291
-     */
2292
-    protected function parseConstKey($key, $curBlock)
2293
-    {
2294
-        if ($this->securityPolicy !== null && $this->securityPolicy->getConstantHandling() === SecurityPolicy::CONST_DISALLOW) {
2295
-            return 'null';
2296
-        }
2297
-
2298
-        if ($curBlock !== 'root') {
2299
-            $output = '(defined("' . $key . '") ? ' . $key . ' : null)';
2300
-        } else {
2301
-            $output = $key;
2302
-        }
2303
-
2304
-        return $output;
2305
-    }
2306
-
2307
-    /**
2308
-     * Parses a variable.
2309
-     *
2310
-     * @param string $in            the string within which we must parse something
2311
-     * @param int    $from          the starting offset of the parsed area
2312
-     * @param int    $to            the ending offset of the parsed area
2313
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2314
-     *                              default
2315
-     * @param string $curBlock      the current parser-block being processed
2316
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2317
-     *                              or null by default
2318
-     *
2319
-     * @return string parsed values
2320
-     * @throws CompilationException
2321
-     */
2322
-    protected function parseVar($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2323
-    {
2324
-        $substr = substr($in, $from, $to - $from);
2325
-
2326
-        // var key
2327
-        $varRegex = '(\\$?\\.?[a-z0-9\\\\_:]*(?:(?:(?:\\.|->)(?:[a-z0-9\\\\_:]+|(?R))|\\[(?:[a-z0-9\\\\_:]+|(?R)|(["\'])[^\\2]*?\\2)\\]))*)';
2328
-        // method call
2329
-        $methodCall = ($curBlock === 'root' || $curBlock === 'function' || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'variable' || $curBlock === 'expression' || $curBlock === 'delimited_string' ? '(\(.*)?' : '()');
2330
-        // simple math expressions
2331
-        $simpleMathExpressions = ($curBlock === 'root' || $curBlock === 'function' || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'variable' || $curBlock === 'delimited_string' ? '((?:(?:[+\/*%=-])(?:(?<!=)=?-?[$%][a-z0-9\\\\.[\]>_:-]+(?:\([^)]*\))?|(?<!=)=?-?[0-9\.,]*|[+-]))*)' : '()');
2332
-        // modifiers
2333
-        $modifiers = $curBlock !== 'modifier' ? '((?:\|(?:@?[a-z0-9\\\\_]+(?:(?::("|\').*?\5|:[^`]*))*))+)?' : '(())';
2334
-
2335
-        $regex = '#';
2336
-        $regex .= $varRegex;
2337
-        $regex .= $methodCall;
2338
-        $regex .= $simpleMathExpressions;
2339
-        $regex .= $modifiers;
2340
-        $regex .= '#i';
2341
-
2342
-        if (preg_match($regex, $substr, $match)) {
2343
-            $key = substr($match[1], 1);
2344
-
2345
-            $matchedLength = strlen($match[0]);
2346
-            $hasModifiers  = !empty($match[5]);
2347
-            $hasExpression = !empty($match[4]);
2348
-            $hasMethodCall = !empty($match[3]);
2349
-
2350
-            if (substr($key, - 1) == '.') {
2351
-                $key = substr($key, 0, - 1);
2352
-                -- $matchedLength;
2353
-            }
2354
-
2355
-            if ($hasMethodCall) {
2356
-                $matchedLength -= strlen($match[3]) + strlen(substr($match[1], strrpos($match[1], '->')));
2357
-                $key        = substr($match[1], 1, strrpos($match[1], '->') - 1);
2358
-                $methodCall = substr($match[1], strrpos($match[1], '->')) . $match[3];
2359
-            }
2360
-
2361
-            if ($hasModifiers) {
2362
-                $matchedLength -= strlen($match[5]);
2363
-            }
2364
-
2365
-            if ($pointer !== null) {
2366
-                $pointer += $matchedLength;
2367
-            }
2368
-
2369
-            // replace useless brackets by dot accessed vars and strip enclosing quotes if present
2370
-            $key = preg_replace('#\[(["\']?)([^$%\[.>-]+)\1\]#', '.$2', $key);
2371
-
2372
-            if ($this->debug) {
2373
-                if ($hasMethodCall) {
2374
-                    echo 'METHOD CALL FOUND : $' . $key . substr($methodCall, 0, 30) . "\n";
2375
-                } else {
2376
-                    echo 'VAR FOUND : $' . $key . "\n";
2377
-                }
2378
-            }
2379
-
2380
-            $key = str_replace('"', '\\"', $key);
2381
-
2382
-            $cnt = substr_count($key, '$');
2383
-            if ($cnt > 0) {
2384
-                $uid           = 0;
2385
-                $parsed        = array($uid => '');
2386
-                $current       = &$parsed;
2387
-                $curTxt        = &$parsed[$uid ++];
2388
-                $tree          = array();
2389
-                $chars         = str_split($key, 1);
2390
-                $inSplittedVar = false;
2391
-                $bracketCount  = 0;
2392
-
2393
-                while (($char = array_shift($chars)) !== null) {
2394
-                    if ($char === '[') {
2395
-                        if (count($tree) > 0) {
2396
-                            ++ $bracketCount;
2397
-                        } else {
2398
-                            $tree[]        = &$current;
2399
-                            $current[$uid] = array($uid + 1 => '');
2400
-                            $current       = &$current[$uid ++];
2401
-                            $curTxt        = &$current[$uid ++];
2402
-                            continue;
2403
-                        }
2404
-                    } elseif ($char === ']') {
2405
-                        if ($bracketCount > 0) {
2406
-                            -- $bracketCount;
2407
-                        } else {
2408
-                            $current = &$tree[count($tree) - 1];
2409
-                            array_pop($tree);
2410
-                            if (current($chars) !== '[' && current($chars) !== false && current($chars) !== ']') {
2411
-                                $current[$uid] = '';
2412
-                                $curTxt        = &$current[$uid ++];
2413
-                            }
2414
-                            continue;
2415
-                        }
2416
-                    } elseif ($char === '$') {
2417
-                        if (count($tree) == 0) {
2418
-                            $curTxt        = &$current[$uid ++];
2419
-                            $inSplittedVar = true;
2420
-                        }
2421
-                    } elseif (($char === '.' || $char === '-') && count($tree) == 0 && $inSplittedVar) {
2422
-                        $curTxt        = &$current[$uid ++];
2423
-                        $inSplittedVar = false;
2424
-                    }
2425
-
2426
-                    $curTxt .= $char;
2427
-                }
2428
-                unset($uid, $current, $curTxt, $tree, $chars);
2429
-
2430
-                if ($this->debug) {
2431
-                    echo 'RECURSIVE VAR REPLACEMENT : ' . $key . "\n";
2432
-                }
2433
-
2434
-                $key = $this->flattenVarTree($parsed);
2435
-
2436
-                if ($this->debug) {
2437
-                    echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2438
-                }
2439
-
2440
-                $output = preg_replace('#(^""\.|""\.|\.""$|(\()""\.|\.""(\)))#', '$2$3', '$this->readVar("' . $key . '")');
2441
-            } else {
2442
-                $output = $this->parseVarKey($key, $hasModifiers ? 'modifier' : $curBlock);
2443
-            }
2444
-
2445
-
2446
-            // methods
2447
-            if ($hasMethodCall) {
2448
-                $ptr = 0;
2449
-
2450
-                $output = $this->parseMethodCall($output, $methodCall, $curBlock, $ptr);
2451
-
2452
-                if ($pointer !== null) {
2453
-                    $pointer += $ptr;
2454
-                }
2455
-                $matchedLength += $ptr;
2456
-            }
2457
-
2458
-            if ($hasExpression) {
2459
-                // expressions
2460
-                preg_match_all('#(?:([+/*%=-])(=?-?[%$][a-z0-9\\\\.[\]>_:-]+(?:\([^)]*\))?|=?-?[0-9.,]+|\1))#i', $match[4], $expMatch);
2461
-                foreach ($expMatch[1] as $k => $operator) {
2462
-                    if (substr($expMatch[2][$k], 0, 1) === '=') {
2463
-                        $assign = true;
2464
-                        if ($operator === '=') {
2465
-                            throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, can not use "==" in expressions');
2466
-                        }
2467
-                        if ($curBlock !== 'root') {
2468
-                            throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, assignments can only be used in top level expressions like {$foo+=3} or {$foo="bar"}');
2469
-                        }
2470
-                        $operator .= '=';
2471
-                        $expMatch[2][$k] = substr($expMatch[2][$k], 1);
2472
-                    }
2473
-
2474
-                    if (substr($expMatch[2][$k], 0, 1) === '-' && strlen($expMatch[2][$k]) > 1) {
2475
-                        $operator .= '-';
2476
-                        $expMatch[2][$k] = substr($expMatch[2][$k], 1);
2477
-                    }
2478
-                    if (($operator === '+' || $operator === '-') && $expMatch[2][$k] === $operator) {
2479
-                        $output = '(' . $output . $operator . $operator . ')';
2480
-                        break;
2481
-                    } elseif (substr($expMatch[2][$k], 0, 1) === '$') {
2482
-                        $output = '(' . $output . ' ' . $operator . ' ' . $this->parseVar($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2483
-                    } elseif (substr($expMatch[2][$k], 0, 1) === '%') {
2484
-                        $output = '(' . $output . ' ' . $operator . ' ' . $this->parseConst($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2485
-                    } elseif (!empty($expMatch[2][$k])) {
2486
-                        $output = '(' . $output . ' ' . $operator . ' ' . str_replace(',', '.', $expMatch[2][$k]) . ')';
2487
-                    } else {
2488
-                        throw new CompilationException($this, 'Unfinished expression <em>' . $substr . '</em>, missing var or number after math operator');
2489
-                    }
2490
-                }
2491
-            }
2492
-
2493
-            if ($this->autoEscape === true && $curBlock !== 'condition') {
2494
-                $output = '(is_string($tmp=' . $output . ') ? htmlspecialchars($tmp, ENT_QUOTES, $this->charset) : $tmp)';
2495
-            }
2496
-
2497
-            // handle modifiers
2498
-            if ($curBlock !== 'modifier' && $hasModifiers) {
2499
-                $ptr    = 0;
2500
-                $output = $this->replaceModifiers(array(null, null, $output, $match[5]), 'var', $ptr);
2501
-                if ($pointer !== null) {
2502
-                    $pointer += $ptr;
2503
-                }
2504
-                $matchedLength += $ptr;
2505
-            }
2506
-
2507
-            if (is_array($parsingParams)) {
2508
-                $parsingParams[] = array($output, $key);
2509
-
2510
-                return $parsingParams;
2511
-            } elseif ($curBlock === 'namedparam') {
2512
-                return array($output, $key);
2513
-            } elseif ($curBlock === 'string' || $curBlock === 'delimited_string') {
2514
-                return array($matchedLength, $output);
2515
-            } elseif ($curBlock === 'expression' || $curBlock === 'variable') {
2516
-                return $output;
2517
-            } elseif (isset($assign)) {
2518
-                return self::PHP_OPEN . $output . ';' . self::PHP_CLOSE;
2519
-            } else {
2520
-                return $output;
2521
-            }
2522
-        } else {
2523
-            if ($curBlock === 'string' || $curBlock === 'delimited_string') {
2524
-                return array(0, '');
2525
-            } else {
2526
-                throw new CompilationException($this, 'Invalid variable name <em>' . $substr . '</em>');
2527
-            }
2528
-        }
2529
-    }
2530
-
2531
-    /**
2532
-     * Parses any number of chained method calls/property reads.
2533
-     *
2534
-     * @param string $output     the variable or whatever upon which the method are called
2535
-     * @param string $methodCall method call source, starting at "->"
2536
-     * @param string $curBlock   the current parser-block being processed
2537
-     * @param int    $pointer    a reference to a pointer that will be increased by the amount of characters parsed
2538
-     *
2539
-     * @return string parsed call(s)/read(s)
2540
-     */
2541
-    protected function parseMethodCall($output, $methodCall, $curBlock, &$pointer)
2542
-    {
2543
-        $ptr = 0;
2544
-        $len = strlen($methodCall);
2545
-
2546
-        while ($ptr < $len) {
2547
-            if (strpos($methodCall, '->', $ptr) === $ptr) {
2548
-                $ptr += 2;
2549
-            }
2550
-
2551
-            if (in_array(
2552
-                $methodCall[$ptr], array(
2553
-                    ';',
2554
-                    ',',
2555
-                    '/',
2556
-                    ' ',
2557
-                    "\t",
2558
-                    "\r",
2559
-                    "\n",
2560
-                    ')',
2561
-                    '+',
2562
-                    '*',
2563
-                    '%',
2564
-                    '=',
2565
-                    '-',
2566
-                    '|'
2567
-                )
2568
-            ) || substr($methodCall, $ptr, strlen($this->rd)) === $this->rd
2569
-            ) {
2570
-                // break char found
2571
-                break;
2572
-            }
2573
-
2574
-            if (!preg_match('/^([a-z0-9_]+)(\(.*?\))?/i', substr($methodCall, $ptr), $methMatch)) {
2575
-                break;
2576
-            }
2577
-
2578
-            if (empty($methMatch[2])) {
2579
-                // property
2580
-                if ($curBlock === 'root') {
2581
-                    $output .= '->' . $methMatch[1];
2582
-                } else {
2583
-                    $output = '(($tmp = ' . $output . ') ? $tmp->' . $methMatch[1] . ' : null)';
2584
-                }
2585
-                $ptr += strlen($methMatch[1]);
2586
-            } else {
2587
-                // method
2588
-                if (substr($methMatch[2], 0, 2) === '()') {
2589
-                    $parsedCall = $methMatch[1] . '()';
2590
-                    $ptr += strlen($methMatch[1]) + 2;
2591
-                } else {
2592
-                    $parsedCall = $this->parseFunction($methodCall, $ptr, strlen($methodCall), false, 'method', $ptr);
2593
-                }
2594
-                if ($this->securityPolicy !== null) {
2595
-                    $argPos = strpos($parsedCall, '(');
2596
-                    $method = strtolower(substr($parsedCall, 0, $argPos));
2597
-                    $args   = substr($parsedCall, $argPos);
2598
-                    if ($curBlock === 'root') {
2599
-                        $output = '$this->getSecurityPolicy()->callMethod($this, ' . $output . ', ' . var_export($method, true) . ', array' . $args . ')';
2600
-                    } else {
2601
-                        $output = '(($tmp = ' . $output . ') ? $this->getSecurityPolicy()->callMethod($this, $tmp, ' . var_export($method, true) . ', array' . $args . ') : null)';
2602
-                    }
2603
-                } else {
2604
-                    if ($curBlock === 'root') {
2605
-                        $output .= '->' . $parsedCall;
2606
-                    } else {
2607
-                        $output = '(($tmp = ' . $output . ') ? $tmp->' . $parsedCall . ' : null)';
2608
-                    }
2609
-                }
2610
-            }
2611
-        }
2612
-
2613
-        $pointer += $ptr;
2614
-
2615
-        return $output;
2616
-    }
2617
-
2618
-    /**
2619
-     * Parses a constant variable (a variable that doesn't contain another variable) and preprocesses it to save
2620
-     * runtime processing time.
2621
-     *
2622
-     * @param string $key      the variable to parse
2623
-     * @param string $curBlock the current parser-block being processed
2624
-     *
2625
-     * @return string parsed variable
2626
-     */
2627
-    protected function parseVarKey($key, $curBlock)
2628
-    {
2629
-        if ($key === '') {
2630
-            return '$this->scope';
2631
-        }
2632
-        if (substr($key, 0, 1) === '.') {
2633
-            $key = 'dwoo' . $key;
2634
-        }
2635
-        if (preg_match('#dwoo\.(get|post|server|cookies|session|env|request)((?:\.[a-z0-9_-]+)+)#i', $key, $m)) {
2636
-            $global = strtoupper($m[1]);
2637
-            if ($global === 'COOKIES') {
2638
-                $global = 'COOKIE';
2639
-            }
2640
-            $key = '$_' . $global;
2641
-            foreach (explode('.', ltrim($m[2], '.')) as $part) {
2642
-                $key .= '[' . var_export($part, true) . ']';
2643
-            }
2644
-            if ($curBlock === 'root') {
2645
-                $output = $key;
2646
-            } else {
2647
-                $output = '(isset(' . $key . ')?' . $key . ':null)';
2648
-            }
2649
-        } elseif (preg_match('#dwoo\\.const\\.([a-z0-9\\\\_:]+)#i', $key, $m)) {
2650
-            return $this->parseConstKey($m[1], $curBlock);
2651
-        } elseif ($this->scope !== null) {
2652
-            if (strstr($key, '.') === false && strstr($key, '[') === false && strstr($key, '->') === false) {
2653
-                if ($key === 'dwoo') {
2654
-                    $output = '$this->globals';
2655
-                } elseif ($key === '_root' || $key === '__') {
2656
-                    $output = '$this->data';
2657
-                } elseif ($key === '_parent' || $key === '_') {
2658
-                    $output = '$this->readParentVar(1)';
2659
-                } elseif ($key === '_key') {
2660
-                    $output = '$tmp_key';
2661
-                } else {
2662
-                    if ($curBlock === 'root') {
2663
-                        $output = '$this->scope["' . $key . '"]';
2664
-                    } else {
2665
-                        $output = '(isset($this->scope["' . $key . '"]) ? $this->scope["' . $key . '"] : null)';
2666
-                    }
2667
-                }
2668
-            } else {
2669
-                preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+|(\\\?[\'"])[^\3]*?\3)\]?#i', $key, $m);
2670
-
2671
-                $i = $m[2][0];
2672
-                if ($i === '_parent' || $i === '_') {
2673
-                    $parentCnt = 0;
2674
-
2675
-                    while (true) {
2676
-                        ++ $parentCnt;
2677
-                        array_shift($m[2]);
2678
-                        array_shift($m[1]);
2679
-                        if (current($m[2]) === '_parent') {
2680
-                            continue;
2681
-                        }
2682
-                        break;
2683
-                    }
2684
-
2685
-                    $output = '$this->readParentVar(' . $parentCnt . ')';
2686
-                } else {
2687
-                    if ($i === 'dwoo') {
2688
-                        $output = '$this->globals';
2689
-                        array_shift($m[2]);
2690
-                        array_shift($m[1]);
2691
-                    } elseif ($i === '_root' || $i === '__') {
2692
-                        $output = '$this->data';
2693
-                        array_shift($m[2]);
2694
-                        array_shift($m[1]);
2695
-                    } elseif ($i === '_key') {
2696
-                        $output = '$tmp_key';
2697
-                    } else {
2698
-                        $output = '$this->scope';
2699
-                    }
2700
-
2701
-                    while (count($m[1]) && $m[1][0] !== '->') {
2702
-                        $m[2][0] = preg_replace('/(^\\\([\'"])|\\\([\'"])$)/x', '$2$3', $m[2][0]);
2703
-                        if (substr($m[2][0], 0, 1) == '"' || substr($m[2][0], 0, 1) == "'") {
2704
-                            $output .= '[' . $m[2][0] . ']';
2705
-                        } else {
2706
-                            $output .= '["' . $m[2][0] . '"]';
2707
-                        }
2708
-                        array_shift($m[2]);
2709
-                        array_shift($m[1]);
2710
-                    }
2711
-
2712
-                    if ($curBlock !== 'root') {
2713
-                        $output = '(isset(' . $output . ') ? ' . $output . ':null)';
2714
-                    }
2715
-                }
2716
-
2717
-                if (count($m[2])) {
2718
-                    unset($m[0]);
2719
-                    $output = '$this->readVarInto(' . str_replace("\n", '', var_export($m, true)) . ', ' . $output . ', ' . ($curBlock == 'root' ? 'false' : 'true') . ')';
2720
-                }
2721
-            }
2722
-        } else {
2723
-            preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+)\]?#i', $key, $m);
2724
-            unset($m[0]);
2725
-            $output = '$this->readVar(' . str_replace("\n", '', var_export($m, true)) . ')';
2726
-        }
2727
-
2728
-        return $output;
2729
-    }
2730
-
2731
-    /**
2732
-     * Flattens a variable tree, this helps in parsing very complex variables such as $var.foo[$foo.bar->baz].baz,
2733
-     * it computes the contents of the brackets first and works out from there.
2734
-     *
2735
-     * @param array $tree     the variable tree parsed by he parseVar() method that must be flattened
2736
-     * @param bool  $recursed leave that to false by default, it is only for internal use
2737
-     *
2738
-     * @return string flattened tree
2739
-     */
2740
-    protected function flattenVarTree(array $tree, $recursed = false)
2741
-    {
2742
-        $out = $recursed ? '".$this->readVarInto(' : '';
2743
-        foreach ($tree as $bit) {
2744
-            if (is_array($bit)) {
2745
-                $out .= '.' . $this->flattenVarTree($bit, false);
2746
-            } else {
2747
-                $key = str_replace('"', '\\"', $bit);
2748
-
2749
-                if (substr($key, 0, 1) === '$') {
2750
-                    $out .= '".' . $this->parseVar($key, 0, strlen($key), false, 'variable') . '."';
2751
-                } else {
2752
-                    $cnt = substr_count($key, '$');
2753
-
2754
-                    if ($this->debug) {
2755
-                        echo 'PARSING SUBVARS IN : ' . $key . "\n";
2756
-                    }
2757
-                    if ($cnt > 0) {
2758
-                        while (-- $cnt >= 0) {
2759
-                            if (isset($last)) {
2760
-                                $last = strrpos($key, '$', - (strlen($key) - $last + 1));
2761
-                            } else {
2762
-                                $last = strrpos($key, '$');
2763
-                            }
2764
-                            preg_match('#\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', substr($key, $last), $submatch);
2765
-
2766
-                            $len = strlen($submatch[0]);
2767
-                            $key = substr_replace(
2768
-                                $key, preg_replace_callback(
2769
-                                    '#(\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*)' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', array(
2770
-                                        $this,
2771
-                                        'replaceVarKeyHelper'
2772
-                                    ), substr($key, $last, $len)
2773
-                                ), $last, $len
2774
-                            );
2775
-                            if ($this->debug) {
2776
-                                echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2777
-                            }
2778
-                        }
2779
-                        unset($last);
2780
-
2781
-                        $out .= $key;
2782
-                    } else {
2783
-                        $out .= $key;
2784
-                    }
2785
-                }
2786
-            }
2787
-        }
2788
-        $out .= $recursed ? ', true)."' : '';
2789
-
2790
-        return $out;
2791
-    }
2792
-
2793
-    /**
2794
-     * Helper function that parses a variable.
2795
-     *
2796
-     * @param array $match the matched variable, array(1=>"string match")
2797
-     *
2798
-     * @return string parsed variable
2799
-     */
2800
-    protected function replaceVarKeyHelper($match)
2801
-    {
2802
-        return '".' . $this->parseVar($match[0], 0, strlen($match[0]), false, 'variable') . '."';
2803
-    }
2804
-
2805
-    /**
2806
-     * Parses various constants, operators or non-quoted strings.
2807
-     *
2808
-     * @param string $in            the string within which we must parse something
2809
-     * @param int    $from          the starting offset of the parsed area
2810
-     * @param int    $to            the ending offset of the parsed area
2811
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2812
-     *                              default
2813
-     * @param string $curBlock      the current parser-block being processed
2814
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2815
-     *                              or null by default
2816
-     *
2817
-     * @return string parsed values
2818
-     * @throws Exception
2819
-     */
2820
-    protected function parseOthers($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2821
-    {
2822
-        $substr = substr($in, $from, $to - $from);
2823
-
2824
-        $end = strlen($substr);
2825
-
2826
-        if ($curBlock === 'condition') {
2827
-            $breakChars = array(
2828
-                '(',
2829
-                ')',
2830
-                ' ',
2831
-                '||',
2832
-                '&&',
2833
-                '|',
2834
-                '&',
2835
-                '>=',
2836
-                '<=',
2837
-                '===',
2838
-                '==',
2839
-                '=',
2840
-                '!==',
2841
-                '!=',
2842
-                '<<',
2843
-                '<',
2844
-                '>>',
2845
-                '>',
2846
-                '^',
2847
-                '~',
2848
-                ',',
2849
-                '+',
2850
-                '-',
2851
-                '*',
2852
-                '/',
2853
-                '%',
2854
-                '!',
2855
-                '?',
2856
-                ':',
2857
-                $this->rd,
2858
-                ';'
2859
-            );
2860
-        } elseif ($curBlock === 'modifier') {
2861
-            $breakChars = array(' ', ',', ')', ':', '|', "\r", "\n", "\t", ';', $this->rd);
2862
-        } elseif ($curBlock === 'expression') {
2863
-            $breakChars = array('/', '%', '+', '-', '*', ' ', ',', ')', "\r", "\n", "\t", ';', $this->rd);
2864
-        } else {
2865
-            $breakChars = array(' ', ',', ')', "\r", "\n", "\t", ';', $this->rd);
2866
-        }
2867
-
2868
-        $breaker = false;
2869
-        while (list($k, $char) = each($breakChars)) {
2870
-            $test = strpos($substr, $char);
2871
-            if ($test !== false && $test < $end) {
2872
-                $end     = $test;
2873
-                $breaker = $k;
2874
-            }
2875
-        }
2876
-
2877
-        if ($curBlock === 'condition') {
2878
-            if ($end === 0 && $breaker !== false) {
2879
-                $end = strlen($breakChars[$breaker]);
2880
-            }
2881
-        }
2882
-
2883
-        if ($end !== false) {
2884
-            $substr = substr($substr, 0, $end);
2885
-        }
2886
-
2887
-        if ($pointer !== null) {
2888
-            $pointer += strlen($substr);
2889
-        }
2890
-
2891
-        $src    = $substr;
2892
-        $substr = trim($substr);
2893
-
2894
-        if (strtolower($substr) === 'false' || strtolower($substr) === 'no' || strtolower($substr) === 'off') {
2895
-            if ($this->debug) {
2896
-                echo 'BOOLEAN(FALSE) PARSED' . "\n";
2897
-            }
2898
-            $substr = 'false';
2899
-            $type   = self::T_BOOL;
2900
-        } elseif (strtolower($substr) === 'true' || strtolower($substr) === 'yes' || strtolower($substr) === 'on') {
2901
-            if ($this->debug) {
2902
-                echo 'BOOLEAN(TRUE) PARSED' . "\n";
2903
-            }
2904
-            $substr = 'true';
2905
-            $type   = self::T_BOOL;
2906
-        } elseif ($substr === 'null' || $substr === 'NULL') {
2907
-            if ($this->debug) {
2908
-                echo 'NULL PARSED' . "\n";
2909
-            }
2910
-            $substr = 'null';
2911
-            $type   = self::T_NULL;
2912
-        } elseif (is_numeric($substr)) {
2913
-            $substr = (float)$substr;
2914
-            if ((int)$substr == $substr) {
2915
-                $substr = (int)$substr;
2916
-            }
2917
-            $type = self::T_NUMERIC;
2918
-            if ($this->debug) {
2919
-                echo 'NUMBER (' . $substr . ') PARSED' . "\n";
2920
-            }
2921
-        } elseif (preg_match('{^-?(\d+|\d*(\.\d+))\s*([/*%+-]\s*-?(\d+|\d*(\.\d+)))+$}', $substr)) {
2922
-            if ($this->debug) {
2923
-                echo 'SIMPLE MATH PARSED . "\n"';
2924
-            }
2925
-            $type   = self::T_MATH;
2926
-            $substr = '(' . $substr . ')';
2927
-        } elseif ($curBlock === 'condition' && array_search($substr, $breakChars, true) !== false) {
2928
-            if ($this->debug) {
2929
-                echo 'BREAKCHAR (' . $substr . ') PARSED' . "\n";
2930
-            }
2931
-            $type = self::T_BREAKCHAR;
2932
-            //$substr = '"'.$substr.'"';
2933
-        } else {
2934
-            $substr = $this->replaceStringVars('\'' . str_replace('\'', '\\\'', $substr) . '\'', '\'', $curBlock);
2935
-            $type   = self::T_UNQUOTED_STRING;
2936
-            if ($this->debug) {
2937
-                echo 'BLABBER (' . $substr . ') CASTED AS STRING' . "\n";
2938
-            }
2939
-        }
2940
-
2941
-        if (is_array($parsingParams)) {
2942
-            $parsingParams[] = array($substr, $src, $type);
2943
-
2944
-            return $parsingParams;
2945
-        } elseif ($curBlock === 'namedparam') {
2946
-            return array($substr, $src, $type);
2947
-        } elseif ($curBlock === 'expression') {
2948
-            return $substr;
2949
-        } else {
2950
-            throw new Exception('Something went wrong');
2951
-        }
2952
-    }
2953
-
2954
-    /**
2955
-     * Replaces variables within a parsed string.
2956
-     *
2957
-     * @param string $string   the parsed string
2958
-     * @param string $first    the first character parsed in the string, which is the string delimiter (' or ")
2959
-     * @param string $curBlock the current parser-block being processed
2960
-     *
2961
-     * @return string the original string with variables replaced
2962
-     */
2963
-    protected function replaceStringVars($string, $first, $curBlock = '')
2964
-    {
2965
-        $pos = 0;
2966
-        if ($this->debug) {
2967
-            echo 'STRING VAR REPLACEMENT : ' . $string . "\n";
2968
-        }
2969
-        // replace vars
2970
-        while (($pos = strpos($string, '$', $pos)) !== false) {
2971
-            $prev = substr($string, $pos - 1, 1);
2972
-            if ($prev === '\\') {
2973
-                ++ $pos;
2974
-                continue;
2975
-            }
2976
-
2977
-            $var = $this->parse($string, $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
2978
-            $len = $var[0];
2979
-            $var = $this->parse(str_replace('\\' . $first, $first, $string), $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
2980
-
2981
-            if ($prev === '`' && substr($string, $pos + $len, 1) === '`') {
2982
-                $string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos - 1, $len + 2);
2983
-            } else {
2984
-                $string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos, $len);
2985
-            }
2986
-            $pos += strlen($var[1]) + 2;
2987
-            if ($this->debug) {
2988
-                echo 'STRING VAR REPLACEMENT DONE : ' . $string . "\n";
2989
-            }
2990
-        }
2991
-
2992
-        // handle modifiers
2993
-        // TODO Obsolete?
2994
-        $string = preg_replace_callback(
2995
-            '#("|\')\.(.+?)\.\1((?:\|(?:@?[a-z0-9_]+(?:(?::("|\').+?\4|:[^`]*))*))+)#i', array(
2996
-            $this,
2997
-            'replaceModifiers'
2998
-            ), $string
2999
-        );
3000
-
3001
-        // replace escaped dollar operators by unescaped ones if required
3002
-        if ($first === "'") {
3003
-            $string = str_replace('\\$', '$', $string);
3004
-        }
3005
-
3006
-        return $string;
3007
-    }
3008
-
3009
-    /**
3010
-     * Replaces the modifiers applied to a string or a variable.
3011
-     *
3012
-     * @param array  $m        the regex matches that must be array(1=>"double or single quotes enclosing a string,
3013
-     *                         when applicable", 2=>"the string or var", 3=>"the modifiers matched")
3014
-     * @param string $curBlock the current parser-block being processed
3015
-     * @param null   $pointer
3016
-     *
3017
-     * @return string the input enclosed with various function calls according to the modifiers found
3018
-     * @throws CompilationException
3019
-     * @throws Exception
3020
-     */
3021
-    protected function replaceModifiers(array $m, $curBlock = null, &$pointer = null)
3022
-    {
3023
-        if ($this->debug) {
3024
-            echo 'PARSING MODIFIERS : ' . $m[3] . "\n";
3025
-        }
3026
-
3027
-        if ($pointer !== null) {
3028
-            $pointer += strlen($m[3]);
3029
-        }
3030
-        // remove first pipe
3031
-        $cmdstrsrc = substr($m[3], 1);
3032
-        // remove last quote if present
3033
-        if (substr($cmdstrsrc, - 1, 1) === $m[1]) {
3034
-            $cmdstrsrc = substr($cmdstrsrc, 0, - 1);
3035
-            $add       = $m[1];
3036
-        }
3037
-
3038
-        $output = $m[2];
3039
-
3040
-        $continue = true;
3041
-        while (strlen($cmdstrsrc) > 0 && $continue) {
3042
-            if ($cmdstrsrc[0] === '|') {
3043
-                $cmdstrsrc = substr($cmdstrsrc, 1);
3044
-                continue;
3045
-            }
3046
-            if ($cmdstrsrc[0] === ' ' || $cmdstrsrc[0] === ';' || substr($cmdstrsrc, 0, strlen($this->rd)) === $this->rd) {
3047
-                if ($this->debug) {
3048
-                    echo 'MODIFIER PARSING ENDED, RIGHT DELIMITER or ";" FOUND' . "\n";
3049
-                }
3050
-                $continue = false;
3051
-                if ($pointer !== null) {
3052
-                    $pointer -= strlen($cmdstrsrc);
3053
-                }
3054
-                break;
3055
-            }
3056
-            $cmdstr   = $cmdstrsrc;
3057
-            $paramsep = ':';
3058
-            if (!preg_match('/^(@{0,2}[a-z_][a-z0-9_]*)(:)?/i', $cmdstr, $match)) {
3059
-                throw new CompilationException($this, 'Invalid modifier name, started with : ' . substr($cmdstr, 0, 10));
3060
-            }
3061
-            $paramspos = !empty($match[2]) ? strlen($match[1]) : false;
3062
-            $func      = $match[1];
3063
-
3064
-            $state = 0;
3065
-            if ($paramspos === false) {
3066
-                $cmdstrsrc = substr($cmdstrsrc, strlen($func));
3067
-                $params    = array();
3068
-                if ($this->debug) {
3069
-                    echo 'MODIFIER (' . $func . ') CALLED WITH NO PARAMS' . "\n";
3070
-                }
3071
-            } else {
3072
-                $paramstr = substr($cmdstr, $paramspos + 1);
3073
-                if (substr($paramstr, - 1, 1) === $paramsep) {
3074
-                    $paramstr = substr($paramstr, 0, - 1);
3075
-                }
3076
-
3077
-                $ptr    = 0;
3078
-                $params = array();
3079
-                while ($ptr < strlen($paramstr)) {
3080
-                    if ($this->debug) {
3081
-                        echo 'MODIFIER (' . $func . ') START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
3082
-                    }
3083
-                    if ($this->debug) {
3084
-                        echo $paramstr . '--' . $ptr . '--' . strlen($paramstr) . '--modifier' . "\n";
3085
-                    }
3086
-                    $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'modifier', $ptr);
3087
-                    if ($this->debug) {
3088
-                        echo 'PARAM PARSED, POINTER AT ' . $ptr . "\n";
3089
-                    }
3090
-
3091
-                    if ($ptr >= strlen($paramstr)) {
3092
-                        if ($this->debug) {
3093
-                            echo 'PARAM PARSING ENDED, PARAM STRING CONSUMED' . "\n";
3094
-                        }
3095
-                        break;
3096
-                    }
3097
-
3098
-                    if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === '|' || $paramstr[$ptr] === ';' || substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
3099
-                        if ($this->debug) {
3100
-                            echo 'PARAM PARSING ENDED, " ", "|", RIGHT DELIMITER or ";" FOUND, POINTER AT ' . $ptr . "\n";
3101
-                        }
3102
-                        if ($paramstr[$ptr] !== '|') {
3103
-                            $continue = false;
3104
-                            if ($pointer !== null) {
3105
-                                $pointer -= strlen($paramstr) - $ptr;
3106
-                            }
3107
-                        }
3108
-                        ++ $ptr;
3109
-                        break;
3110
-                    }
3111
-                    if ($ptr < strlen($paramstr) && $paramstr[$ptr] === ':') {
3112
-                        ++ $ptr;
3113
-                    }
3114
-                }
3115
-                $cmdstrsrc = substr($cmdstrsrc, strlen($func) + 1 + $ptr);
3116
-                foreach ($params as $k => $p) {
3117
-                    if (is_array($p) && is_array($p[1])) {
3118
-                        $state |= 2;
3119
-                    } else {
3120
-                        if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m)) {
3121
-                            $params[$k] = array($m[2], array('true', 'true'));
3122
-                        } else {
3123
-                            if ($state & 2) {
3124
-                                throw new CompilationException($this, 'You can not use an unnamed parameter after a named one');
3125
-                            }
3126
-                            $state |= 1;
3127
-                        }
3128
-                    }
3129
-                }
3130
-            }
3131
-
3132
-            // check if we must use array_map with this plugin or not
3133
-            $mapped = false;
3134
-            if (substr($func, 0, 1) === '@') {
3135
-                $func   = substr($func, 1);
3136
-                $mapped = true;
3137
-            }
3138
-
3139
-            $pluginType = $this->getPluginType($func);
3140
-
3141
-            if ($state & 2) {
3142
-                array_unshift($params, array('value', is_array($output) ? $output : array($output, $output)));
3143
-            } else {
3144
-                array_unshift($params, is_array($output) ? $output : array($output, $output));
3145
-            }
3146
-
3147
-            if ($pluginType & Core::NATIVE_PLUGIN) {
3148
-                $params = $this->mapParams($params, null, $state);
3149
-
3150
-                $params = $params['*'][0];
3151
-
3152
-                $params = self::implode_r($params);
3153
-
3154
-                if ($mapped) {
3155
-                    $output = '$this->arrayMap(\'' . $func . '\', array(' . $params . '))';
3156
-                } else {
3157
-                    $output = $func . '(' . $params . ')';
3158
-                }
3159
-            } elseif ($pluginType & Core::PROXY_PLUGIN) {
3160
-                $params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state);
3161
-                foreach ($params as &$p) {
3162
-                    $p = $p[0];
3163
-                }
3164
-                $output = call_user_func(array($this->getDwoo()->getPluginProxy(), 'getCode'), $func, $params);
3165
-            } elseif ($pluginType & Core::SMARTY_MODIFIER) {
3166
-                $params = $this->mapParams($params, null, $state);
3167
-                $params = $params['*'][0];
3168
-
3169
-                $params = self::implode_r($params);
3170
-
3171
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
3172
-                    $callback = $this->customPlugins[$func]['callback'];
3173
-                    if (is_array($callback)) {
3174
-                        if (is_object($callback[0])) {
3175
-                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(' . $params . '))';
3176
-                        } else {
3177
-                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3178
-                        }
3179
-                    } elseif ($mapped) {
3180
-                        $output = '$this->arrayMap(\'' . $callback . '\', array(' . $params . '))';
3181
-                    } else {
3182
-                        $output = $callback . '(' . $params . ')';
3183
-                    }
3184
-                } elseif ($mapped) {
3185
-                    $output = '$this->arrayMap(\'smarty_modifier_' . $func . '\', array(' . $params . '))';
3186
-                } else {
3187
-                    $output = 'smarty_modifier_' . $func . '(' . $params . ')';
3188
-                }
3189
-            } else {
3190
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
3191
-                    $callback   = $this->customPlugins[$func]['callback'];
3192
-                    $pluginName = $callback;
3193
-                } else {
3194
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false || function_exists('Plugin' .
3195
-                            Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''))
3196
-                        !== false) {
3197
-                        $pluginName = 'Plugin' . Core::toCamelCase($func);
3198
-                    } else {
3199
-                        $pluginName = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func);
3200
-                    }
3201
-                    if ($pluginType & Core::CLASS_PLUGIN) {
3202
-                        $callback = array($pluginName, ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process');
3203
-                    } else {
3204
-                        $callback = $pluginName . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '');
3205
-                    }
3206
-                }
3207
-                $params = $this->mapParams($params, $callback, $state);
3208
-
3209
-                foreach ($params as &$p) {
3210
-                    $p = $p[0];
3211
-                }
3212
-
3213
-                if ($pluginType & Core::FUNC_PLUGIN) {
3214
-                    if ($pluginType & Core::COMPILABLE_PLUGIN) {
3215
-                        if ($mapped) {
3216
-                            throw new CompilationException($this, 'The @ operator can not be used on compiled plugins.');
3217
-                        }
3218
-                        if ($pluginType & Core::CUSTOM_PLUGIN) {
3219
-                            $funcCompiler = $this->customPlugins[$func]['callback'];
3220
-                        } else {
3221
-                            if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
3222
-                                $funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
3223
-                            } else {
3224
-                                $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
3225
-                                    'Compile';
3226
-                            }
3227
-                        }
3228
-                        array_unshift($params, $this);
3229
-                        $output = call_user_func_array($funcCompiler, $params);
3230
-                    } else {
3231
-                        array_unshift($params, '$this');
3232
-
3233
-                        $params = self::implode_r($params);
3234
-                        if ($mapped) {
3235
-                            $output = '$this->arrayMap(\'' . $pluginName . '\', array(' . $params . '))';
3236
-                        } else {
3237
-                            $output = $pluginName . '(' . $params . ')';
3238
-                        }
3239
-                    }
3240
-                } else {
3241
-                    if ($pluginType & Core::COMPILABLE_PLUGIN) {
3242
-                        if ($mapped) {
3243
-                            throw new CompilationException($this, 'The @ operator can not be used on compiled plugins.');
3244
-                        }
3245
-                        if ($pluginType & Core::CUSTOM_PLUGIN) {
3246
-                            $callback = $this->customPlugins[$func]['callback'];
3247
-                            if (!is_array($callback)) {
3248
-                                if (!method_exists($callback, 'compile')) {
3249
-                                    throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
3250
-                                }
3251
-                                if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
3252
-                                    $funcCompiler = array($callback, 'compile');
3253
-                                } else {
3254
-                                    $funcCompiler = array(new $callback(), 'compile');
3255
-                                }
3256
-                            } else {
3257
-                                $funcCompiler = $callback;
3258
-                            }
3259
-                        } else {
3260
-                            if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3261
-                                $funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
3262
-                            } else {
3263
-                                $funcCompiler = array(
3264
-                                    Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
3265
-                                    'compile'
3266
-                                );
3267
-                            }
3268
-                            array_unshift($params, $this);
3269
-                        }
3270
-                        $output = call_user_func_array($funcCompiler, $params);
3271
-                    } else {
3272
-                        $params = self::implode_r($params);
3273
-
3274
-                        if ($pluginType & Core::CUSTOM_PLUGIN) {
3275
-                            if (is_object($callback[0])) {
3276
-                                $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(' . $params . '))';
3277
-                            } else {
3278
-                                $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3279
-                            }
3280
-                        } elseif ($mapped) {
3281
-                            $output = '$this->arrayMap(array($this->getObjectPlugin(\''.
3282
-                                Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '\'), 
2117
+					} else{
2118
+						$output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
2119
+					}
2120
+				}
2121
+			}
2122
+		} elseif ($pluginType & Core::PROXY_PLUGIN) {
2123
+			$output = call_user_func(array($this->getDwoo()->getPluginProxy(), 'getCode'), $func, $params);
2124
+		} elseif ($pluginType & Core::SMARTY_FUNCTION) {
2125
+			if (isset($params['*'])) {
2126
+				$params = self::implode_r($params['*'], true);
2127
+			} else {
2128
+				$params = '';
2129
+			}
2130
+
2131
+			if ($pluginType & Core::CUSTOM_PLUGIN) {
2132
+				$callback = $this->customPlugins[$func]['callback'];
2133
+				if (is_array($callback)) {
2134
+					if (is_object($callback[0])) {
2135
+						$output = 'call_user_func_array(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2136
+					} else {
2137
+						$output = 'call_user_func_array(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2138
+					}
2139
+				} else {
2140
+					$output = $callback . '(array(' . $params . '), $this)';
2141
+				}
2142
+			} else {
2143
+				$output = 'smarty_function_' . $func . '(array(' . $params . '), $this)';
2144
+			}
2145
+		} elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
2146
+			array_unshift($params, '$this');
2147
+			$params                                 = self::implode_r($params);
2148
+			$output                                 = 'Plugin' . Core::toCamelCase($func) .
2149
+				$this->templatePlugins[$func]['uuid'] . '(' . $params . ')';
2150
+			$this->templatePlugins[$func]['called'] = true;
2151
+		}
2152
+
2153
+		if (is_array($parsingParams)) {
2154
+			$parsingParams[] = array($output, $output);
2155
+
2156
+			return $parsingParams;
2157
+		} elseif ($curBlock === 'namedparam') {
2158
+			return array($output, $output);
2159
+		} else {
2160
+			return $output;
2161
+		}
2162
+	}
2163
+
2164
+	/**
2165
+	 * Parses a string.
2166
+	 *
2167
+	 * @param string $in            the string within which we must parse something
2168
+	 * @param int    $from          the starting offset of the parsed area
2169
+	 * @param int    $to            the ending offset of the parsed area
2170
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2171
+	 *                              default
2172
+	 * @param string $curBlock      the current parser-block being processed
2173
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2174
+	 *                              or null by default
2175
+	 *
2176
+	 * @return string parsed values
2177
+	 * @throws CompilationException
2178
+	 */
2179
+	protected function parseString($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2180
+	{
2181
+		$substr = substr($in, $from, $to - $from);
2182
+		$first  = $substr[0];
2183
+
2184
+		if ($this->debug) {
2185
+			echo 'STRING FOUND (in ' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . ')' . "\n";
2186
+		}
2187
+		$strend = false;
2188
+		$o      = $from + 1;
2189
+		while ($strend === false) {
2190
+			$strend = strpos($in, $first, $o);
2191
+			if ($strend === false) {
2192
+				throw new CompilationException($this, 'Unfinished string, started with ' . substr($in, $from, $to - $from));
2193
+			}
2194
+			if (substr($in, $strend - 1, 1) === '\\') {
2195
+				$o      = $strend + 1;
2196
+				$strend = false;
2197
+			}
2198
+		}
2199
+		if ($this->debug) {
2200
+			echo 'STRING DELIMITED: ' . substr($in, $from, $strend + 1 - $from) . "\n";
2201
+		}
2202
+
2203
+		$srcOutput = substr($in, $from, $strend + 1 - $from);
2204
+
2205
+		if ($pointer !== null) {
2206
+			$pointer += strlen($srcOutput);
2207
+		}
2208
+
2209
+		$output = $this->replaceStringVars($srcOutput, $first);
2210
+
2211
+		// handle modifiers
2212
+		if ($curBlock !== 'modifier' && preg_match('#^((?:\|(?:@?[a-z0-9_]+(?::.*)*))+)#i', substr($substr, $strend + 1 - $from), $match)) {
2213
+			$modstr = $match[1];
2214
+
2215
+			if ($curBlock === 'root' && substr($modstr, - 1) === '}') {
2216
+				$modstr = substr($modstr, 0, - 1);
2217
+			}
2218
+			$modstr = str_replace('\\' . $first, $first, $modstr);
2219
+			$ptr    = 0;
2220
+			$output = $this->replaceModifiers(array(null, null, $output, $modstr), 'string', $ptr);
2221
+
2222
+			$strend += $ptr;
2223
+			if ($pointer !== null) {
2224
+				$pointer += $ptr;
2225
+			}
2226
+			$srcOutput .= substr($substr, $strend + 1 - $from, $ptr);
2227
+		}
2228
+
2229
+		if (is_array($parsingParams)) {
2230
+			$parsingParams[] = array($output, substr($srcOutput, 1, - 1));
2231
+
2232
+			return $parsingParams;
2233
+		} elseif ($curBlock === 'namedparam') {
2234
+			return array($output, substr($srcOutput, 1, - 1));
2235
+		} else {
2236
+			return $output;
2237
+		}
2238
+	}
2239
+
2240
+	/**
2241
+	 * Parses a constant.
2242
+	 *
2243
+	 * @param string $in            the string within which we must parse something
2244
+	 * @param int    $from          the starting offset of the parsed area
2245
+	 * @param int    $to            the ending offset of the parsed area
2246
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2247
+	 *                              default
2248
+	 * @param string $curBlock      the current parser-block being processed
2249
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2250
+	 *                              or null by default
2251
+	 *
2252
+	 * @return string parsed values
2253
+	 * @throws CompilationException
2254
+	 */
2255
+	protected function parseConst($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2256
+	{
2257
+		$substr = substr($in, $from, $to - $from);
2258
+
2259
+		if ($this->debug) {
2260
+			echo 'CONST FOUND : ' . $substr . "\n";
2261
+		}
2262
+
2263
+		if (!preg_match('#^%([\\\\a-z0-9_:]+)#i', $substr, $m)) {
2264
+			throw new CompilationException($this, 'Invalid constant');
2265
+		}
2266
+
2267
+		if ($pointer !== null) {
2268
+			$pointer += strlen($m[0]);
2269
+		}
2270
+
2271
+		$output = $this->parseConstKey($m[1], $curBlock);
2272
+
2273
+		if (is_array($parsingParams)) {
2274
+			$parsingParams[] = array($output, $m[1]);
2275
+
2276
+			return $parsingParams;
2277
+		} elseif ($curBlock === 'namedparam') {
2278
+			return array($output, $m[1]);
2279
+		} else {
2280
+			return $output;
2281
+		}
2282
+	}
2283
+
2284
+	/**
2285
+	 * Parses a constant.
2286
+	 *
2287
+	 * @param string $key      the constant to parse
2288
+	 * @param string $curBlock the current parser-block being processed
2289
+	 *
2290
+	 * @return string parsed constant
2291
+	 */
2292
+	protected function parseConstKey($key, $curBlock)
2293
+	{
2294
+		if ($this->securityPolicy !== null && $this->securityPolicy->getConstantHandling() === SecurityPolicy::CONST_DISALLOW) {
2295
+			return 'null';
2296
+		}
2297
+
2298
+		if ($curBlock !== 'root') {
2299
+			$output = '(defined("' . $key . '") ? ' . $key . ' : null)';
2300
+		} else {
2301
+			$output = $key;
2302
+		}
2303
+
2304
+		return $output;
2305
+	}
2306
+
2307
+	/**
2308
+	 * Parses a variable.
2309
+	 *
2310
+	 * @param string $in            the string within which we must parse something
2311
+	 * @param int    $from          the starting offset of the parsed area
2312
+	 * @param int    $to            the ending offset of the parsed area
2313
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2314
+	 *                              default
2315
+	 * @param string $curBlock      the current parser-block being processed
2316
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2317
+	 *                              or null by default
2318
+	 *
2319
+	 * @return string parsed values
2320
+	 * @throws CompilationException
2321
+	 */
2322
+	protected function parseVar($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2323
+	{
2324
+		$substr = substr($in, $from, $to - $from);
2325
+
2326
+		// var key
2327
+		$varRegex = '(\\$?\\.?[a-z0-9\\\\_:]*(?:(?:(?:\\.|->)(?:[a-z0-9\\\\_:]+|(?R))|\\[(?:[a-z0-9\\\\_:]+|(?R)|(["\'])[^\\2]*?\\2)\\]))*)';
2328
+		// method call
2329
+		$methodCall = ($curBlock === 'root' || $curBlock === 'function' || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'variable' || $curBlock === 'expression' || $curBlock === 'delimited_string' ? '(\(.*)?' : '()');
2330
+		// simple math expressions
2331
+		$simpleMathExpressions = ($curBlock === 'root' || $curBlock === 'function' || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'variable' || $curBlock === 'delimited_string' ? '((?:(?:[+\/*%=-])(?:(?<!=)=?-?[$%][a-z0-9\\\\.[\]>_:-]+(?:\([^)]*\))?|(?<!=)=?-?[0-9\.,]*|[+-]))*)' : '()');
2332
+		// modifiers
2333
+		$modifiers = $curBlock !== 'modifier' ? '((?:\|(?:@?[a-z0-9\\\\_]+(?:(?::("|\').*?\5|:[^`]*))*))+)?' : '(())';
2334
+
2335
+		$regex = '#';
2336
+		$regex .= $varRegex;
2337
+		$regex .= $methodCall;
2338
+		$regex .= $simpleMathExpressions;
2339
+		$regex .= $modifiers;
2340
+		$regex .= '#i';
2341
+
2342
+		if (preg_match($regex, $substr, $match)) {
2343
+			$key = substr($match[1], 1);
2344
+
2345
+			$matchedLength = strlen($match[0]);
2346
+			$hasModifiers  = !empty($match[5]);
2347
+			$hasExpression = !empty($match[4]);
2348
+			$hasMethodCall = !empty($match[3]);
2349
+
2350
+			if (substr($key, - 1) == '.') {
2351
+				$key = substr($key, 0, - 1);
2352
+				-- $matchedLength;
2353
+			}
2354
+
2355
+			if ($hasMethodCall) {
2356
+				$matchedLength -= strlen($match[3]) + strlen(substr($match[1], strrpos($match[1], '->')));
2357
+				$key        = substr($match[1], 1, strrpos($match[1], '->') - 1);
2358
+				$methodCall = substr($match[1], strrpos($match[1], '->')) . $match[3];
2359
+			}
2360
+
2361
+			if ($hasModifiers) {
2362
+				$matchedLength -= strlen($match[5]);
2363
+			}
2364
+
2365
+			if ($pointer !== null) {
2366
+				$pointer += $matchedLength;
2367
+			}
2368
+
2369
+			// replace useless brackets by dot accessed vars and strip enclosing quotes if present
2370
+			$key = preg_replace('#\[(["\']?)([^$%\[.>-]+)\1\]#', '.$2', $key);
2371
+
2372
+			if ($this->debug) {
2373
+				if ($hasMethodCall) {
2374
+					echo 'METHOD CALL FOUND : $' . $key . substr($methodCall, 0, 30) . "\n";
2375
+				} else {
2376
+					echo 'VAR FOUND : $' . $key . "\n";
2377
+				}
2378
+			}
2379
+
2380
+			$key = str_replace('"', '\\"', $key);
2381
+
2382
+			$cnt = substr_count($key, '$');
2383
+			if ($cnt > 0) {
2384
+				$uid           = 0;
2385
+				$parsed        = array($uid => '');
2386
+				$current       = &$parsed;
2387
+				$curTxt        = &$parsed[$uid ++];
2388
+				$tree          = array();
2389
+				$chars         = str_split($key, 1);
2390
+				$inSplittedVar = false;
2391
+				$bracketCount  = 0;
2392
+
2393
+				while (($char = array_shift($chars)) !== null) {
2394
+					if ($char === '[') {
2395
+						if (count($tree) > 0) {
2396
+							++ $bracketCount;
2397
+						} else {
2398
+							$tree[]        = &$current;
2399
+							$current[$uid] = array($uid + 1 => '');
2400
+							$current       = &$current[$uid ++];
2401
+							$curTxt        = &$current[$uid ++];
2402
+							continue;
2403
+						}
2404
+					} elseif ($char === ']') {
2405
+						if ($bracketCount > 0) {
2406
+							-- $bracketCount;
2407
+						} else {
2408
+							$current = &$tree[count($tree) - 1];
2409
+							array_pop($tree);
2410
+							if (current($chars) !== '[' && current($chars) !== false && current($chars) !== ']') {
2411
+								$current[$uid] = '';
2412
+								$curTxt        = &$current[$uid ++];
2413
+							}
2414
+							continue;
2415
+						}
2416
+					} elseif ($char === '$') {
2417
+						if (count($tree) == 0) {
2418
+							$curTxt        = &$current[$uid ++];
2419
+							$inSplittedVar = true;
2420
+						}
2421
+					} elseif (($char === '.' || $char === '-') && count($tree) == 0 && $inSplittedVar) {
2422
+						$curTxt        = &$current[$uid ++];
2423
+						$inSplittedVar = false;
2424
+					}
2425
+
2426
+					$curTxt .= $char;
2427
+				}
2428
+				unset($uid, $current, $curTxt, $tree, $chars);
2429
+
2430
+				if ($this->debug) {
2431
+					echo 'RECURSIVE VAR REPLACEMENT : ' . $key . "\n";
2432
+				}
2433
+
2434
+				$key = $this->flattenVarTree($parsed);
2435
+
2436
+				if ($this->debug) {
2437
+					echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2438
+				}
2439
+
2440
+				$output = preg_replace('#(^""\.|""\.|\.""$|(\()""\.|\.""(\)))#', '$2$3', '$this->readVar("' . $key . '")');
2441
+			} else {
2442
+				$output = $this->parseVarKey($key, $hasModifiers ? 'modifier' : $curBlock);
2443
+			}
2444
+
2445
+
2446
+			// methods
2447
+			if ($hasMethodCall) {
2448
+				$ptr = 0;
2449
+
2450
+				$output = $this->parseMethodCall($output, $methodCall, $curBlock, $ptr);
2451
+
2452
+				if ($pointer !== null) {
2453
+					$pointer += $ptr;
2454
+				}
2455
+				$matchedLength += $ptr;
2456
+			}
2457
+
2458
+			if ($hasExpression) {
2459
+				// expressions
2460
+				preg_match_all('#(?:([+/*%=-])(=?-?[%$][a-z0-9\\\\.[\]>_:-]+(?:\([^)]*\))?|=?-?[0-9.,]+|\1))#i', $match[4], $expMatch);
2461
+				foreach ($expMatch[1] as $k => $operator) {
2462
+					if (substr($expMatch[2][$k], 0, 1) === '=') {
2463
+						$assign = true;
2464
+						if ($operator === '=') {
2465
+							throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, can not use "==" in expressions');
2466
+						}
2467
+						if ($curBlock !== 'root') {
2468
+							throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, assignments can only be used in top level expressions like {$foo+=3} or {$foo="bar"}');
2469
+						}
2470
+						$operator .= '=';
2471
+						$expMatch[2][$k] = substr($expMatch[2][$k], 1);
2472
+					}
2473
+
2474
+					if (substr($expMatch[2][$k], 0, 1) === '-' && strlen($expMatch[2][$k]) > 1) {
2475
+						$operator .= '-';
2476
+						$expMatch[2][$k] = substr($expMatch[2][$k], 1);
2477
+					}
2478
+					if (($operator === '+' || $operator === '-') && $expMatch[2][$k] === $operator) {
2479
+						$output = '(' . $output . $operator . $operator . ')';
2480
+						break;
2481
+					} elseif (substr($expMatch[2][$k], 0, 1) === '$') {
2482
+						$output = '(' . $output . ' ' . $operator . ' ' . $this->parseVar($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2483
+					} elseif (substr($expMatch[2][$k], 0, 1) === '%') {
2484
+						$output = '(' . $output . ' ' . $operator . ' ' . $this->parseConst($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2485
+					} elseif (!empty($expMatch[2][$k])) {
2486
+						$output = '(' . $output . ' ' . $operator . ' ' . str_replace(',', '.', $expMatch[2][$k]) . ')';
2487
+					} else {
2488
+						throw new CompilationException($this, 'Unfinished expression <em>' . $substr . '</em>, missing var or number after math operator');
2489
+					}
2490
+				}
2491
+			}
2492
+
2493
+			if ($this->autoEscape === true && $curBlock !== 'condition') {
2494
+				$output = '(is_string($tmp=' . $output . ') ? htmlspecialchars($tmp, ENT_QUOTES, $this->charset) : $tmp)';
2495
+			}
2496
+
2497
+			// handle modifiers
2498
+			if ($curBlock !== 'modifier' && $hasModifiers) {
2499
+				$ptr    = 0;
2500
+				$output = $this->replaceModifiers(array(null, null, $output, $match[5]), 'var', $ptr);
2501
+				if ($pointer !== null) {
2502
+					$pointer += $ptr;
2503
+				}
2504
+				$matchedLength += $ptr;
2505
+			}
2506
+
2507
+			if (is_array($parsingParams)) {
2508
+				$parsingParams[] = array($output, $key);
2509
+
2510
+				return $parsingParams;
2511
+			} elseif ($curBlock === 'namedparam') {
2512
+				return array($output, $key);
2513
+			} elseif ($curBlock === 'string' || $curBlock === 'delimited_string') {
2514
+				return array($matchedLength, $output);
2515
+			} elseif ($curBlock === 'expression' || $curBlock === 'variable') {
2516
+				return $output;
2517
+			} elseif (isset($assign)) {
2518
+				return self::PHP_OPEN . $output . ';' . self::PHP_CLOSE;
2519
+			} else {
2520
+				return $output;
2521
+			}
2522
+		} else {
2523
+			if ($curBlock === 'string' || $curBlock === 'delimited_string') {
2524
+				return array(0, '');
2525
+			} else {
2526
+				throw new CompilationException($this, 'Invalid variable name <em>' . $substr . '</em>');
2527
+			}
2528
+		}
2529
+	}
2530
+
2531
+	/**
2532
+	 * Parses any number of chained method calls/property reads.
2533
+	 *
2534
+	 * @param string $output     the variable or whatever upon which the method are called
2535
+	 * @param string $methodCall method call source, starting at "->"
2536
+	 * @param string $curBlock   the current parser-block being processed
2537
+	 * @param int    $pointer    a reference to a pointer that will be increased by the amount of characters parsed
2538
+	 *
2539
+	 * @return string parsed call(s)/read(s)
2540
+	 */
2541
+	protected function parseMethodCall($output, $methodCall, $curBlock, &$pointer)
2542
+	{
2543
+		$ptr = 0;
2544
+		$len = strlen($methodCall);
2545
+
2546
+		while ($ptr < $len) {
2547
+			if (strpos($methodCall, '->', $ptr) === $ptr) {
2548
+				$ptr += 2;
2549
+			}
2550
+
2551
+			if (in_array(
2552
+				$methodCall[$ptr], array(
2553
+					';',
2554
+					',',
2555
+					'/',
2556
+					' ',
2557
+					"\t",
2558
+					"\r",
2559
+					"\n",
2560
+					')',
2561
+					'+',
2562
+					'*',
2563
+					'%',
2564
+					'=',
2565
+					'-',
2566
+					'|'
2567
+				)
2568
+			) || substr($methodCall, $ptr, strlen($this->rd)) === $this->rd
2569
+			) {
2570
+				// break char found
2571
+				break;
2572
+			}
2573
+
2574
+			if (!preg_match('/^([a-z0-9_]+)(\(.*?\))?/i', substr($methodCall, $ptr), $methMatch)) {
2575
+				break;
2576
+			}
2577
+
2578
+			if (empty($methMatch[2])) {
2579
+				// property
2580
+				if ($curBlock === 'root') {
2581
+					$output .= '->' . $methMatch[1];
2582
+				} else {
2583
+					$output = '(($tmp = ' . $output . ') ? $tmp->' . $methMatch[1] . ' : null)';
2584
+				}
2585
+				$ptr += strlen($methMatch[1]);
2586
+			} else {
2587
+				// method
2588
+				if (substr($methMatch[2], 0, 2) === '()') {
2589
+					$parsedCall = $methMatch[1] . '()';
2590
+					$ptr += strlen($methMatch[1]) + 2;
2591
+				} else {
2592
+					$parsedCall = $this->parseFunction($methodCall, $ptr, strlen($methodCall), false, 'method', $ptr);
2593
+				}
2594
+				if ($this->securityPolicy !== null) {
2595
+					$argPos = strpos($parsedCall, '(');
2596
+					$method = strtolower(substr($parsedCall, 0, $argPos));
2597
+					$args   = substr($parsedCall, $argPos);
2598
+					if ($curBlock === 'root') {
2599
+						$output = '$this->getSecurityPolicy()->callMethod($this, ' . $output . ', ' . var_export($method, true) . ', array' . $args . ')';
2600
+					} else {
2601
+						$output = '(($tmp = ' . $output . ') ? $this->getSecurityPolicy()->callMethod($this, $tmp, ' . var_export($method, true) . ', array' . $args . ') : null)';
2602
+					}
2603
+				} else {
2604
+					if ($curBlock === 'root') {
2605
+						$output .= '->' . $parsedCall;
2606
+					} else {
2607
+						$output = '(($tmp = ' . $output . ') ? $tmp->' . $parsedCall . ' : null)';
2608
+					}
2609
+				}
2610
+			}
2611
+		}
2612
+
2613
+		$pointer += $ptr;
2614
+
2615
+		return $output;
2616
+	}
2617
+
2618
+	/**
2619
+	 * Parses a constant variable (a variable that doesn't contain another variable) and preprocesses it to save
2620
+	 * runtime processing time.
2621
+	 *
2622
+	 * @param string $key      the variable to parse
2623
+	 * @param string $curBlock the current parser-block being processed
2624
+	 *
2625
+	 * @return string parsed variable
2626
+	 */
2627
+	protected function parseVarKey($key, $curBlock)
2628
+	{
2629
+		if ($key === '') {
2630
+			return '$this->scope';
2631
+		}
2632
+		if (substr($key, 0, 1) === '.') {
2633
+			$key = 'dwoo' . $key;
2634
+		}
2635
+		if (preg_match('#dwoo\.(get|post|server|cookies|session|env|request)((?:\.[a-z0-9_-]+)+)#i', $key, $m)) {
2636
+			$global = strtoupper($m[1]);
2637
+			if ($global === 'COOKIES') {
2638
+				$global = 'COOKIE';
2639
+			}
2640
+			$key = '$_' . $global;
2641
+			foreach (explode('.', ltrim($m[2], '.')) as $part) {
2642
+				$key .= '[' . var_export($part, true) . ']';
2643
+			}
2644
+			if ($curBlock === 'root') {
2645
+				$output = $key;
2646
+			} else {
2647
+				$output = '(isset(' . $key . ')?' . $key . ':null)';
2648
+			}
2649
+		} elseif (preg_match('#dwoo\\.const\\.([a-z0-9\\\\_:]+)#i', $key, $m)) {
2650
+			return $this->parseConstKey($m[1], $curBlock);
2651
+		} elseif ($this->scope !== null) {
2652
+			if (strstr($key, '.') === false && strstr($key, '[') === false && strstr($key, '->') === false) {
2653
+				if ($key === 'dwoo') {
2654
+					$output = '$this->globals';
2655
+				} elseif ($key === '_root' || $key === '__') {
2656
+					$output = '$this->data';
2657
+				} elseif ($key === '_parent' || $key === '_') {
2658
+					$output = '$this->readParentVar(1)';
2659
+				} elseif ($key === '_key') {
2660
+					$output = '$tmp_key';
2661
+				} else {
2662
+					if ($curBlock === 'root') {
2663
+						$output = '$this->scope["' . $key . '"]';
2664
+					} else {
2665
+						$output = '(isset($this->scope["' . $key . '"]) ? $this->scope["' . $key . '"] : null)';
2666
+					}
2667
+				}
2668
+			} else {
2669
+				preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+|(\\\?[\'"])[^\3]*?\3)\]?#i', $key, $m);
2670
+
2671
+				$i = $m[2][0];
2672
+				if ($i === '_parent' || $i === '_') {
2673
+					$parentCnt = 0;
2674
+
2675
+					while (true) {
2676
+						++ $parentCnt;
2677
+						array_shift($m[2]);
2678
+						array_shift($m[1]);
2679
+						if (current($m[2]) === '_parent') {
2680
+							continue;
2681
+						}
2682
+						break;
2683
+					}
2684
+
2685
+					$output = '$this->readParentVar(' . $parentCnt . ')';
2686
+				} else {
2687
+					if ($i === 'dwoo') {
2688
+						$output = '$this->globals';
2689
+						array_shift($m[2]);
2690
+						array_shift($m[1]);
2691
+					} elseif ($i === '_root' || $i === '__') {
2692
+						$output = '$this->data';
2693
+						array_shift($m[2]);
2694
+						array_shift($m[1]);
2695
+					} elseif ($i === '_key') {
2696
+						$output = '$tmp_key';
2697
+					} else {
2698
+						$output = '$this->scope';
2699
+					}
2700
+
2701
+					while (count($m[1]) && $m[1][0] !== '->') {
2702
+						$m[2][0] = preg_replace('/(^\\\([\'"])|\\\([\'"])$)/x', '$2$3', $m[2][0]);
2703
+						if (substr($m[2][0], 0, 1) == '"' || substr($m[2][0], 0, 1) == "'") {
2704
+							$output .= '[' . $m[2][0] . ']';
2705
+						} else {
2706
+							$output .= '["' . $m[2][0] . '"]';
2707
+						}
2708
+						array_shift($m[2]);
2709
+						array_shift($m[1]);
2710
+					}
2711
+
2712
+					if ($curBlock !== 'root') {
2713
+						$output = '(isset(' . $output . ') ? ' . $output . ':null)';
2714
+					}
2715
+				}
2716
+
2717
+				if (count($m[2])) {
2718
+					unset($m[0]);
2719
+					$output = '$this->readVarInto(' . str_replace("\n", '', var_export($m, true)) . ', ' . $output . ', ' . ($curBlock == 'root' ? 'false' : 'true') . ')';
2720
+				}
2721
+			}
2722
+		} else {
2723
+			preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+)\]?#i', $key, $m);
2724
+			unset($m[0]);
2725
+			$output = '$this->readVar(' . str_replace("\n", '', var_export($m, true)) . ')';
2726
+		}
2727
+
2728
+		return $output;
2729
+	}
2730
+
2731
+	/**
2732
+	 * Flattens a variable tree, this helps in parsing very complex variables such as $var.foo[$foo.bar->baz].baz,
2733
+	 * it computes the contents of the brackets first and works out from there.
2734
+	 *
2735
+	 * @param array $tree     the variable tree parsed by he parseVar() method that must be flattened
2736
+	 * @param bool  $recursed leave that to false by default, it is only for internal use
2737
+	 *
2738
+	 * @return string flattened tree
2739
+	 */
2740
+	protected function flattenVarTree(array $tree, $recursed = false)
2741
+	{
2742
+		$out = $recursed ? '".$this->readVarInto(' : '';
2743
+		foreach ($tree as $bit) {
2744
+			if (is_array($bit)) {
2745
+				$out .= '.' . $this->flattenVarTree($bit, false);
2746
+			} else {
2747
+				$key = str_replace('"', '\\"', $bit);
2748
+
2749
+				if (substr($key, 0, 1) === '$') {
2750
+					$out .= '".' . $this->parseVar($key, 0, strlen($key), false, 'variable') . '."';
2751
+				} else {
2752
+					$cnt = substr_count($key, '$');
2753
+
2754
+					if ($this->debug) {
2755
+						echo 'PARSING SUBVARS IN : ' . $key . "\n";
2756
+					}
2757
+					if ($cnt > 0) {
2758
+						while (-- $cnt >= 0) {
2759
+							if (isset($last)) {
2760
+								$last = strrpos($key, '$', - (strlen($key) - $last + 1));
2761
+							} else {
2762
+								$last = strrpos($key, '$');
2763
+							}
2764
+							preg_match('#\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', substr($key, $last), $submatch);
2765
+
2766
+							$len = strlen($submatch[0]);
2767
+							$key = substr_replace(
2768
+								$key, preg_replace_callback(
2769
+									'#(\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*)' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', array(
2770
+										$this,
2771
+										'replaceVarKeyHelper'
2772
+									), substr($key, $last, $len)
2773
+								), $last, $len
2774
+							);
2775
+							if ($this->debug) {
2776
+								echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2777
+							}
2778
+						}
2779
+						unset($last);
2780
+
2781
+						$out .= $key;
2782
+					} else {
2783
+						$out .= $key;
2784
+					}
2785
+				}
2786
+			}
2787
+		}
2788
+		$out .= $recursed ? ', true)."' : '';
2789
+
2790
+		return $out;
2791
+	}
2792
+
2793
+	/**
2794
+	 * Helper function that parses a variable.
2795
+	 *
2796
+	 * @param array $match the matched variable, array(1=>"string match")
2797
+	 *
2798
+	 * @return string parsed variable
2799
+	 */
2800
+	protected function replaceVarKeyHelper($match)
2801
+	{
2802
+		return '".' . $this->parseVar($match[0], 0, strlen($match[0]), false, 'variable') . '."';
2803
+	}
2804
+
2805
+	/**
2806
+	 * Parses various constants, operators or non-quoted strings.
2807
+	 *
2808
+	 * @param string $in            the string within which we must parse something
2809
+	 * @param int    $from          the starting offset of the parsed area
2810
+	 * @param int    $to            the ending offset of the parsed area
2811
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2812
+	 *                              default
2813
+	 * @param string $curBlock      the current parser-block being processed
2814
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2815
+	 *                              or null by default
2816
+	 *
2817
+	 * @return string parsed values
2818
+	 * @throws Exception
2819
+	 */
2820
+	protected function parseOthers($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2821
+	{
2822
+		$substr = substr($in, $from, $to - $from);
2823
+
2824
+		$end = strlen($substr);
2825
+
2826
+		if ($curBlock === 'condition') {
2827
+			$breakChars = array(
2828
+				'(',
2829
+				')',
2830
+				' ',
2831
+				'||',
2832
+				'&&',
2833
+				'|',
2834
+				'&',
2835
+				'>=',
2836
+				'<=',
2837
+				'===',
2838
+				'==',
2839
+				'=',
2840
+				'!==',
2841
+				'!=',
2842
+				'<<',
2843
+				'<',
2844
+				'>>',
2845
+				'>',
2846
+				'^',
2847
+				'~',
2848
+				',',
2849
+				'+',
2850
+				'-',
2851
+				'*',
2852
+				'/',
2853
+				'%',
2854
+				'!',
2855
+				'?',
2856
+				':',
2857
+				$this->rd,
2858
+				';'
2859
+			);
2860
+		} elseif ($curBlock === 'modifier') {
2861
+			$breakChars = array(' ', ',', ')', ':', '|', "\r", "\n", "\t", ';', $this->rd);
2862
+		} elseif ($curBlock === 'expression') {
2863
+			$breakChars = array('/', '%', '+', '-', '*', ' ', ',', ')', "\r", "\n", "\t", ';', $this->rd);
2864
+		} else {
2865
+			$breakChars = array(' ', ',', ')', "\r", "\n", "\t", ';', $this->rd);
2866
+		}
2867
+
2868
+		$breaker = false;
2869
+		while (list($k, $char) = each($breakChars)) {
2870
+			$test = strpos($substr, $char);
2871
+			if ($test !== false && $test < $end) {
2872
+				$end     = $test;
2873
+				$breaker = $k;
2874
+			}
2875
+		}
2876
+
2877
+		if ($curBlock === 'condition') {
2878
+			if ($end === 0 && $breaker !== false) {
2879
+				$end = strlen($breakChars[$breaker]);
2880
+			}
2881
+		}
2882
+
2883
+		if ($end !== false) {
2884
+			$substr = substr($substr, 0, $end);
2885
+		}
2886
+
2887
+		if ($pointer !== null) {
2888
+			$pointer += strlen($substr);
2889
+		}
2890
+
2891
+		$src    = $substr;
2892
+		$substr = trim($substr);
2893
+
2894
+		if (strtolower($substr) === 'false' || strtolower($substr) === 'no' || strtolower($substr) === 'off') {
2895
+			if ($this->debug) {
2896
+				echo 'BOOLEAN(FALSE) PARSED' . "\n";
2897
+			}
2898
+			$substr = 'false';
2899
+			$type   = self::T_BOOL;
2900
+		} elseif (strtolower($substr) === 'true' || strtolower($substr) === 'yes' || strtolower($substr) === 'on') {
2901
+			if ($this->debug) {
2902
+				echo 'BOOLEAN(TRUE) PARSED' . "\n";
2903
+			}
2904
+			$substr = 'true';
2905
+			$type   = self::T_BOOL;
2906
+		} elseif ($substr === 'null' || $substr === 'NULL') {
2907
+			if ($this->debug) {
2908
+				echo 'NULL PARSED' . "\n";
2909
+			}
2910
+			$substr = 'null';
2911
+			$type   = self::T_NULL;
2912
+		} elseif (is_numeric($substr)) {
2913
+			$substr = (float)$substr;
2914
+			if ((int)$substr == $substr) {
2915
+				$substr = (int)$substr;
2916
+			}
2917
+			$type = self::T_NUMERIC;
2918
+			if ($this->debug) {
2919
+				echo 'NUMBER (' . $substr . ') PARSED' . "\n";
2920
+			}
2921
+		} elseif (preg_match('{^-?(\d+|\d*(\.\d+))\s*([/*%+-]\s*-?(\d+|\d*(\.\d+)))+$}', $substr)) {
2922
+			if ($this->debug) {
2923
+				echo 'SIMPLE MATH PARSED . "\n"';
2924
+			}
2925
+			$type   = self::T_MATH;
2926
+			$substr = '(' . $substr . ')';
2927
+		} elseif ($curBlock === 'condition' && array_search($substr, $breakChars, true) !== false) {
2928
+			if ($this->debug) {
2929
+				echo 'BREAKCHAR (' . $substr . ') PARSED' . "\n";
2930
+			}
2931
+			$type = self::T_BREAKCHAR;
2932
+			//$substr = '"'.$substr.'"';
2933
+		} else {
2934
+			$substr = $this->replaceStringVars('\'' . str_replace('\'', '\\\'', $substr) . '\'', '\'', $curBlock);
2935
+			$type   = self::T_UNQUOTED_STRING;
2936
+			if ($this->debug) {
2937
+				echo 'BLABBER (' . $substr . ') CASTED AS STRING' . "\n";
2938
+			}
2939
+		}
2940
+
2941
+		if (is_array($parsingParams)) {
2942
+			$parsingParams[] = array($substr, $src, $type);
2943
+
2944
+			return $parsingParams;
2945
+		} elseif ($curBlock === 'namedparam') {
2946
+			return array($substr, $src, $type);
2947
+		} elseif ($curBlock === 'expression') {
2948
+			return $substr;
2949
+		} else {
2950
+			throw new Exception('Something went wrong');
2951
+		}
2952
+	}
2953
+
2954
+	/**
2955
+	 * Replaces variables within a parsed string.
2956
+	 *
2957
+	 * @param string $string   the parsed string
2958
+	 * @param string $first    the first character parsed in the string, which is the string delimiter (' or ")
2959
+	 * @param string $curBlock the current parser-block being processed
2960
+	 *
2961
+	 * @return string the original string with variables replaced
2962
+	 */
2963
+	protected function replaceStringVars($string, $first, $curBlock = '')
2964
+	{
2965
+		$pos = 0;
2966
+		if ($this->debug) {
2967
+			echo 'STRING VAR REPLACEMENT : ' . $string . "\n";
2968
+		}
2969
+		// replace vars
2970
+		while (($pos = strpos($string, '$', $pos)) !== false) {
2971
+			$prev = substr($string, $pos - 1, 1);
2972
+			if ($prev === '\\') {
2973
+				++ $pos;
2974
+				continue;
2975
+			}
2976
+
2977
+			$var = $this->parse($string, $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
2978
+			$len = $var[0];
2979
+			$var = $this->parse(str_replace('\\' . $first, $first, $string), $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
2980
+
2981
+			if ($prev === '`' && substr($string, $pos + $len, 1) === '`') {
2982
+				$string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos - 1, $len + 2);
2983
+			} else {
2984
+				$string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos, $len);
2985
+			}
2986
+			$pos += strlen($var[1]) + 2;
2987
+			if ($this->debug) {
2988
+				echo 'STRING VAR REPLACEMENT DONE : ' . $string . "\n";
2989
+			}
2990
+		}
2991
+
2992
+		// handle modifiers
2993
+		// TODO Obsolete?
2994
+		$string = preg_replace_callback(
2995
+			'#("|\')\.(.+?)\.\1((?:\|(?:@?[a-z0-9_]+(?:(?::("|\').+?\4|:[^`]*))*))+)#i', array(
2996
+			$this,
2997
+			'replaceModifiers'
2998
+			), $string
2999
+		);
3000
+
3001
+		// replace escaped dollar operators by unescaped ones if required
3002
+		if ($first === "'") {
3003
+			$string = str_replace('\\$', '$', $string);
3004
+		}
3005
+
3006
+		return $string;
3007
+	}
3008
+
3009
+	/**
3010
+	 * Replaces the modifiers applied to a string or a variable.
3011
+	 *
3012
+	 * @param array  $m        the regex matches that must be array(1=>"double or single quotes enclosing a string,
3013
+	 *                         when applicable", 2=>"the string or var", 3=>"the modifiers matched")
3014
+	 * @param string $curBlock the current parser-block being processed
3015
+	 * @param null   $pointer
3016
+	 *
3017
+	 * @return string the input enclosed with various function calls according to the modifiers found
3018
+	 * @throws CompilationException
3019
+	 * @throws Exception
3020
+	 */
3021
+	protected function replaceModifiers(array $m, $curBlock = null, &$pointer = null)
3022
+	{
3023
+		if ($this->debug) {
3024
+			echo 'PARSING MODIFIERS : ' . $m[3] . "\n";
3025
+		}
3026
+
3027
+		if ($pointer !== null) {
3028
+			$pointer += strlen($m[3]);
3029
+		}
3030
+		// remove first pipe
3031
+		$cmdstrsrc = substr($m[3], 1);
3032
+		// remove last quote if present
3033
+		if (substr($cmdstrsrc, - 1, 1) === $m[1]) {
3034
+			$cmdstrsrc = substr($cmdstrsrc, 0, - 1);
3035
+			$add       = $m[1];
3036
+		}
3037
+
3038
+		$output = $m[2];
3039
+
3040
+		$continue = true;
3041
+		while (strlen($cmdstrsrc) > 0 && $continue) {
3042
+			if ($cmdstrsrc[0] === '|') {
3043
+				$cmdstrsrc = substr($cmdstrsrc, 1);
3044
+				continue;
3045
+			}
3046
+			if ($cmdstrsrc[0] === ' ' || $cmdstrsrc[0] === ';' || substr($cmdstrsrc, 0, strlen($this->rd)) === $this->rd) {
3047
+				if ($this->debug) {
3048
+					echo 'MODIFIER PARSING ENDED, RIGHT DELIMITER or ";" FOUND' . "\n";
3049
+				}
3050
+				$continue = false;
3051
+				if ($pointer !== null) {
3052
+					$pointer -= strlen($cmdstrsrc);
3053
+				}
3054
+				break;
3055
+			}
3056
+			$cmdstr   = $cmdstrsrc;
3057
+			$paramsep = ':';
3058
+			if (!preg_match('/^(@{0,2}[a-z_][a-z0-9_]*)(:)?/i', $cmdstr, $match)) {
3059
+				throw new CompilationException($this, 'Invalid modifier name, started with : ' . substr($cmdstr, 0, 10));
3060
+			}
3061
+			$paramspos = !empty($match[2]) ? strlen($match[1]) : false;
3062
+			$func      = $match[1];
3063
+
3064
+			$state = 0;
3065
+			if ($paramspos === false) {
3066
+				$cmdstrsrc = substr($cmdstrsrc, strlen($func));
3067
+				$params    = array();
3068
+				if ($this->debug) {
3069
+					echo 'MODIFIER (' . $func . ') CALLED WITH NO PARAMS' . "\n";
3070
+				}
3071
+			} else {
3072
+				$paramstr = substr($cmdstr, $paramspos + 1);
3073
+				if (substr($paramstr, - 1, 1) === $paramsep) {
3074
+					$paramstr = substr($paramstr, 0, - 1);
3075
+				}
3076
+
3077
+				$ptr    = 0;
3078
+				$params = array();
3079
+				while ($ptr < strlen($paramstr)) {
3080
+					if ($this->debug) {
3081
+						echo 'MODIFIER (' . $func . ') START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
3082
+					}
3083
+					if ($this->debug) {
3084
+						echo $paramstr . '--' . $ptr . '--' . strlen($paramstr) . '--modifier' . "\n";
3085
+					}
3086
+					$params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'modifier', $ptr);
3087
+					if ($this->debug) {
3088
+						echo 'PARAM PARSED, POINTER AT ' . $ptr . "\n";
3089
+					}
3090
+
3091
+					if ($ptr >= strlen($paramstr)) {
3092
+						if ($this->debug) {
3093
+							echo 'PARAM PARSING ENDED, PARAM STRING CONSUMED' . "\n";
3094
+						}
3095
+						break;
3096
+					}
3097
+
3098
+					if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === '|' || $paramstr[$ptr] === ';' || substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
3099
+						if ($this->debug) {
3100
+							echo 'PARAM PARSING ENDED, " ", "|", RIGHT DELIMITER or ";" FOUND, POINTER AT ' . $ptr . "\n";
3101
+						}
3102
+						if ($paramstr[$ptr] !== '|') {
3103
+							$continue = false;
3104
+							if ($pointer !== null) {
3105
+								$pointer -= strlen($paramstr) - $ptr;
3106
+							}
3107
+						}
3108
+						++ $ptr;
3109
+						break;
3110
+					}
3111
+					if ($ptr < strlen($paramstr) && $paramstr[$ptr] === ':') {
3112
+						++ $ptr;
3113
+					}
3114
+				}
3115
+				$cmdstrsrc = substr($cmdstrsrc, strlen($func) + 1 + $ptr);
3116
+				foreach ($params as $k => $p) {
3117
+					if (is_array($p) && is_array($p[1])) {
3118
+						$state |= 2;
3119
+					} else {
3120
+						if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m)) {
3121
+							$params[$k] = array($m[2], array('true', 'true'));
3122
+						} else {
3123
+							if ($state & 2) {
3124
+								throw new CompilationException($this, 'You can not use an unnamed parameter after a named one');
3125
+							}
3126
+							$state |= 1;
3127
+						}
3128
+					}
3129
+				}
3130
+			}
3131
+
3132
+			// check if we must use array_map with this plugin or not
3133
+			$mapped = false;
3134
+			if (substr($func, 0, 1) === '@') {
3135
+				$func   = substr($func, 1);
3136
+				$mapped = true;
3137
+			}
3138
+
3139
+			$pluginType = $this->getPluginType($func);
3140
+
3141
+			if ($state & 2) {
3142
+				array_unshift($params, array('value', is_array($output) ? $output : array($output, $output)));
3143
+			} else {
3144
+				array_unshift($params, is_array($output) ? $output : array($output, $output));
3145
+			}
3146
+
3147
+			if ($pluginType & Core::NATIVE_PLUGIN) {
3148
+				$params = $this->mapParams($params, null, $state);
3149
+
3150
+				$params = $params['*'][0];
3151
+
3152
+				$params = self::implode_r($params);
3153
+
3154
+				if ($mapped) {
3155
+					$output = '$this->arrayMap(\'' . $func . '\', array(' . $params . '))';
3156
+				} else {
3157
+					$output = $func . '(' . $params . ')';
3158
+				}
3159
+			} elseif ($pluginType & Core::PROXY_PLUGIN) {
3160
+				$params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state);
3161
+				foreach ($params as &$p) {
3162
+					$p = $p[0];
3163
+				}
3164
+				$output = call_user_func(array($this->getDwoo()->getPluginProxy(), 'getCode'), $func, $params);
3165
+			} elseif ($pluginType & Core::SMARTY_MODIFIER) {
3166
+				$params = $this->mapParams($params, null, $state);
3167
+				$params = $params['*'][0];
3168
+
3169
+				$params = self::implode_r($params);
3170
+
3171
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
3172
+					$callback = $this->customPlugins[$func]['callback'];
3173
+					if (is_array($callback)) {
3174
+						if (is_object($callback[0])) {
3175
+							$output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(' . $params . '))';
3176
+						} else {
3177
+							$output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3178
+						}
3179
+					} elseif ($mapped) {
3180
+						$output = '$this->arrayMap(\'' . $callback . '\', array(' . $params . '))';
3181
+					} else {
3182
+						$output = $callback . '(' . $params . ')';
3183
+					}
3184
+				} elseif ($mapped) {
3185
+					$output = '$this->arrayMap(\'smarty_modifier_' . $func . '\', array(' . $params . '))';
3186
+				} else {
3187
+					$output = 'smarty_modifier_' . $func . '(' . $params . ')';
3188
+				}
3189
+			} else {
3190
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
3191
+					$callback   = $this->customPlugins[$func]['callback'];
3192
+					$pluginName = $callback;
3193
+				} else {
3194
+					if (class_exists('Plugin' . Core::toCamelCase($func)) !== false || function_exists('Plugin' .
3195
+							Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''))
3196
+						!== false) {
3197
+						$pluginName = 'Plugin' . Core::toCamelCase($func);
3198
+					} else {
3199
+						$pluginName = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func);
3200
+					}
3201
+					if ($pluginType & Core::CLASS_PLUGIN) {
3202
+						$callback = array($pluginName, ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process');
3203
+					} else {
3204
+						$callback = $pluginName . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '');
3205
+					}
3206
+				}
3207
+				$params = $this->mapParams($params, $callback, $state);
3208
+
3209
+				foreach ($params as &$p) {
3210
+					$p = $p[0];
3211
+				}
3212
+
3213
+				if ($pluginType & Core::FUNC_PLUGIN) {
3214
+					if ($pluginType & Core::COMPILABLE_PLUGIN) {
3215
+						if ($mapped) {
3216
+							throw new CompilationException($this, 'The @ operator can not be used on compiled plugins.');
3217
+						}
3218
+						if ($pluginType & Core::CUSTOM_PLUGIN) {
3219
+							$funcCompiler = $this->customPlugins[$func]['callback'];
3220
+						} else {
3221
+							if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
3222
+								$funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
3223
+							} else {
3224
+								$funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
3225
+									'Compile';
3226
+							}
3227
+						}
3228
+						array_unshift($params, $this);
3229
+						$output = call_user_func_array($funcCompiler, $params);
3230
+					} else {
3231
+						array_unshift($params, '$this');
3232
+
3233
+						$params = self::implode_r($params);
3234
+						if ($mapped) {
3235
+							$output = '$this->arrayMap(\'' . $pluginName . '\', array(' . $params . '))';
3236
+						} else {
3237
+							$output = $pluginName . '(' . $params . ')';
3238
+						}
3239
+					}
3240
+				} else {
3241
+					if ($pluginType & Core::COMPILABLE_PLUGIN) {
3242
+						if ($mapped) {
3243
+							throw new CompilationException($this, 'The @ operator can not be used on compiled plugins.');
3244
+						}
3245
+						if ($pluginType & Core::CUSTOM_PLUGIN) {
3246
+							$callback = $this->customPlugins[$func]['callback'];
3247
+							if (!is_array($callback)) {
3248
+								if (!method_exists($callback, 'compile')) {
3249
+									throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
3250
+								}
3251
+								if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
3252
+									$funcCompiler = array($callback, 'compile');
3253
+								} else {
3254
+									$funcCompiler = array(new $callback(), 'compile');
3255
+								}
3256
+							} else {
3257
+								$funcCompiler = $callback;
3258
+							}
3259
+						} else {
3260
+							if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3261
+								$funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
3262
+							} else {
3263
+								$funcCompiler = array(
3264
+									Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
3265
+									'compile'
3266
+								);
3267
+							}
3268
+							array_unshift($params, $this);
3269
+						}
3270
+						$output = call_user_func_array($funcCompiler, $params);
3271
+					} else {
3272
+						$params = self::implode_r($params);
3273
+
3274
+						if ($pluginType & Core::CUSTOM_PLUGIN) {
3275
+							if (is_object($callback[0])) {
3276
+								$output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(' . $params . '))';
3277
+							} else {
3278
+								$output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3279
+							}
3280
+						} elseif ($mapped) {
3281
+							$output = '$this->arrayMap(array($this->getObjectPlugin(\''.
3282
+								Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '\'), 
3283 3283
                             \'process\'), array(' . $params . '))';
3284
-                        } else {
3285
-                            if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3286
-                                $output = '$this->classCall(\'Plugin' . Core::toCamelCase($func) . '\', array(' . $params . '))';
3287
-                            } else {
3288
-                                $output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
3289
-                            }
3290
-                        }
3291
-                    }
3292
-                }
3293
-            }
3294
-        }
3295
-
3296
-        if ($curBlock === 'namedparam') {
3297
-            return array($output, $output);
3298
-        } elseif ($curBlock === 'var' || $m[1] === null) {
3299
-            return $output;
3300
-        } elseif ($curBlock === 'string' || $curBlock === 'root') {
3301
-            return $m[1] . '.' . $output . '.' . $m[1] . (isset($add) ? $add : null);
3302
-        }
3303
-
3304
-        return '';
3305
-    }
3306
-
3307
-    /**
3308
-     * Recursively implodes an array in a similar manner as var_export() does but with some tweaks
3309
-     * to handle pre-compiled values and the fact that we do not need to enclose everything with
3310
-     * "array" and do not require top-level keys to be displayed.
3311
-     *
3312
-     * @param array $params        the array to implode
3313
-     * @param bool  $recursiveCall if set to true, the function outputs key names for the top level
3314
-     *
3315
-     * @return string the imploded array
3316
-     */
3317
-    public static function implode_r(array $params, $recursiveCall = false)
3318
-    {
3319
-        $out = '';
3320
-        foreach ($params as $k => $p) {
3321
-            if (is_array($p)) {
3322
-                $out2 = 'array(';
3323
-                foreach ($p as $k2 => $v) {
3324
-                    $out2 .= var_export($k2, true) . ' => ' . (is_array($v) ? 'array(' . self::implode_r($v, true) . ')' : $v) . ', ';
3325
-                }
3326
-                $p = rtrim($out2, ', ') . ')';
3327
-            }
3328
-            if ($recursiveCall) {
3329
-                $out .= var_export($k, true) . ' => ' . $p . ', ';
3330
-            } else {
3331
-                $out .= $p . ', ';
3332
-            }
3333
-        }
3334
-
3335
-        return rtrim($out, ', ');
3336
-    }
3337
-
3338
-    /**
3339
-     * Returns the plugin type of a plugin and adds it to the used plugins array if required.
3340
-     *
3341
-     * @param string $name plugin name, as found in the template
3342
-     *
3343
-     * @return int type as a multi bit flag composed of the Dwoo plugin types constants
3344
-     * @throws Exception
3345
-     * @throws SecurityException
3346
-     * @throws Exception
3347
-     */
3348
-    protected function getPluginType($name)
3349
-    {
3350
-        $pluginType = - 1;
3351
-
3352
-        if (($this->securityPolicy === null && (function_exists($name) || strtolower($name) === 'isset' || strtolower($name) === 'empty')) || ($this->securityPolicy !== null && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) !== false)) {
3353
-            $phpFunc = true;
3354
-        } elseif ($this->securityPolicy !== null && function_exists($name) && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) === false) {
3355
-            throw new SecurityException('Call to a disallowed php function : ' . $name);
3356
-        }
3357
-
3358
-        while ($pluginType <= 0) {
3359
-            // Template plugin compilable
3360
-            if (isset($this->templatePlugins[$name])) {
3361
-                $pluginType = Core::TEMPLATE_PLUGIN | Core::COMPILABLE_PLUGIN;
3362
-            } // Custom plugin
3363
-            elseif (isset($this->customPlugins[$name])) {
3364
-                $pluginType = $this->customPlugins[$name]['type'] | Core::CUSTOM_PLUGIN;
3365
-            } // Class blocks plugin
3366
-            elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name), false) !==
3367
-                false) {
3368
-                if (is_subclass_of(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3369
-                    $pluginType = Core::BLOCK_PLUGIN;
3370
-                } else {
3371
-                    $pluginType = Core::CLASS_PLUGIN;
3372
-                }
3373
-                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name));
3374
-                if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3375
-                    $pluginType |= Core::COMPILABLE_PLUGIN;
3376
-                }
3377
-            } // Class functions plugin
3378
-            elseif(class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name), false) !==
3379
-                false) {
3380
-                $pluginType = Core::CLASS_PLUGIN;
3381
-                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name));
3382
-                if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3383
-                    $pluginType |= Core::COMPILABLE_PLUGIN;
3384
-                }
3385
-            } // Class without namespace
3386
-            elseif(class_exists('Plugin' . Core::toCamelCase($name), false) !== false) {
3387
-                $pluginType = Core::CLASS_PLUGIN;
3388
-                $interfaces = class_implements('Plugin' . Core::toCamelCase($name));
3389
-                if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3390
-                    $pluginType |= Core::COMPILABLE_PLUGIN;
3391
-                }
3392
-            } // Function plugin (with/without namespaces)
3393
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase
3394
-                    ($name)) !==
3395
-                false || function_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3396
-                $pluginType = Core::FUNC_PLUGIN;
3397
-            } // Function plugin compile (with/without namespaces)
3398
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name) .
3399
-                    'Compile') !== false || function_exists('Plugin' . Core::toCamelCase($name) . 'Compile') !==
3400
-                false) {
3401
-                $pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3402
-            } // Helper plugin compile
3403
-            elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name) . 'Compile')
3404
-                !== false) {
3405
-                $pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3406
-            } // Smarty modifier
3407
-            elseif (function_exists('smarty_modifier_' . $name) !== false) {
3408
-                $pluginType = Core::SMARTY_MODIFIER;
3409
-            } // Smarty function
3410
-            elseif (function_exists('smarty_function_' . $name) !== false) {
3411
-                $pluginType = Core::SMARTY_FUNCTION;
3412
-            } // Smarty block
3413
-            elseif (function_exists('smarty_block_' . $name) !== false) {
3414
-                $pluginType = Core::SMARTY_BLOCK;
3415
-            } // Everything else
3416
-            else {
3417
-                if ($pluginType === - 1) {
3418
-                    try {
3419
-                        $this->getDwoo()->getLoader()->loadPlugin(
3420
-                            'Plugin' . Core::toCamelCase($name));
3421
-                    }
3422
-                    catch (Exception $e) {
3423
-                        if (isset($phpFunc)) {
3424
-                            $pluginType = Core::NATIVE_PLUGIN;
3425
-                        } elseif (is_object($this->getDwoo()->getPluginProxy()) && $this->getDwoo()->getPluginProxy()->handles($name)) {
3426
-                            $pluginType = Core::PROXY_PLUGIN;
3427
-                            break;
3428
-                        } else {
3429
-                            throw $e;
3430
-                        }
3431
-                    }
3432
-                } else {
3433
-                    throw new Exception('Plugin "' . $name . '" could not be found, type:' . $pluginType);
3434
-                }
3435
-                ++ $pluginType;
3436
-            }
3437
-        }
3438
-
3439
-        if (($pluginType & Core::COMPILABLE_PLUGIN) === 0 && ($pluginType & Core::NATIVE_PLUGIN) === 0 && ($pluginType & Core::PROXY_PLUGIN) === 0) {
3440
-            $this->addUsedPlugin(Core::toCamelCase($name), $pluginType);
3441
-        }
3442
-
3443
-        return $pluginType;
3444
-    }
3445
-
3446
-    /**
3447
-     * Allows a plugin to load another one at compile time, this will also mark
3448
-     * it as used by this template so it will be loaded at runtime (which can be
3449
-     * useful for compiled plugins that rely on another plugin when their compiled
3450
-     * code runs).
3451
-     *
3452
-     * @param string $name the plugin name
3453
-     *
3454
-     * @return void
3455
-     */
3456
-    public function loadPlugin($name)
3457
-    {
3458
-        $this->getPluginType($name);
3459
-    }
3460
-
3461
-    /**
3462
-     * Runs htmlentities over the matched <?php ?> blocks when the security policy enforces that.
3463
-     *
3464
-     * @param array $match matched php block
3465
-     *
3466
-     * @return string the htmlentities-converted string
3467
-     */
3468
-    protected function phpTagEncodingHelper($match)
3469
-    {
3470
-        return htmlspecialchars($match[0]);
3471
-    }
3472
-
3473
-    /**
3474
-     * Maps the parameters received from the template onto the parameters required by the given callback.
3475
-     *
3476
-     * @param array    $params   the array of parameters
3477
-     * @param callback $callback the function or method to reflect on to find out the required parameters
3478
-     * @param int      $callType the type of call in the template, 0 = no params, 1 = php-style call, 2 = named
3479
-     *                           parameters call
3480
-     * @param array    $map      the parameter map to use, if not provided it will be built from the callback
3481
-     *
3482
-     * @return array parameters sorted in the correct order with missing optional parameters filled
3483
-     * @throws CompilationException
3484
-     */
3485
-    protected function mapParams(array $params, $callback, $callType = 2, $map = null)
3486
-    {
3487
-        if (!$map) {
3488
-            $map = $this->getParamMap($callback);
3489
-        }
3490
-
3491
-        $paramlist = array();
3492
-
3493
-        // transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values))
3494
-        $ps = array();
3495
-        foreach ($params as $p) {
3496
-            if (is_array($p[1])) {
3497
-                $ps[$p[0]] = $p[1];
3498
-            } else {
3499
-                $ps[] = $p;
3500
-            }
3501
-        }
3502
-
3503
-        // loops over the param map and assigns values from the template or default value for unset optional params
3504
-        while (list($k, $v) = each($map)) {
3505
-            if ($v[0] === '*') {
3506
-                // "rest" array parameter, fill every remaining params in it and then break
3507
-                if (count($ps) === 0) {
3508
-                    if ($v[1] === false) {
3509
-                        throw new CompilationException(
3510
-                            $this, 'Rest argument missing for ' . str_replace(
3511
-                                array(
3512
-                                    Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3513
-                                'Compile'
3514
-                                ), '', (is_array($callback) ? $callback[0] : $callback)
3515
-                            )
3516
-                        );
3517
-                    } else {
3518
-                        break;
3519
-                    }
3520
-                }
3521
-                $tmp  = array();
3522
-                $tmp2 = array();
3523
-                $tmp3 = array();
3524
-                foreach ($ps as $i => $p) {
3525
-                    $tmp[$i]  = $p[0];
3526
-                    $tmp2[$i] = $p[1];
3527
-                    $tmp3[$i] = isset($p[2]) ? $p[2] : 0;
3528
-                    unset($ps[$i]);
3529
-                }
3530
-                $paramlist[$v[0]] = array($tmp, $tmp2, $tmp3);
3531
-                unset($tmp, $tmp2, $i, $p);
3532
-                break;
3533
-            } elseif (isset($ps[$v[0]])) {
3534
-                // parameter is defined as named param
3535
-                $paramlist[$v[0]] = $ps[$v[0]];
3536
-                unset($ps[$v[0]]);
3537
-            } elseif (isset($ps[$k])) {
3538
-                // parameter is defined as ordered param
3539
-                $paramlist[$v[0]] = $ps[$k];
3540
-                unset($ps[$k]);
3541
-            } elseif ($v[1] === false) {
3542
-                // parameter is not defined and not optional, throw error
3543
-                if (is_array($callback)) {
3544
-                    if (is_object($callback[0])) {
3545
-                        $name = get_class($callback[0]) . '::' . $callback[1];
3546
-                    } else {
3547
-                        $name = $callback[0];
3548
-                    }
3549
-                } else {
3550
-                    $name = $callback;
3551
-                }
3552
-
3553
-                throw new CompilationException(
3554
-                    $this, 'Argument ' . $k . '/' . $v[0] . ' missing for ' . str_replace(
3555
-                        array(
3556
-                            Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3557
-                        'Compile'
3558
-                        ), '', $name
3559
-                    )
3560
-                );
3561
-            } elseif ($v[2] === null) {
3562
-                // enforce lowercased null if default value is null (php outputs NULL with var export)
3563
-                $paramlist[$v[0]] = array('null', null, self::T_NULL);
3564
-            } else {
3565
-                // outputs default value with var_export
3566
-                $paramlist[$v[0]] = array(var_export($v[2], true), $v[2]);
3567
-            }
3568
-        }
3569
-
3570
-        if (count($ps)) {
3571
-            foreach ($ps as $i => $p) {
3572
-                array_push($paramlist, $p);
3573
-            }
3574
-        }
3575
-
3576
-        return $paramlist;
3577
-    }
3578
-
3579
-    /**
3580
-     * Returns the parameter map of the given callback, it filters out entries typed as Dwoo and Compiler and turns the
3581
-     * rest parameter into a "*".
3582
-     *
3583
-     * @param callback $callback the function/method to reflect on
3584
-     *
3585
-     * @return array processed parameter map
3586
-     */
3587
-    protected function getParamMap($callback)
3588
-    {
3589
-        if (is_null($callback)) {
3590
-            return array(array('*', true));
3591
-        }
3592
-        if (is_array($callback)) {
3593
-            $ref = new ReflectionMethod($callback[0], $callback[1]);
3594
-        } else {
3595
-            $ref = new ReflectionFunction($callback);
3596
-        }
3597
-
3598
-        $out = array();
3599
-        foreach ($ref->getParameters() as $param) {
3600
-            if (($class = $param->getClass()) !== null && $class->name === 'Dwoo\Core') {
3601
-                continue;
3602
-            }
3603
-            if (($class = $param->getClass()) !== null && $class->name === 'Dwoo\Compiler') {
3604
-                continue;
3605
-            }
3606
-            if ($param->getName() === 'rest' && $param->isArray() === true) {
3607
-                $out[] = array('*', $param->isOptional(), null);
3608
-                continue;
3609
-            }
3610
-            $out[] = array(
3611
-                $param->getName(),
3612
-                $param->isOptional(),
3613
-                $param->isOptional() ? $param->getDefaultValue() : null
3614
-            );
3615
-        }
3616
-
3617
-        return $out;
3618
-    }
3619
-
3620
-    /**
3621
-     * Returns a default instance of this compiler, used by default by all Dwoo templates that do not have a
3622
-     * specific compiler assigned and when you do not override the default compiler factory function.
3623
-     *
3624
-     * @see    Core::setDefaultCompilerFactory()
3625
-     * @return Compiler
3626
-     */
3627
-    public static function compilerFactory()
3628
-    {
3629
-        if (self::$instance === null) {
3630
-            self::$instance = new self();
3631
-        }
3632
-
3633
-        return self::$instance;
3634
-    }
3284
+						} else {
3285
+							if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3286
+								$output = '$this->classCall(\'Plugin' . Core::toCamelCase($func) . '\', array(' . $params . '))';
3287
+							} else {
3288
+								$output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
3289
+							}
3290
+						}
3291
+					}
3292
+				}
3293
+			}
3294
+		}
3295
+
3296
+		if ($curBlock === 'namedparam') {
3297
+			return array($output, $output);
3298
+		} elseif ($curBlock === 'var' || $m[1] === null) {
3299
+			return $output;
3300
+		} elseif ($curBlock === 'string' || $curBlock === 'root') {
3301
+			return $m[1] . '.' . $output . '.' . $m[1] . (isset($add) ? $add : null);
3302
+		}
3303
+
3304
+		return '';
3305
+	}
3306
+
3307
+	/**
3308
+	 * Recursively implodes an array in a similar manner as var_export() does but with some tweaks
3309
+	 * to handle pre-compiled values and the fact that we do not need to enclose everything with
3310
+	 * "array" and do not require top-level keys to be displayed.
3311
+	 *
3312
+	 * @param array $params        the array to implode
3313
+	 * @param bool  $recursiveCall if set to true, the function outputs key names for the top level
3314
+	 *
3315
+	 * @return string the imploded array
3316
+	 */
3317
+	public static function implode_r(array $params, $recursiveCall = false)
3318
+	{
3319
+		$out = '';
3320
+		foreach ($params as $k => $p) {
3321
+			if (is_array($p)) {
3322
+				$out2 = 'array(';
3323
+				foreach ($p as $k2 => $v) {
3324
+					$out2 .= var_export($k2, true) . ' => ' . (is_array($v) ? 'array(' . self::implode_r($v, true) . ')' : $v) . ', ';
3325
+				}
3326
+				$p = rtrim($out2, ', ') . ')';
3327
+			}
3328
+			if ($recursiveCall) {
3329
+				$out .= var_export($k, true) . ' => ' . $p . ', ';
3330
+			} else {
3331
+				$out .= $p . ', ';
3332
+			}
3333
+		}
3334
+
3335
+		return rtrim($out, ', ');
3336
+	}
3337
+
3338
+	/**
3339
+	 * Returns the plugin type of a plugin and adds it to the used plugins array if required.
3340
+	 *
3341
+	 * @param string $name plugin name, as found in the template
3342
+	 *
3343
+	 * @return int type as a multi bit flag composed of the Dwoo plugin types constants
3344
+	 * @throws Exception
3345
+	 * @throws SecurityException
3346
+	 * @throws Exception
3347
+	 */
3348
+	protected function getPluginType($name)
3349
+	{
3350
+		$pluginType = - 1;
3351
+
3352
+		if (($this->securityPolicy === null && (function_exists($name) || strtolower($name) === 'isset' || strtolower($name) === 'empty')) || ($this->securityPolicy !== null && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) !== false)) {
3353
+			$phpFunc = true;
3354
+		} elseif ($this->securityPolicy !== null && function_exists($name) && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) === false) {
3355
+			throw new SecurityException('Call to a disallowed php function : ' . $name);
3356
+		}
3357
+
3358
+		while ($pluginType <= 0) {
3359
+			// Template plugin compilable
3360
+			if (isset($this->templatePlugins[$name])) {
3361
+				$pluginType = Core::TEMPLATE_PLUGIN | Core::COMPILABLE_PLUGIN;
3362
+			} // Custom plugin
3363
+			elseif (isset($this->customPlugins[$name])) {
3364
+				$pluginType = $this->customPlugins[$name]['type'] | Core::CUSTOM_PLUGIN;
3365
+			} // Class blocks plugin
3366
+			elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name), false) !==
3367
+				false) {
3368
+				if (is_subclass_of(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3369
+					$pluginType = Core::BLOCK_PLUGIN;
3370
+				} else {
3371
+					$pluginType = Core::CLASS_PLUGIN;
3372
+				}
3373
+				$interfaces = class_implements(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name));
3374
+				if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3375
+					$pluginType |= Core::COMPILABLE_PLUGIN;
3376
+				}
3377
+			} // Class functions plugin
3378
+			elseif(class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name), false) !==
3379
+				false) {
3380
+				$pluginType = Core::CLASS_PLUGIN;
3381
+				$interfaces = class_implements(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name));
3382
+				if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3383
+					$pluginType |= Core::COMPILABLE_PLUGIN;
3384
+				}
3385
+			} // Class without namespace
3386
+			elseif(class_exists('Plugin' . Core::toCamelCase($name), false) !== false) {
3387
+				$pluginType = Core::CLASS_PLUGIN;
3388
+				$interfaces = class_implements('Plugin' . Core::toCamelCase($name));
3389
+				if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3390
+					$pluginType |= Core::COMPILABLE_PLUGIN;
3391
+				}
3392
+			} // Function plugin (with/without namespaces)
3393
+			elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase
3394
+					($name)) !==
3395
+				false || function_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3396
+				$pluginType = Core::FUNC_PLUGIN;
3397
+			} // Function plugin compile (with/without namespaces)
3398
+			elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name) .
3399
+					'Compile') !== false || function_exists('Plugin' . Core::toCamelCase($name) . 'Compile') !==
3400
+				false) {
3401
+				$pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3402
+			} // Helper plugin compile
3403
+			elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name) . 'Compile')
3404
+				!== false) {
3405
+				$pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3406
+			} // Smarty modifier
3407
+			elseif (function_exists('smarty_modifier_' . $name) !== false) {
3408
+				$pluginType = Core::SMARTY_MODIFIER;
3409
+			} // Smarty function
3410
+			elseif (function_exists('smarty_function_' . $name) !== false) {
3411
+				$pluginType = Core::SMARTY_FUNCTION;
3412
+			} // Smarty block
3413
+			elseif (function_exists('smarty_block_' . $name) !== false) {
3414
+				$pluginType = Core::SMARTY_BLOCK;
3415
+			} // Everything else
3416
+			else {
3417
+				if ($pluginType === - 1) {
3418
+					try {
3419
+						$this->getDwoo()->getLoader()->loadPlugin(
3420
+							'Plugin' . Core::toCamelCase($name));
3421
+					}
3422
+					catch (Exception $e) {
3423
+						if (isset($phpFunc)) {
3424
+							$pluginType = Core::NATIVE_PLUGIN;
3425
+						} elseif (is_object($this->getDwoo()->getPluginProxy()) && $this->getDwoo()->getPluginProxy()->handles($name)) {
3426
+							$pluginType = Core::PROXY_PLUGIN;
3427
+							break;
3428
+						} else {
3429
+							throw $e;
3430
+						}
3431
+					}
3432
+				} else {
3433
+					throw new Exception('Plugin "' . $name . '" could not be found, type:' . $pluginType);
3434
+				}
3435
+				++ $pluginType;
3436
+			}
3437
+		}
3438
+
3439
+		if (($pluginType & Core::COMPILABLE_PLUGIN) === 0 && ($pluginType & Core::NATIVE_PLUGIN) === 0 && ($pluginType & Core::PROXY_PLUGIN) === 0) {
3440
+			$this->addUsedPlugin(Core::toCamelCase($name), $pluginType);
3441
+		}
3442
+
3443
+		return $pluginType;
3444
+	}
3445
+
3446
+	/**
3447
+	 * Allows a plugin to load another one at compile time, this will also mark
3448
+	 * it as used by this template so it will be loaded at runtime (which can be
3449
+	 * useful for compiled plugins that rely on another plugin when their compiled
3450
+	 * code runs).
3451
+	 *
3452
+	 * @param string $name the plugin name
3453
+	 *
3454
+	 * @return void
3455
+	 */
3456
+	public function loadPlugin($name)
3457
+	{
3458
+		$this->getPluginType($name);
3459
+	}
3460
+
3461
+	/**
3462
+	 * Runs htmlentities over the matched <?php ?> blocks when the security policy enforces that.
3463
+	 *
3464
+	 * @param array $match matched php block
3465
+	 *
3466
+	 * @return string the htmlentities-converted string
3467
+	 */
3468
+	protected function phpTagEncodingHelper($match)
3469
+	{
3470
+		return htmlspecialchars($match[0]);
3471
+	}
3472
+
3473
+	/**
3474
+	 * Maps the parameters received from the template onto the parameters required by the given callback.
3475
+	 *
3476
+	 * @param array    $params   the array of parameters
3477
+	 * @param callback $callback the function or method to reflect on to find out the required parameters
3478
+	 * @param int      $callType the type of call in the template, 0 = no params, 1 = php-style call, 2 = named
3479
+	 *                           parameters call
3480
+	 * @param array    $map      the parameter map to use, if not provided it will be built from the callback
3481
+	 *
3482
+	 * @return array parameters sorted in the correct order with missing optional parameters filled
3483
+	 * @throws CompilationException
3484
+	 */
3485
+	protected function mapParams(array $params, $callback, $callType = 2, $map = null)
3486
+	{
3487
+		if (!$map) {
3488
+			$map = $this->getParamMap($callback);
3489
+		}
3490
+
3491
+		$paramlist = array();
3492
+
3493
+		// transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values))
3494
+		$ps = array();
3495
+		foreach ($params as $p) {
3496
+			if (is_array($p[1])) {
3497
+				$ps[$p[0]] = $p[1];
3498
+			} else {
3499
+				$ps[] = $p;
3500
+			}
3501
+		}
3502
+
3503
+		// loops over the param map and assigns values from the template or default value for unset optional params
3504
+		while (list($k, $v) = each($map)) {
3505
+			if ($v[0] === '*') {
3506
+				// "rest" array parameter, fill every remaining params in it and then break
3507
+				if (count($ps) === 0) {
3508
+					if ($v[1] === false) {
3509
+						throw new CompilationException(
3510
+							$this, 'Rest argument missing for ' . str_replace(
3511
+								array(
3512
+									Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3513
+								'Compile'
3514
+								), '', (is_array($callback) ? $callback[0] : $callback)
3515
+							)
3516
+						);
3517
+					} else {
3518
+						break;
3519
+					}
3520
+				}
3521
+				$tmp  = array();
3522
+				$tmp2 = array();
3523
+				$tmp3 = array();
3524
+				foreach ($ps as $i => $p) {
3525
+					$tmp[$i]  = $p[0];
3526
+					$tmp2[$i] = $p[1];
3527
+					$tmp3[$i] = isset($p[2]) ? $p[2] : 0;
3528
+					unset($ps[$i]);
3529
+				}
3530
+				$paramlist[$v[0]] = array($tmp, $tmp2, $tmp3);
3531
+				unset($tmp, $tmp2, $i, $p);
3532
+				break;
3533
+			} elseif (isset($ps[$v[0]])) {
3534
+				// parameter is defined as named param
3535
+				$paramlist[$v[0]] = $ps[$v[0]];
3536
+				unset($ps[$v[0]]);
3537
+			} elseif (isset($ps[$k])) {
3538
+				// parameter is defined as ordered param
3539
+				$paramlist[$v[0]] = $ps[$k];
3540
+				unset($ps[$k]);
3541
+			} elseif ($v[1] === false) {
3542
+				// parameter is not defined and not optional, throw error
3543
+				if (is_array($callback)) {
3544
+					if (is_object($callback[0])) {
3545
+						$name = get_class($callback[0]) . '::' . $callback[1];
3546
+					} else {
3547
+						$name = $callback[0];
3548
+					}
3549
+				} else {
3550
+					$name = $callback;
3551
+				}
3552
+
3553
+				throw new CompilationException(
3554
+					$this, 'Argument ' . $k . '/' . $v[0] . ' missing for ' . str_replace(
3555
+						array(
3556
+							Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3557
+						'Compile'
3558
+						), '', $name
3559
+					)
3560
+				);
3561
+			} elseif ($v[2] === null) {
3562
+				// enforce lowercased null if default value is null (php outputs NULL with var export)
3563
+				$paramlist[$v[0]] = array('null', null, self::T_NULL);
3564
+			} else {
3565
+				// outputs default value with var_export
3566
+				$paramlist[$v[0]] = array(var_export($v[2], true), $v[2]);
3567
+			}
3568
+		}
3569
+
3570
+		if (count($ps)) {
3571
+			foreach ($ps as $i => $p) {
3572
+				array_push($paramlist, $p);
3573
+			}
3574
+		}
3575
+
3576
+		return $paramlist;
3577
+	}
3578
+
3579
+	/**
3580
+	 * Returns the parameter map of the given callback, it filters out entries typed as Dwoo and Compiler and turns the
3581
+	 * rest parameter into a "*".
3582
+	 *
3583
+	 * @param callback $callback the function/method to reflect on
3584
+	 *
3585
+	 * @return array processed parameter map
3586
+	 */
3587
+	protected function getParamMap($callback)
3588
+	{
3589
+		if (is_null($callback)) {
3590
+			return array(array('*', true));
3591
+		}
3592
+		if (is_array($callback)) {
3593
+			$ref = new ReflectionMethod($callback[0], $callback[1]);
3594
+		} else {
3595
+			$ref = new ReflectionFunction($callback);
3596
+		}
3597
+
3598
+		$out = array();
3599
+		foreach ($ref->getParameters() as $param) {
3600
+			if (($class = $param->getClass()) !== null && $class->name === 'Dwoo\Core') {
3601
+				continue;
3602
+			}
3603
+			if (($class = $param->getClass()) !== null && $class->name === 'Dwoo\Compiler') {
3604
+				continue;
3605
+			}
3606
+			if ($param->getName() === 'rest' && $param->isArray() === true) {
3607
+				$out[] = array('*', $param->isOptional(), null);
3608
+				continue;
3609
+			}
3610
+			$out[] = array(
3611
+				$param->getName(),
3612
+				$param->isOptional(),
3613
+				$param->isOptional() ? $param->getDefaultValue() : null
3614
+			);
3615
+		}
3616
+
3617
+		return $out;
3618
+	}
3619
+
3620
+	/**
3621
+	 * Returns a default instance of this compiler, used by default by all Dwoo templates that do not have a
3622
+	 * specific compiler assigned and when you do not override the default compiler factory function.
3623
+	 *
3624
+	 * @see    Core::setDefaultCompilerFactory()
3625
+	 * @return Compiler
3626
+	 */
3627
+	public static function compilerFactory()
3628
+	{
3629
+		if (self::$instance === null) {
3630
+			self::$instance = new self();
3631
+		}
3632
+
3633
+		return self::$instance;
3634
+	}
3635 3635
 }
Please login to merge, or discard this patch.
lib/Dwoo/Loader.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -57,7 +57,7 @@
 block discarded – undo
57 57
     /**
58 58
      * Loader constructor.
59 59
      *
60
-     * @param $cacheDir
60
+     * @param string $cacheDir
61 61
      */
62 62
     public function __construct($cacheDir)
63 63
     {
Please login to merge, or discard this patch.
Indentation   +162 added lines, -162 removed lines patch added patch discarded remove patch
@@ -23,176 +23,176 @@
 block discarded – undo
23 23
  */
24 24
 class Loader implements ILoader
25 25
 {
26
-    /**
27
-     * Stores the plugin directories.
28
-     *
29
-     * @see addDirectory
30
-     * @var array
31
-     */
32
-    protected $paths = array();
26
+	/**
27
+	 * Stores the plugin directories.
28
+	 *
29
+	 * @see addDirectory
30
+	 * @var array
31
+	 */
32
+	protected $paths = array();
33 33
 
34
-    /**
35
-     * Stores the plugins names/paths relationships
36
-     * don't edit this on your own, use addDirectory.
37
-     *
38
-     * @see addDirectory
39
-     * @var array
40
-     */
41
-    protected $classPath = array();
34
+	/**
35
+	 * Stores the plugins names/paths relationships
36
+	 * don't edit this on your own, use addDirectory.
37
+	 *
38
+	 * @see addDirectory
39
+	 * @var array
40
+	 */
41
+	protected $classPath = array();
42 42
 
43
-    /**
44
-     * Path where class paths cache files are written.
45
-     *
46
-     * @var string
47
-     */
48
-    protected $cacheDir;
43
+	/**
44
+	 * Path where class paths cache files are written.
45
+	 *
46
+	 * @var string
47
+	 */
48
+	protected $cacheDir;
49 49
 
50
-    /**
51
-     * Path where builtin plugins are stored.
52
-     *
53
-     * @var string
54
-     */
55
-    protected $corePluginDir;
50
+	/**
51
+	 * Path where builtin plugins are stored.
52
+	 *
53
+	 * @var string
54
+	 */
55
+	protected $corePluginDir;
56 56
 
57
-    /**
58
-     * Loader constructor.
59
-     *
60
-     * @param $cacheDir
61
-     */
62
-    public function __construct($cacheDir)
63
-    {
64
-        $this->corePluginDir = __DIR__ . DIRECTORY_SEPARATOR . 'Plugins';
65
-        $this->cacheDir      = rtrim($cacheDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
57
+	/**
58
+	 * Loader constructor.
59
+	 *
60
+	 * @param $cacheDir
61
+	 */
62
+	public function __construct($cacheDir)
63
+	{
64
+		$this->corePluginDir = __DIR__ . DIRECTORY_SEPARATOR . 'Plugins';
65
+		$this->cacheDir      = rtrim($cacheDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
66 66
 
67
-        // include class paths or rebuild paths if the cache file isn't there
68
-        $cacheFile = $this->cacheDir . 'classpath.cache.d' . Core::RELEASE_TAG . '.php';
69
-        if (file_exists($cacheFile)) {
70
-            $classpath       = file_get_contents($cacheFile);
71
-            $this->classPath = unserialize($classpath) + $this->classPath;
72
-        } else {
73
-            $this->rebuildClassPathCache($this->corePluginDir, $cacheFile);
74
-        }
75
-    }
67
+		// include class paths or rebuild paths if the cache file isn't there
68
+		$cacheFile = $this->cacheDir . 'classpath.cache.d' . Core::RELEASE_TAG . '.php';
69
+		if (file_exists($cacheFile)) {
70
+			$classpath       = file_get_contents($cacheFile);
71
+			$this->classPath = unserialize($classpath) + $this->classPath;
72
+		} else {
73
+			$this->rebuildClassPathCache($this->corePluginDir, $cacheFile);
74
+		}
75
+	}
76 76
 
77
-    /**
78
-     * Rebuilds class paths, scans the given directory recursively and saves all paths in the given file.
79
-     *
80
-     * @param string $path      the plugin path to scan
81
-     * @param string $cacheFile the file where to store the plugin paths cache, it will be overwritten
82
-     *
83
-     * @throws Exception
84
-     */
85
-    protected function rebuildClassPathCache($path, $cacheFile)
86
-    {
87
-        if ($cacheFile !== false) {
88
-            $tmp             = $this->classPath;
89
-            $this->classPath = array();
90
-        }
77
+	/**
78
+	 * Rebuilds class paths, scans the given directory recursively and saves all paths in the given file.
79
+	 *
80
+	 * @param string $path      the plugin path to scan
81
+	 * @param string $cacheFile the file where to store the plugin paths cache, it will be overwritten
82
+	 *
83
+	 * @throws Exception
84
+	 */
85
+	protected function rebuildClassPathCache($path, $cacheFile)
86
+	{
87
+		if ($cacheFile !== false) {
88
+			$tmp             = $this->classPath;
89
+			$this->classPath = array();
90
+		}
91 91
 
92
-        // iterates over all files/folders
93
-        $list = glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*');
94
-        if (is_array($list)) {
95
-            foreach ($list as $f) {
96
-                if (is_dir($f)) {
97
-                    $this->rebuildClassPathCache($f, false);
98
-                } else {
99
-                    // TODO: is it still valid now?
100
-                    $this->classPath[str_replace(array(
101
-                        'function.',
102
-                        'block.',
103
-                        'modifier.',
104
-                        'outputfilter.',
105
-                        'filter.',
106
-                        'prefilter.',
107
-                        'postfilter.',
108
-                        'pre.',
109
-                        'post.',
110
-                        'output.',
111
-                        'shared.',
112
-                        'helper.'
113
-                    ), '', basename($f, '.php'))] = $f;
114
-                }
115
-            }
116
-        }
92
+		// iterates over all files/folders
93
+		$list = glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*');
94
+		if (is_array($list)) {
95
+			foreach ($list as $f) {
96
+				if (is_dir($f)) {
97
+					$this->rebuildClassPathCache($f, false);
98
+				} else {
99
+					// TODO: is it still valid now?
100
+					$this->classPath[str_replace(array(
101
+						'function.',
102
+						'block.',
103
+						'modifier.',
104
+						'outputfilter.',
105
+						'filter.',
106
+						'prefilter.',
107
+						'postfilter.',
108
+						'pre.',
109
+						'post.',
110
+						'output.',
111
+						'shared.',
112
+						'helper.'
113
+					), '', basename($f, '.php'))] = $f;
114
+				}
115
+			}
116
+		}
117 117
 
118
-        // save in file if it's the first call (not recursed)
119
-        if ($cacheFile !== false) {
120
-            if (!file_put_contents($cacheFile, serialize($this->classPath))) {
121
-                throw new Exception('Could not write into ' . $cacheFile .
122
-                    ', either because the folder is not there (create it) or because of the chmod configuration (please ensure this directory is writable by php), alternatively you can change the directory used with $dwoo->setCompileDir() or provide a custom loader object with $dwoo->setLoader()');
123
-            }
124
-            $this->classPath += $tmp;
125
-        }
126
-    }
118
+		// save in file if it's the first call (not recursed)
119
+		if ($cacheFile !== false) {
120
+			if (!file_put_contents($cacheFile, serialize($this->classPath))) {
121
+				throw new Exception('Could not write into ' . $cacheFile .
122
+					', either because the folder is not there (create it) or because of the chmod configuration (please ensure this directory is writable by php), alternatively you can change the directory used with $dwoo->setCompileDir() or provide a custom loader object with $dwoo->setLoader()');
123
+			}
124
+			$this->classPath += $tmp;
125
+		}
126
+	}
127 127
 
128
-    /**
129
-     * Loads a plugin file.
130
-     *
131
-     * @param string $class       the plugin name, without the `Plugin` prefix
132
-     * @param bool   $forceRehash if true, the class path caches will be rebuilt if the plugin is not found, in case it
133
-     *                            has just been added, defaults to true
134
-     *
135
-     * @throws Exception
136
-     */
137
-    public function loadPlugin($class, $forceRehash = true)
138
-    {
139
-        /**
140
-         * An unknown class was requested (maybe newly added) or the
141
-         * include failed so we rebuild the cache. include() will fail
142
-         * with an uncatchable error if the file doesn't exist, which
143
-         * usually means that the cache is stale and must be rebuilt,
144
-         * so we check for that before trying to include() the plugin.
145
-         */
146
-        if ((!isset($this->classPath[$class]) || !is_readable($this->classPath[$class])) || (!isset
147
-                ($this->classPath[$class . 'Compile']) || !is_readable($this->classPath[$class . 'Compile']))) {
148
-            if ($forceRehash) {
149
-                $this->rebuildClassPathCache($this->corePluginDir, $this->cacheDir . 'classpath.cache.d' .
150
-                    Core::RELEASE_TAG . '.php');
151
-                foreach ($this->paths as $path => $file) {
152
-                    $this->rebuildClassPathCache($path, $file);
153
-                }
154
-                if (isset($this->classPath[$class])) {
155
-                    include_once $this->classPath[$class];
156
-                } elseif (isset($this->classPath[$class . 'Compile'])) {
157
-                    include_once $this->classPath[$class . 'Compile'];
158
-                } else {
159
-                    throw new Exception('Plugin "' . $class .
160
-                        '" can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE);
161
-                }
162
-            } else {
163
-                throw new Exception('Plugin "' . $class .
164
-                    '" can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE);
165
-            }
166
-        }
167
-    }
128
+	/**
129
+	 * Loads a plugin file.
130
+	 *
131
+	 * @param string $class       the plugin name, without the `Plugin` prefix
132
+	 * @param bool   $forceRehash if true, the class path caches will be rebuilt if the plugin is not found, in case it
133
+	 *                            has just been added, defaults to true
134
+	 *
135
+	 * @throws Exception
136
+	 */
137
+	public function loadPlugin($class, $forceRehash = true)
138
+	{
139
+		/**
140
+		 * An unknown class was requested (maybe newly added) or the
141
+		 * include failed so we rebuild the cache. include() will fail
142
+		 * with an uncatchable error if the file doesn't exist, which
143
+		 * usually means that the cache is stale and must be rebuilt,
144
+		 * so we check for that before trying to include() the plugin.
145
+		 */
146
+		if ((!isset($this->classPath[$class]) || !is_readable($this->classPath[$class])) || (!isset
147
+				($this->classPath[$class . 'Compile']) || !is_readable($this->classPath[$class . 'Compile']))) {
148
+			if ($forceRehash) {
149
+				$this->rebuildClassPathCache($this->corePluginDir, $this->cacheDir . 'classpath.cache.d' .
150
+					Core::RELEASE_TAG . '.php');
151
+				foreach ($this->paths as $path => $file) {
152
+					$this->rebuildClassPathCache($path, $file);
153
+				}
154
+				if (isset($this->classPath[$class])) {
155
+					include_once $this->classPath[$class];
156
+				} elseif (isset($this->classPath[$class . 'Compile'])) {
157
+					include_once $this->classPath[$class . 'Compile'];
158
+				} else {
159
+					throw new Exception('Plugin "' . $class .
160
+						'" can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE);
161
+				}
162
+			} else {
163
+				throw new Exception('Plugin "' . $class .
164
+					'" can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE);
165
+			}
166
+		}
167
+	}
168 168
 
169
-    /**
170
-     * Adds a plugin directory, the plugins found in the new plugin directory
171
-     * will take precedence over the other directories (including the default
172
-     * dwoo plugin directory), you can use this for example to override plugins
173
-     * in a specific directory for a specific application while keeping all your
174
-     * usual plugins in the same place for all applications.
175
-     * TOCOM don't forget that php functions overrides are not rehashed so you
176
-     * need to clear the classpath caches by hand when adding those.
177
-     *
178
-     * @param string $pluginDirectory the plugin path to scan
179
-     *
180
-     * @throws Exception
181
-     */
182
-    public function addDirectory($pluginDirectory)
183
-    {
184
-        $pluginDir = realpath($pluginDirectory);
185
-        if (!$pluginDir) {
186
-            throw new Exception('Plugin directory does not exist or can not be read : ' . $pluginDirectory);
187
-        }
188
-        $cacheFile = $this->cacheDir . 'classpath-' . substr(strtr($pluginDir, '/\\:' . PATH_SEPARATOR, '----'),
189
-                strlen($pluginDir) > 80 ? - 80 : 0) . '.d' . Core::RELEASE_TAG . '.php';
190
-        $this->paths[$pluginDir] = $cacheFile;
191
-        if (file_exists($cacheFile)) {
192
-            $classpath       = file_get_contents($cacheFile);
193
-            $this->classPath = unserialize($classpath) + $this->classPath;
194
-        } else {
195
-            $this->rebuildClassPathCache($pluginDir, $cacheFile);
196
-        }
197
-    }
169
+	/**
170
+	 * Adds a plugin directory, the plugins found in the new plugin directory
171
+	 * will take precedence over the other directories (including the default
172
+	 * dwoo plugin directory), you can use this for example to override plugins
173
+	 * in a specific directory for a specific application while keeping all your
174
+	 * usual plugins in the same place for all applications.
175
+	 * TOCOM don't forget that php functions overrides are not rehashed so you
176
+	 * need to clear the classpath caches by hand when adding those.
177
+	 *
178
+	 * @param string $pluginDirectory the plugin path to scan
179
+	 *
180
+	 * @throws Exception
181
+	 */
182
+	public function addDirectory($pluginDirectory)
183
+	{
184
+		$pluginDir = realpath($pluginDirectory);
185
+		if (!$pluginDir) {
186
+			throw new Exception('Plugin directory does not exist or can not be read : ' . $pluginDirectory);
187
+		}
188
+		$cacheFile = $this->cacheDir . 'classpath-' . substr(strtr($pluginDir, '/\\:' . PATH_SEPARATOR, '----'),
189
+				strlen($pluginDir) > 80 ? - 80 : 0) . '.d' . Core::RELEASE_TAG . '.php';
190
+		$this->paths[$pluginDir] = $cacheFile;
191
+		if (file_exists($cacheFile)) {
192
+			$classpath       = file_get_contents($cacheFile);
193
+			$this->classPath = unserialize($classpath) + $this->classPath;
194
+		} else {
195
+			$this->rebuildClassPathCache($pluginDir, $cacheFile);
196
+		}
197
+	}
198 198
 }
Please login to merge, or discard this patch.
lib/Dwoo/Plugins/Blocks/PluginDynamic.php 2 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -85,8 +85,8 @@
 block discarded – undo
85 85
 
86 86
     /**
87 87
      * @param $output
88
-     * @param $dynamicId
89
-     * @param $compiledFile
88
+     * @param string $dynamicId
89
+     * @param string $compiledFile
90 90
      *
91 91
      * @return mixed|string
92 92
      */
Please login to merge, or discard this patch.
Indentation   +78 added lines, -78 removed lines patch added patch discarded remove patch
@@ -28,89 +28,89 @@
 block discarded – undo
28 28
  */
29 29
 class PluginDynamic extends BlockPlugin implements ICompilableBlock
30 30
 {
31
-    /**
32
-     *
33
-     */
34
-    public function init()
35
-    {
36
-    }
31
+	/**
32
+	 *
33
+	 */
34
+	public function init()
35
+	{
36
+	}
37 37
 
38
-    /**
39
-     * @param Compiler $compiler
40
-     * @param array    $params
41
-     * @param string   $prepend
42
-     * @param string   $append
43
-     * @param string   $type
44
-     *
45
-     * @return string
46
-     */
47
-    public static function preProcessing(Compiler $compiler, array $params, $prepend, $append, $type)
48
-    {
49
-        return '';
50
-    }
38
+	/**
39
+	 * @param Compiler $compiler
40
+	 * @param array    $params
41
+	 * @param string   $prepend
42
+	 * @param string   $append
43
+	 * @param string   $type
44
+	 *
45
+	 * @return string
46
+	 */
47
+	public static function preProcessing(Compiler $compiler, array $params, $prepend, $append, $type)
48
+	{
49
+		return '';
50
+	}
51 51
 
52
-    /**
53
-     * @param Compiler $compiler
54
-     * @param array    $params
55
-     * @param string   $prepend
56
-     * @param string   $append
57
-     * @param string   $content
58
-     *
59
-     * @return string
60
-     */
61
-    public static function postProcessing(Compiler $compiler, array $params, $prepend, $append, $content)
62
-    {
63
-        try {
64
-            $compiler->findBlock('dynamic');
52
+	/**
53
+	 * @param Compiler $compiler
54
+	 * @param array    $params
55
+	 * @param string   $prepend
56
+	 * @param string   $append
57
+	 * @param string   $content
58
+	 *
59
+	 * @return string
60
+	 */
61
+	public static function postProcessing(Compiler $compiler, array $params, $prepend, $append, $content)
62
+	{
63
+		try {
64
+			$compiler->findBlock('dynamic');
65 65
 
66
-            return $content;
67
-        }
68
-        catch (CompilationException $e) {
69
-        }
70
-        $output = Compiler::PHP_OPEN . 'if($doCache) {' . "\n\t" . 'echo \'<dwoo:dynamic_\'.$dynamicId.\'>' . str_replace('\'', '\\\'', $content) . '</dwoo:dynamic_\'.$dynamicId.\'>\';' . "\n} else {\n\t";
71
-        if (substr($content, 0, strlen(Compiler::PHP_OPEN)) == Compiler::PHP_OPEN) {
72
-            $output .= substr($content, strlen(Compiler::PHP_OPEN));
73
-        } else {
74
-            $output .= Compiler::PHP_CLOSE . $content;
75
-        }
76
-        if (substr($output, - strlen(Compiler::PHP_CLOSE)) == Compiler::PHP_CLOSE) {
77
-            $output = substr($output, 0, - strlen(Compiler::PHP_CLOSE));
78
-        } else {
79
-            $output .= Compiler::PHP_OPEN;
80
-        }
81
-        $output .= "\n}" . Compiler::PHP_CLOSE;
66
+			return $content;
67
+		}
68
+		catch (CompilationException $e) {
69
+		}
70
+		$output = Compiler::PHP_OPEN . 'if($doCache) {' . "\n\t" . 'echo \'<dwoo:dynamic_\'.$dynamicId.\'>' . str_replace('\'', '\\\'', $content) . '</dwoo:dynamic_\'.$dynamicId.\'>\';' . "\n} else {\n\t";
71
+		if (substr($content, 0, strlen(Compiler::PHP_OPEN)) == Compiler::PHP_OPEN) {
72
+			$output .= substr($content, strlen(Compiler::PHP_OPEN));
73
+		} else {
74
+			$output .= Compiler::PHP_CLOSE . $content;
75
+		}
76
+		if (substr($output, - strlen(Compiler::PHP_CLOSE)) == Compiler::PHP_CLOSE) {
77
+			$output = substr($output, 0, - strlen(Compiler::PHP_CLOSE));
78
+		} else {
79
+			$output .= Compiler::PHP_OPEN;
80
+		}
81
+		$output .= "\n}" . Compiler::PHP_CLOSE;
82 82
 
83
-        return $output;
84
-    }
83
+		return $output;
84
+	}
85 85
 
86
-    /**
87
-     * @param $output
88
-     * @param $dynamicId
89
-     * @param $compiledFile
90
-     *
91
-     * @return mixed|string
92
-     */
93
-    public static function unescape($output, $dynamicId, $compiledFile)
94
-    {
95
-        $output = preg_replace_callback('/<dwoo:dynamic_(' . $dynamicId . ')>(.+?)<\/dwoo:dynamic_' . $dynamicId . '>/s', array(
96
-            'self',
97
-            'unescapePhp'
98
-        ), $output, - 1, $count);
99
-        // re-add the includes on top of the file
100
-        if ($count && preg_match('#/\* template head \*/(.+?)/\* end template head \*/#s', file_get_contents($compiledFile), $m)) {
101
-            $output = '<?php ' . $m[1] . ' ?>' . $output;
102
-        }
86
+	/**
87
+	 * @param $output
88
+	 * @param $dynamicId
89
+	 * @param $compiledFile
90
+	 *
91
+	 * @return mixed|string
92
+	 */
93
+	public static function unescape($output, $dynamicId, $compiledFile)
94
+	{
95
+		$output = preg_replace_callback('/<dwoo:dynamic_(' . $dynamicId . ')>(.+?)<\/dwoo:dynamic_' . $dynamicId . '>/s', array(
96
+			'self',
97
+			'unescapePhp'
98
+		), $output, - 1, $count);
99
+		// re-add the includes on top of the file
100
+		if ($count && preg_match('#/\* template head \*/(.+?)/\* end template head \*/#s', file_get_contents($compiledFile), $m)) {
101
+			$output = '<?php ' . $m[1] . ' ?>' . $output;
102
+		}
103 103
 
104
-        return $output;
105
-    }
104
+		return $output;
105
+	}
106 106
 
107
-    /**
108
-     * @param $match
109
-     *
110
-     * @return mixed
111
-     */
112
-    public static function unescapePhp($match)
113
-    {
114
-        return preg_replace('{<\?php /\*' . $match[1] . '\*/ echo \'(.+?)\'; \?>}s', '$1', $match[2]);
115
-    }
107
+	/**
108
+	 * @param $match
109
+	 *
110
+	 * @return mixed
111
+	 */
112
+	public static function unescapePhp($match)
113
+	{
114
+		return preg_replace('{<\?php /\*' . $match[1] . '\*/ echo \'(.+?)\'; \?>}s', '$1', $match[2]);
115
+	}
116 116
 }
Please login to merge, or discard this patch.
lib/Dwoo/Plugins/Blocks/PluginStrip.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -59,7 +59,7 @@
 block discarded – undo
59 59
      * @param string   $append
60 60
      * @param string   $content
61 61
      *
62
-     * @return mixed|string
62
+     * @return string
63 63
      */
64 64
     public static function postProcessing(Compiler $compiler, array $params, $prepend, $append, $content)
65 65
     {
Please login to merge, or discard this patch.
Indentation   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -31,59 +31,59 @@
 block discarded – undo
31 31
  */
32 32
 class PluginStrip extends BlockPlugin implements ICompilableBlock
33 33
 {
34
-    /**
35
-     * @param string $mode
36
-     */
37
-    public function init($mode = 'default')
38
-    {
39
-    }
34
+	/**
35
+	 * @param string $mode
36
+	 */
37
+	public function init($mode = 'default')
38
+	{
39
+	}
40 40
 
41
-    /**
42
-     * @param Compiler $compiler
43
-     * @param array    $params
44
-     * @param string   $prepend
45
-     * @param string   $append
46
-     * @param string   $type
47
-     *
48
-     * @return string
49
-     */
50
-    public static function preProcessing(Compiler $compiler, array $params, $prepend, $append, $type)
51
-    {
52
-        return '';
53
-    }
41
+	/**
42
+	 * @param Compiler $compiler
43
+	 * @param array    $params
44
+	 * @param string   $prepend
45
+	 * @param string   $append
46
+	 * @param string   $type
47
+	 *
48
+	 * @return string
49
+	 */
50
+	public static function preProcessing(Compiler $compiler, array $params, $prepend, $append, $type)
51
+	{
52
+		return '';
53
+	}
54 54
 
55
-    /**
56
-     * @param Compiler $compiler
57
-     * @param array    $params
58
-     * @param string   $prepend
59
-     * @param string   $append
60
-     * @param string   $content
61
-     *
62
-     * @return mixed|string
63
-     */
64
-    public static function postProcessing(Compiler $compiler, array $params, $prepend, $append, $content)
65
-    {
66
-        $params = $compiler->getCompiledParams($params);
55
+	/**
56
+	 * @param Compiler $compiler
57
+	 * @param array    $params
58
+	 * @param string   $prepend
59
+	 * @param string   $append
60
+	 * @param string   $content
61
+	 *
62
+	 * @return mixed|string
63
+	 */
64
+	public static function postProcessing(Compiler $compiler, array $params, $prepend, $append, $content)
65
+	{
66
+		$params = $compiler->getCompiledParams($params);
67 67
 
68
-        $mode = trim($params['mode'], '"\'');
69
-        switch ($mode) {
70
-            case 'js':
71
-            case 'javascript':
72
-                $content = preg_replace('#(?<!:)//\s[^\r\n]*|/\*.*?\*/#s', '', $content);
68
+		$mode = trim($params['mode'], '"\'');
69
+		switch ($mode) {
70
+			case 'js':
71
+			case 'javascript':
72
+				$content = preg_replace('#(?<!:)//\s[^\r\n]*|/\*.*?\*/#s', '', $content);
73 73
 
74
-            case 'default':
75
-            default:
76
-        }
77
-        $content = preg_replace(array(
78
-            "/\n/",
79
-            "/\r/",
80
-            '/(<\?(?:php)?|<%)\s*/'
81
-        ), array(
82
-            '',
83
-            '',
84
-            '$1 '
85
-        ), preg_replace('#^\s*(.+?)\s*$#m', '$1', $content));
74
+			case 'default':
75
+			default:
76
+		}
77
+		$content = preg_replace(array(
78
+			"/\n/",
79
+			"/\r/",
80
+			'/(<\?(?:php)?|<%)\s*/'
81
+		), array(
82
+			'',
83
+			'',
84
+			'$1 '
85
+		), preg_replace('#^\s*(.+?)\s*$#m', '$1', $content));
86 86
 
87
-        return $content;
88
-    }
87
+		return $content;
88
+	}
89 89
 }
Please login to merge, or discard this patch.
lib/Dwoo/Plugins/Functions/PluginDump.php 2 patches
Doc Comments   +6 added lines patch added patch discarded remove patch
@@ -86,6 +86,9 @@  discard block
 block discarded – undo
86 86
         return $out;
87 87
     }
88 88
 
89
+    /**
90
+     * @param string $i
91
+     */
89 92
     protected function exportVar($i, $v)
90 93
     {
91 94
         if (is_string($v) || is_bool($v) || is_numeric($v)) {
@@ -99,6 +102,9 @@  discard block
 block discarded – undo
99 102
         }
100 103
     }
101 104
 
105
+    /**
106
+     * @param string $i
107
+     */
102 108
     protected function exportObj($i, $obj)
103 109
     {
104 110
         if (array_search($obj, $this->outputObjects, true) !== false) {
Please login to merge, or discard this patch.
Indentation   +145 added lines, -145 removed lines patch added patch discarded remove patch
@@ -29,156 +29,156 @@
 block discarded – undo
29 29
  */
30 30
 class PluginDump extends Plugin
31 31
 {
32
-    protected $outputObjects;
33
-    protected $outputMethods;
34
-
35
-    public function process($var = '$', $show_methods = false)
36
-    {
37
-        $this->outputMethods = $show_methods;
38
-        if ($var === '$') {
39
-            $var = $this->core->getData();
40
-            $out = '<div style="background:#aaa; padding:5px; margin:5px; color:#000;">data';
41
-        } else {
42
-            $out = '<div style="background:#aaa; padding:5px; margin:5px; color:#000;">dump';
43
-        }
44
-
45
-        $this->outputObjects = array();
46
-
47
-        if (!is_array($var)) {
48
-            if (is_object($var)) {
49
-                return $this->exportObj('', $var);
50
-            } else {
51
-                return $this->exportVar('', $var);
52
-            }
53
-        }
54
-
55
-        $scope = $this->core->getScope();
56
-
57
-        if ($var === $scope) {
58
-            $out .= ' (current scope): <div style="background:#ccc;">';
59
-        } else {
60
-            $out .= ':<div style="padding-left:20px;">';
61
-        }
62
-
63
-        $out .= $this->export($var, $scope);
64
-
65
-        return $out . '</div></div>';
66
-    }
67
-
68
-    protected function export($var, $scope)
69
-    {
70
-        $out = '';
71
-        foreach ($var as $i => $v) {
72
-            if (is_array($v) || (is_object($v) && $v instanceof Iterator)) {
73
-                $out .= $i . ' (' . (is_array($v) ? 'array' : 'object: ' . get_class($v)) . ')';
74
-                if ($v === $scope) {
75
-                    $out .= ' (current scope):<div style="background:#ccc;padding-left:20px;">' . $this->export($v, $scope) . '</div>';
76
-                } else {
77
-                    $out .= ':<div style="padding-left:20px;">' . $this->export($v, $scope) . '</div>';
78
-                }
79
-            } elseif (is_object($v)) {
80
-                $out .= $this->exportObj($i . ' (object: ' . get_class($v) . '):', $v);
81
-            } else {
82
-                $out .= $this->exportVar($i . ' = ', $v);
83
-            }
84
-        }
85
-
86
-        return $out;
87
-    }
88
-
89
-    protected function exportVar($i, $v)
90
-    {
91
-        if (is_string($v) || is_bool($v) || is_numeric($v)) {
92
-            return $i . htmlentities(var_export($v, true)) . '<br />';
93
-        } elseif (is_null($v)) {
94
-            return $i . 'null<br />';
95
-        } elseif (is_resource($v)) {
96
-            return $i . 'resource(' . get_resource_type($v) . ')<br />';
97
-        } else {
98
-            return $i . htmlentities(var_export($v, true)) . '<br />';
99
-        }
100
-    }
101
-
102
-    protected function exportObj($i, $obj)
103
-    {
104
-        if (array_search($obj, $this->outputObjects, true) !== false) {
105
-            return $i . ' [recursion, skipped]<br />';
106
-        }
107
-
108
-        $this->outputObjects[] = $obj;
109
-
110
-        $list = (array)$obj;
111
-
112
-        $protectedLength = strlen(get_class($obj)) + 2;
113
-
114
-        $out = array();
115
-
116
-        if ($this->outputMethods) {
117
-            $ref = new ReflectionObject($obj);
118
-
119
-            foreach ($ref->getMethods() as $method) {
120
-                if (!$method->isPublic()) {
121
-                    continue;
122
-                }
123
-
124
-                if (empty($out['method'])) {
125
-                    $out['method'] = '';
126
-                }
127
-
128
-                $params = array();
129
-                foreach ($method->getParameters() as $param) {
130
-                    $params[] = ($param->isPassedByReference() ? '&' : '') . '$' . $param->getName() . ($param->isOptional() ? ' = ' . var_export($param->getDefaultValue(), true) : '');
131
-                }
132
-
133
-                $out['method'] .= '(method) ' . $method->getName() . '(' . implode(', ', $params) . ')<br />';
134
-            }
135
-        }
136
-
137
-        foreach ($list as $attributeName => $attributeValue) {
138
-            if (property_exists($obj, $attributeName)) {
139
-                $key = 'public';
140
-            } elseif (substr($attributeName, 0, 3) === "\0*\0") {
141
-                $key           = 'protected';
142
-                $attributeName = substr($attributeName, 3);
143
-            } else {
144
-                $key           = 'private';
145
-                $attributeName = substr($attributeName, $protectedLength);
146
-            }
147
-
148
-            if (empty($out[$key])) {
149
-                $out[$key] = '';
150
-            }
151
-
152
-            $out[$key] .= '(' . $key . ') ';
153
-
154
-            if (is_array($attributeValue)) {
155
-                $out[$key] .= $attributeName . ' (array):<br />
32
+	protected $outputObjects;
33
+	protected $outputMethods;
34
+
35
+	public function process($var = '$', $show_methods = false)
36
+	{
37
+		$this->outputMethods = $show_methods;
38
+		if ($var === '$') {
39
+			$var = $this->core->getData();
40
+			$out = '<div style="background:#aaa; padding:5px; margin:5px; color:#000;">data';
41
+		} else {
42
+			$out = '<div style="background:#aaa; padding:5px; margin:5px; color:#000;">dump';
43
+		}
44
+
45
+		$this->outputObjects = array();
46
+
47
+		if (!is_array($var)) {
48
+			if (is_object($var)) {
49
+				return $this->exportObj('', $var);
50
+			} else {
51
+				return $this->exportVar('', $var);
52
+			}
53
+		}
54
+
55
+		$scope = $this->core->getScope();
56
+
57
+		if ($var === $scope) {
58
+			$out .= ' (current scope): <div style="background:#ccc;">';
59
+		} else {
60
+			$out .= ':<div style="padding-left:20px;">';
61
+		}
62
+
63
+		$out .= $this->export($var, $scope);
64
+
65
+		return $out . '</div></div>';
66
+	}
67
+
68
+	protected function export($var, $scope)
69
+	{
70
+		$out = '';
71
+		foreach ($var as $i => $v) {
72
+			if (is_array($v) || (is_object($v) && $v instanceof Iterator)) {
73
+				$out .= $i . ' (' . (is_array($v) ? 'array' : 'object: ' . get_class($v)) . ')';
74
+				if ($v === $scope) {
75
+					$out .= ' (current scope):<div style="background:#ccc;padding-left:20px;">' . $this->export($v, $scope) . '</div>';
76
+				} else {
77
+					$out .= ':<div style="padding-left:20px;">' . $this->export($v, $scope) . '</div>';
78
+				}
79
+			} elseif (is_object($v)) {
80
+				$out .= $this->exportObj($i . ' (object: ' . get_class($v) . '):', $v);
81
+			} else {
82
+				$out .= $this->exportVar($i . ' = ', $v);
83
+			}
84
+		}
85
+
86
+		return $out;
87
+	}
88
+
89
+	protected function exportVar($i, $v)
90
+	{
91
+		if (is_string($v) || is_bool($v) || is_numeric($v)) {
92
+			return $i . htmlentities(var_export($v, true)) . '<br />';
93
+		} elseif (is_null($v)) {
94
+			return $i . 'null<br />';
95
+		} elseif (is_resource($v)) {
96
+			return $i . 'resource(' . get_resource_type($v) . ')<br />';
97
+		} else {
98
+			return $i . htmlentities(var_export($v, true)) . '<br />';
99
+		}
100
+	}
101
+
102
+	protected function exportObj($i, $obj)
103
+	{
104
+		if (array_search($obj, $this->outputObjects, true) !== false) {
105
+			return $i . ' [recursion, skipped]<br />';
106
+		}
107
+
108
+		$this->outputObjects[] = $obj;
109
+
110
+		$list = (array)$obj;
111
+
112
+		$protectedLength = strlen(get_class($obj)) + 2;
113
+
114
+		$out = array();
115
+
116
+		if ($this->outputMethods) {
117
+			$ref = new ReflectionObject($obj);
118
+
119
+			foreach ($ref->getMethods() as $method) {
120
+				if (!$method->isPublic()) {
121
+					continue;
122
+				}
123
+
124
+				if (empty($out['method'])) {
125
+					$out['method'] = '';
126
+				}
127
+
128
+				$params = array();
129
+				foreach ($method->getParameters() as $param) {
130
+					$params[] = ($param->isPassedByReference() ? '&' : '') . '$' . $param->getName() . ($param->isOptional() ? ' = ' . var_export($param->getDefaultValue(), true) : '');
131
+				}
132
+
133
+				$out['method'] .= '(method) ' . $method->getName() . '(' . implode(', ', $params) . ')<br />';
134
+			}
135
+		}
136
+
137
+		foreach ($list as $attributeName => $attributeValue) {
138
+			if (property_exists($obj, $attributeName)) {
139
+				$key = 'public';
140
+			} elseif (substr($attributeName, 0, 3) === "\0*\0") {
141
+				$key           = 'protected';
142
+				$attributeName = substr($attributeName, 3);
143
+			} else {
144
+				$key           = 'private';
145
+				$attributeName = substr($attributeName, $protectedLength);
146
+			}
147
+
148
+			if (empty($out[$key])) {
149
+				$out[$key] = '';
150
+			}
151
+
152
+			$out[$key] .= '(' . $key . ') ';
153
+
154
+			if (is_array($attributeValue)) {
155
+				$out[$key] .= $attributeName . ' (array):<br />
156 156
 							<div style="padding-left:20px;">' . $this->export($attributeValue, false) . '</div>';
157
-            } elseif (is_object($attributeValue)) {
158
-                $out[$key] .= $this->exportObj($attributeName . ' (object: ' . get_class($attributeValue) . '):', $attributeValue);
159
-            } else {
160
-                $out[$key] .= $this->exportVar($attributeName . ' = ', $attributeValue);
161
-            }
162
-        }
157
+			} elseif (is_object($attributeValue)) {
158
+				$out[$key] .= $this->exportObj($attributeName . ' (object: ' . get_class($attributeValue) . '):', $attributeValue);
159
+			} else {
160
+				$out[$key] .= $this->exportVar($attributeName . ' = ', $attributeValue);
161
+			}
162
+		}
163 163
 
164
-        $return = $i . '<br /><div style="padding-left:20px;">';
164
+		$return = $i . '<br /><div style="padding-left:20px;">';
165 165
 
166
-        if (!empty($out['method'])) {
167
-            $return .= $out['method'];
168
-        }
166
+		if (!empty($out['method'])) {
167
+			$return .= $out['method'];
168
+		}
169 169
 
170
-        if (!empty($out['public'])) {
171
-            $return .= $out['public'];
172
-        }
170
+		if (!empty($out['public'])) {
171
+			$return .= $out['public'];
172
+		}
173 173
 
174
-        if (!empty($out['protected'])) {
175
-            $return .= $out['protected'];
176
-        }
174
+		if (!empty($out['protected'])) {
175
+			$return .= $out['protected'];
176
+		}
177 177
 
178
-        if (!empty($out['private'])) {
179
-            $return .= $out['private'];
180
-        }
178
+		if (!empty($out['private'])) {
179
+			$return .= $out['private'];
180
+		}
181 181
 
182
-        return $return . '</div>';
183
-    }
182
+		return $return . '</div>';
183
+	}
184 184
 }
Please login to merge, or discard this patch.
lib/Dwoo/Plugins/Processors/PluginSmartyCompatible.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -29,7 +29,7 @@
 block discarded – undo
29 29
     /**
30 30
      * @param string $input
31 31
      *
32
-     * @return mixed
32
+     * @return string
33 33
      */
34 34
     public function process($input)
35 35
     {
Please login to merge, or discard this patch.
Indentation   +58 added lines, -58 removed lines patch added patch discarded remove patch
@@ -26,69 +26,69 @@
 block discarded – undo
26 26
  */
27 27
 class PluginSmartyCompatible extends Processor
28 28
 {
29
-    /**
30
-     * @param string $input
31
-     *
32
-     * @return mixed
33
-     */
34
-    public function process($input)
35
-    {
36
-        list($l, $r) = $this->compiler->getDelimiters();
29
+	/**
30
+	 * @param string $input
31
+	 *
32
+	 * @return mixed
33
+	 */
34
+	public function process($input)
35
+	{
36
+		list($l, $r) = $this->compiler->getDelimiters();
37 37
 
38
-        $rl           = preg_quote($l, '/');
39
-        $rr           = preg_quote($r, '/');
40
-        $sectionParam = '(?:(name|loop|start|step|max|show)\s*=\s*(\S+))?\s*';
41
-        $input        = preg_replace_callback('/' . $rl . '\s*section ' . str_repeat($sectionParam, 6) . '\s*' . $rr . '(.+?)(?:' . $rl . '\s*sectionelse\s*' . $rr . '(.+?))?' . $rl . '\s*\/section\s*' . $rr . '/is', array(
42
-            $this,
43
-            'convertSection'
44
-        ), $input);
45
-        $input        = str_replace('$smarty.section.', '$smarty.for.', $input);
38
+		$rl           = preg_quote($l, '/');
39
+		$rr           = preg_quote($r, '/');
40
+		$sectionParam = '(?:(name|loop|start|step|max|show)\s*=\s*(\S+))?\s*';
41
+		$input        = preg_replace_callback('/' . $rl . '\s*section ' . str_repeat($sectionParam, 6) . '\s*' . $rr . '(.+?)(?:' . $rl . '\s*sectionelse\s*' . $rr . '(.+?))?' . $rl . '\s*\/section\s*' . $rr . '/is', array(
42
+			$this,
43
+			'convertSection'
44
+		), $input);
45
+		$input        = str_replace('$smarty.section.', '$smarty.for.', $input);
46 46
 
47
-        $smarty = array(
48
-            '/' . $rl . '\s*ldelim\s*' . $rr . '/',
49
-            '/' . $rl . '\s*rdelim\s*' . $rr . '/',
50
-            '/' . $rl . '\s*\$smarty\.ldelim\s*' . $rr . '/',
51
-            '/' . $rl . '\s*\$smarty\.rdelim\s*' . $rr . '/',
52
-            '/\$smarty\./',
53
-            '/' . $rl . '\s*php\s*' . $rr . '/',
54
-            '/' . $rl . '\s*\/php\s*' . $rr . '/',
55
-            '/\|(@?)strip(\||' . $rr . ')/',
56
-            '/' . $rl . '\s*sectionelse\s*' . $rr . '/',
57
-        );
47
+		$smarty = array(
48
+			'/' . $rl . '\s*ldelim\s*' . $rr . '/',
49
+			'/' . $rl . '\s*rdelim\s*' . $rr . '/',
50
+			'/' . $rl . '\s*\$smarty\.ldelim\s*' . $rr . '/',
51
+			'/' . $rl . '\s*\$smarty\.rdelim\s*' . $rr . '/',
52
+			'/\$smarty\./',
53
+			'/' . $rl . '\s*php\s*' . $rr . '/',
54
+			'/' . $rl . '\s*\/php\s*' . $rr . '/',
55
+			'/\|(@?)strip(\||' . $rr . ')/',
56
+			'/' . $rl . '\s*sectionelse\s*' . $rr . '/',
57
+		);
58 58
 
59
-        $dwoo = array(
60
-            '\\' . $l,
61
-            $r,
62
-            '\\' . $l,
63
-            $r,
64
-            '$dwoo.',
65
-            '<?php ',
66
-            ' ?>',
67
-            '|$1whitespace$2',
68
-            $l . 'else' . $r,
69
-        );
59
+		$dwoo = array(
60
+			'\\' . $l,
61
+			$r,
62
+			'\\' . $l,
63
+			$r,
64
+			'$dwoo.',
65
+			'<?php ',
66
+			' ?>',
67
+			'|$1whitespace$2',
68
+			$l . 'else' . $r,
69
+		);
70 70
 
71
-        if (preg_match('{\|@([a-z][a-z0-9_]*)}i', $input, $matches)) {
72
-            trigger_error('The Smarty Compatibility Module has detected that you use |@' . $matches[1] . ' in your template, this might lead to problems as Dwoo interprets the @ operator differently than Smarty, see http://wiki.dwoo.org/index.php/Syntax#The_.40_Operator', E_USER_NOTICE);
73
-        }
71
+		if (preg_match('{\|@([a-z][a-z0-9_]*)}i', $input, $matches)) {
72
+			trigger_error('The Smarty Compatibility Module has detected that you use |@' . $matches[1] . ' in your template, this might lead to problems as Dwoo interprets the @ operator differently than Smarty, see http://wiki.dwoo.org/index.php/Syntax#The_.40_Operator', E_USER_NOTICE);
73
+		}
74 74
 
75
-        return preg_replace($smarty, $dwoo, $input);
76
-    }
75
+		return preg_replace($smarty, $dwoo, $input);
76
+	}
77 77
 
78
-    /**
79
-     * @param array $matches
80
-     *
81
-     * @return mixed
82
-     */
83
-    protected function convertSection(array $matches)
84
-    {
85
-        $params = array();
86
-        $index  = 1;
87
-        while (!empty($matches[$index]) && $index < 13) {
88
-            $params[$matches[$index]] = $matches[$index + 1];
89
-            $index += 2;
90
-        }
78
+	/**
79
+	 * @param array $matches
80
+	 *
81
+	 * @return mixed
82
+	 */
83
+	protected function convertSection(array $matches)
84
+	{
85
+		$params = array();
86
+		$index  = 1;
87
+		while (!empty($matches[$index]) && $index < 13) {
88
+			$params[$matches[$index]] = $matches[$index + 1];
89
+			$index += 2;
90
+		}
91 91
 
92
-        return str_replace('[' . trim($params['name'], '"\'') . ']', '[$' . trim($params['name'], '"\'') . ']', $matches[0]);
93
-    }
92
+		return str_replace('[' . trim($params['name'], '"\'') . ']', '[$' . trim($params['name'], '"\'') . ']', $matches[0]);
93
+	}
94 94
 }
Please login to merge, or discard this patch.
lib/Dwoo/Smarty/Adapter.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -312,7 +312,7 @@
 block discarded – undo
312 312
 
313 313
     /**
314 314
      * @param mixed $_tpl
315
-     * @param array $data
315
+     * @param Data $data
316 316
      * @param null  $_compiler
317 317
      * @param bool  $_output
318 318
      *
Please login to merge, or discard this patch.
Indentation   +657 added lines, -657 removed lines patch added patch discarded remove patch
@@ -26,14 +26,14 @@  discard block
 block discarded – undo
26 26
 use Dwoo\Smarty\Processor\Adapter as ProcessorAdapter;
27 27
 
28 28
 if (!defined('DIR_SEP')) {
29
-    define('DIR_SEP', DIRECTORY_SEPARATOR);
29
+	define('DIR_SEP', DIRECTORY_SEPARATOR);
30 30
 }
31 31
 
32 32
 if (!defined('SMARTY_PHP_PASSTHRU')) {
33
-    define('SMARTY_PHP_PASSTHRU', 0);
34
-    define('SMARTY_PHP_QUOTE', 1);
35
-    define('SMARTY_PHP_REMOVE', 2);
36
-    define('SMARTY_PHP_ALLOW', 3);
33
+	define('SMARTY_PHP_PASSTHRU', 0);
34
+	define('SMARTY_PHP_QUOTE', 1);
35
+	define('SMARTY_PHP_REMOVE', 2);
36
+	define('SMARTY_PHP_ALLOW', 3);
37 37
 }
38 38
 
39 39
 /**
@@ -43,656 +43,656 @@  discard block
 block discarded – undo
43 43
  */
44 44
 class Adapter extends Core
45 45
 {
46
-    /**
47
-     * Magic get/set/call functions that handle unsupported features
48
-     *
49
-     * @param string $p
50
-     * @param string $v
51
-     */
52
-    public function __set($p, $v)
53
-    {
54
-        if ($p === 'scope') {
55
-            $this->scope = $v;
56
-
57
-            return;
58
-        }
59
-        if ($p === 'data') {
60
-            $this->data = $v;
61
-
62
-            return;
63
-        }
64
-        if (array_key_exists($p, $this->compat['properties']) !== false) {
65
-            if ($this->show_compat_errors) {
66
-                $this->triggerError('Property ' . $p . ' is not available in the Dwoo\Smarty\Adapter, however it might be implemented in the future, check out http://wiki.dwoo.org/index.php/SmartySupport for more details.', E_USER_NOTICE);
67
-            }
68
-            $this->compat['properties'][$p] = $v;
69
-        } else {
70
-            if ($this->show_compat_errors) {
71
-                $this->triggerError('Property ' . $p . ' is not available in the Dwoo\Smarty\Adapter, but it is not listed as such, so you might want to tell me about it at [email protected]', E_USER_NOTICE);
72
-            }
73
-        }
74
-    }
75
-
76
-    /**
77
-     * @param $p
78
-     *
79
-     * @return mixed
80
-     */
81
-    public function __get($p)
82
-    {
83
-        if (array_key_exists($p, $this->compat['properties']) !== false) {
84
-            if ($this->show_compat_errors) {
85
-                $this->triggerError('Property ' . $p . ' is not available in the Dwoo\Smarty\Adapter, however it might be implemented in the future, check out http://wiki.dwoo.org/index.php/SmartySupport for more details.', E_USER_NOTICE);
86
-            }
87
-
88
-            return $this->compat['properties'][$p];
89
-        } else {
90
-            if ($this->show_compat_errors) {
91
-                $this->triggerError('Property ' . $p . ' is not available in the Dwoo\Smarty\Adapter, but it is not listed as such, so you might want to tell me about it at [email protected]', E_USER_NOTICE);
92
-            }
93
-        }
94
-    }
95
-
96
-    /**
97
-     * @param string $m
98
-     * @param array  $a
99
-     *
100
-     * @return mixed|void
101
-     */
102
-    public function __call($m, $a)
103
-    {
104
-        if (method_exists($this->dataProvider, $m)) {
105
-            call_user_func_array(
106
-                array(
107
-                $this->dataProvider,
108
-                $m
109
-                ), $a
110
-            );
111
-        } elseif ($this->show_compat_errors) {
112
-            if (array_search($m, $this->compat['methods']) !== false) {
113
-                $this->triggerError('Method ' . $m . ' is not available in the Dwoo\Smarty\Adapter, however it might be implemented in the future, check out http://wiki.dwoo.org/index.php/SmartySupport for more details.', E_USER_NOTICE);
114
-            } else {
115
-                $this->triggerError('Method ' . $m . ' is not available in the Dwoo\Smarty\Adapter, but it is not listed as such, so you might want to tell me about it at [email protected]', E_USER_NOTICE);
116
-            }
117
-        }
118
-    }
119
-
120
-    /**
121
-     * List of unsupported properties and methods
122
-     */
123
-    protected $compat = array(
124
-        'methods'    => array(
125
-            'register_resource',
126
-            'unregister_resource',
127
-            'load_filter',
128
-            'clear_compiled_tpl',
129
-            'clear_config',
130
-            'get_config_vars',
131
-            'config_load',
132
-        ),
133
-        'properties' => array(
134
-            'cache_handler_func'            => null,
135
-            'debugging'                     => false,
136
-            'error_reporting'               => null,
137
-            'debugging_ctrl'                => 'NONE',
138
-            'request_vars_order'            => 'EGPCS',
139
-            'request_use_auto_globals'      => true,
140
-            'use_sub_dirs'                  => false,
141
-            'autoload_filters'              => array(),
142
-            'default_template_handler_func' => '',
143
-            'debug_tpl'                     => '',
144
-            'cache_modified_check'          => false,
145
-            'default_modifiers'             => array(),
146
-            'default_resource_type'         => 'file',
147
-            'config_overwrite'              => true,
148
-            'config_booleanize'             => true,
149
-            'config_read_hidden'            => false,
150
-            'config_fix_newlines'           => true,
151
-            'config_class'                  => 'Config_File',
152
-        ),
153
-    );
154
-
155
-    /**
156
-     * Security vars
157
-     */
158
-    public $security          = false;
159
-    public $trusted_dir       = array();
160
-    public $secure_dir        = array();
161
-    public $php_handling      = SMARTY_PHP_PASSTHRU;
162
-    public $security_settings = array(
163
-        'PHP_HANDLING'    => false,
164
-        'IF_FUNCS'        => array(
165
-            'list',
166
-            'empty',
167
-            'count',
168
-            'sizeof',
169
-            'in_array',
170
-            'is_array',
171
-        ),
172
-        'INCLUDE_ANY'     => false,
173
-        'PHP_TAGS'        => false,
174
-        'MODIFIER_FUNCS'  => array(),
175
-        'ALLOW_CONSTANTS' => false,
176
-    );
177
-
178
-    /**
179
-     * Paths
180
-     */
181
-    public $template_dir = 'templates';
182
-    public $compile_dir  = 'templates_c';
183
-    public $config_dir   = 'configs';
184
-    public $cache_dir    = 'cache';
185
-    public $plugins_dir  = array();
186
-
187
-    /**
188
-     * Misc options
189
-     */
190
-    public $left_delimiter  = '{';
191
-    public $right_delimiter = '}';
192
-    public $compile_check   = true;
193
-    public $force_compile   = false;
194
-    public $caching         = 0;
195
-    public $cache_lifetime  = 3600;
196
-    public $compile_id      = null;
197
-    public $compiler_file   = null;
198
-    public $compiler_class  = null;
199
-
200
-    /**
201
-     * Dwoo/Smarty compat layer
202
-     */
203
-    public           $show_compat_errors = false;
204
-    protected        $dataProvider;
205
-    protected        $_filters           = array(
206
-        'pre'    => array(),
207
-        'post'   => array(),
208
-        'output' => array()
209
-    );
210
-    protected static $tplCache           = array();
211
-    protected        $compiler           = null;
212
-
213
-    /**
214
-     * Adapter constructor.
215
-     */
216
-    public function __construct()
217
-    {
218
-        parent::__construct();
219
-        $this->charset      = 'iso-8859-1';
220
-        $this->dataProvider = new Data();
221
-        $this->compiler     = new Compiler();
222
-    }
223
-
224
-    /**
225
-     * @param      $filename
226
-     * @param null $cacheId
227
-     * @param null $compileId
228
-     */
229
-    public function display($filename, $cacheId = null, $compileId = null)
230
-    {
231
-        $this->fetch($filename, $cacheId, $compileId, true);
232
-    }
233
-
234
-    /**
235
-     * @param      $filename
236
-     * @param null $cacheId
237
-     * @param null $compileId
238
-     * @param bool $display
239
-     *
240
-     * @return string|void
241
-     */
242
-    public function fetch($filename, $cacheId = null, $compileId = null, $display = false)
243
-    {
244
-        $this->setCacheDir($this->cache_dir);
245
-        $this->setCompileDir($this->compile_dir);
246
-
247
-        if ($this->security) {
248
-            $policy = new SecurityPolicy();
249
-            $policy->addPhpFunction(array_merge($this->security_settings['IF_FUNCS'], $this->security_settings['MODIFIER_FUNCS']));
250
-
251
-            $phpTags = $this->security_settings['PHP_HANDLING'] ? SMARTY_PHP_ALLOW : $this->php_handling;
252
-            if ($this->security_settings['PHP_TAGS']) {
253
-                $phpTags = SMARTY_PHP_ALLOW;
254
-            }
255
-            switch ($phpTags) {
256
-            case SMARTY_PHP_ALLOW:
257
-            case SMARTY_PHP_PASSTHRU:
258
-                $phpTags = SecurityPolicy::PHP_ALLOW;
259
-                break;
260
-            case SMARTY_PHP_QUOTE:
261
-                $phpTags = SecurityPolicy::PHP_ENCODE;
262
-                break;
263
-            case SMARTY_PHP_REMOVE:
264
-            default:
265
-                $phpTags = SecurityPolicy::PHP_REMOVE;
266
-                break;
267
-            }
268
-            $policy->setPhpHandling($phpTags);
269
-
270
-            $policy->setConstantHandling($this->security_settings['ALLOW_CONSTANTS']);
271
-
272
-            if ($this->security_settings['INCLUDE_ANY']) {
273
-                $policy->allowDirectory(preg_replace('{^((?:[a-z]:)?[\\\\/]).*}i', '$1', __FILE__));
274
-            } else {
275
-                $policy->allowDirectory($this->secure_dir);
276
-            }
277
-
278
-            $this->setSecurityPolicy($policy);
279
-        }
280
-
281
-        if (!empty($this->plugins_dir)) {
282
-            foreach ($this->plugins_dir as $dir) {
283
-                $this->getLoader()->addDirectory(rtrim($dir, '\\/'));
284
-            }
285
-        }
286
-
287
-        $tpl = $this->makeTemplate($filename, $cacheId, $compileId);
288
-        if ($this->force_compile) {
289
-            $tpl->forceCompilation();
290
-        }
291
-
292
-        if ($this->caching > 0) {
293
-            $this->cacheTime = $this->cache_lifetime;
294
-        } else {
295
-            $this->cacheTime = 0;
296
-        }
297
-
298
-        if ($this->compiler_class !== null) {
299
-            if ($this->compiler_file !== null && !class_exists($this->compiler_class)) {
300
-                include $this->compiler_file;
301
-            }
302
-            $this->compiler = new $this->compiler_class();
303
-        } else {
304
-            $this->compiler->addPreProcessor('PluginSmartyCompatible', true);
305
-            $this->compiler->setLooseOpeningHandling(true);
306
-        }
307
-
308
-        $this->compiler->setDelimiters($this->left_delimiter, $this->right_delimiter);
309
-
310
-        return $this->get($tpl, $this->dataProvider, $this->compiler, $display === true);
311
-    }
312
-
313
-    /**
314
-     * @param mixed $_tpl
315
-     * @param array $data
316
-     * @param null  $_compiler
317
-     * @param bool  $_output
318
-     *
319
-     * @return string|void
320
-     */
321
-    public function get($_tpl, $data = array(), $_compiler = null, $_output = false)
322
-    {
323
-        if ($_compiler === null) {
324
-            $_compiler = $this->compiler;
325
-        }
326
-
327
-        return parent::get($_tpl, $data, $_compiler, $_output);
328
-    }
329
-
330
-    /**
331
-     * @param      $name
332
-     * @param      $callback
333
-     * @param bool $cacheable
334
-     * @param null $cache_attrs
335
-     *
336
-     * @throws Exception
337
-     */
338
-    public function register_function($name, $callback, $cacheable = true, $cache_attrs = null)
339
-    {
340
-        if (isset($this->plugins[$name]) && $this->plugins[$name][0] !== self::SMARTY_FUNCTION) {
341
-            throw new Exception('Multiple plugins of different types can not share the same name');
342
-        }
343
-        $this->plugins[$name] = array(
344
-            'type'     => self::SMARTY_FUNCTION,
345
-            'callback' => $callback
346
-        );
347
-    }
348
-
349
-    /**
350
-     * @param $name
351
-     */
352
-    public function unregister_function($name)
353
-    {
354
-        unset($this->plugins[$name]);
355
-    }
356
-
357
-    /**
358
-     * @param      $name
359
-     * @param      $callback
360
-     * @param bool $cacheable
361
-     * @param null $cache_attrs
362
-     *
363
-     * @throws Exception
364
-     */
365
-    public function register_block($name, $callback, $cacheable = true, $cache_attrs = null)
366
-    {
367
-        if (isset($this->plugins[$name]) && $this->plugins[$name][0] !== self::SMARTY_BLOCK) {
368
-            throw new Exception('Multiple plugins of different types can not share the same name');
369
-        }
370
-        $this->plugins[$name] = array(
371
-            'type'     => self::SMARTY_BLOCK,
372
-            'callback' => $callback
373
-        );
374
-    }
375
-
376
-    /**
377
-     * @param $name
378
-     */
379
-    public function unregister_block($name)
380
-    {
381
-        unset($this->plugins[$name]);
382
-    }
383
-
384
-    /**
385
-     * @param $name
386
-     * @param $callback
387
-     *
388
-     * @throws Exception
389
-     */
390
-    public function register_modifier($name, $callback)
391
-    {
392
-        if (isset($this->plugins[$name]) && $this->plugins[$name][0] !== self::SMARTY_MODIFIER) {
393
-            throw new Exception('Multiple plugins of different types can not share the same name');
394
-        }
395
-        $this->plugins[$name] = array(
396
-            'type'     => self::SMARTY_MODIFIER,
397
-            'callback' => $callback
398
-        );
399
-    }
400
-
401
-    /**
402
-     * @param $name
403
-     */
404
-    public function unregister_modifier($name)
405
-    {
406
-        unset($this->plugins[$name]);
407
-    }
408
-
409
-    /**
410
-     * @param $callback
411
-     */
412
-    public function register_prefilter($callback)
413
-    {
414
-        $processor = new ProcessorAdapter($this->compiler);
415
-        $processor->registerCallback($callback);
416
-        $this->_filters['pre'][] = $processor;
417
-        $this->compiler->addPreProcessor($processor);
418
-    }
419
-
420
-    /**
421
-     * @param $callback
422
-     */
423
-    public function unregister_prefilter($callback)
424
-    {
425
-        foreach ($this->_filters['pre'] as $index => $processor) {
426
-            if ($processor->callback === $callback) {
427
-                $this->compiler->removePostProcessor($processor);
428
-                unset($this->_filters['pre'][$index]);
429
-            }
430
-        }
431
-    }
432
-
433
-    /**
434
-     * @param $callback
435
-     */
436
-    public function register_postfilter($callback)
437
-    {
438
-        $processor = new ProcessorAdapter($this->compiler);
439
-        $processor->registerCallback($callback);
440
-        $this->_filters['post'][] = $processor;
441
-        $this->compiler->addPostProcessor($processor);
442
-    }
443
-
444
-    /**
445
-     * @param $callback
446
-     */
447
-    public function unregister_postfilter($callback)
448
-    {
449
-        foreach ($this->_filters['post'] as $index => $processor) {
450
-            if ($processor->callback === $callback) {
451
-                $this->compiler->removePostProcessor($processor);
452
-                unset($this->_filters['post'][$index]);
453
-            }
454
-        }
455
-    }
456
-
457
-    /**
458
-     * @param $callback
459
-     */
460
-    public function register_outputfilter($callback)
461
-    {
462
-        $filter = new FilterAdapter($this);
463
-        $filter->registerCallback($callback);
464
-        $this->_filters['output'][] = $filter;
465
-        $this->addFilter($filter);
466
-    }
467
-
468
-    /**
469
-     * @param $callback
470
-     */
471
-    public function unregister_outputfilter($callback)
472
-    {
473
-        foreach ($this->_filters['output'] as $index => $filter) {
474
-            if ($filter->callback === $callback) {
475
-                $this->removeOutputFilter($filter);
476
-                unset($this->_filters['output'][$index]);
477
-            }
478
-        }
479
-    }
480
-
481
-    /**
482
-     * @param       $object
483
-     * @param       $object_impl
484
-     * @param array $allowed
485
-     * @param bool  $smarty_args
486
-     * @param array $block_methods
487
-     */
488
-    public function register_object($object, $object_impl, $allowed = array(), $smarty_args = false, $block_methods = array())
489
-    {
490
-        settype($allowed, 'array');
491
-        settype($block_methods, 'array');
492
-        settype($smarty_args, 'boolean');
493
-
494
-        if (!empty($allowed) && $this->show_compat_errors) {
495
-            $this->triggerError('You can register objects but can not restrict the method/properties used, this is PHP5, you have proper OOP access restrictions so use them.', E_USER_NOTICE);
496
-        }
497
-
498
-        if ($smarty_args) {
499
-            $this->triggerError('You can register objects but methods will be called using method($arg1, $arg2, $arg3), not as an argument array like smarty did.', E_USER_NOTICE);
500
-        }
501
-
502
-        if (!empty($block_methods)) {
503
-            $this->triggerError('You can register objects but can not use methods as being block methods, you have to build a plugin for that.', E_USER_NOTICE);
504
-        }
505
-
506
-        $this->dataProvider->assign($object, $object_impl);
507
-    }
508
-
509
-    /**
510
-     * @param $object
511
-     */
512
-    public function unregister_object($object)
513
-    {
514
-        $this->dataProvider->clear($object);
515
-    }
516
-
517
-    /**
518
-     * @param $name
519
-     *
520
-     * @return mixed
521
-     */
522
-    public function get_registered_object($name)
523
-    {
524
-        $data = $this->dataProvider->getData();
525
-        if (isset($data[$name]) && is_object($data[$name])) {
526
-            return $data[$name];
527
-        } else {
528
-            trigger_error('Dwoo_Compiler: object "' . $name . '" was not registered or is not an object', E_USER_ERROR);
529
-        }
530
-    }
531
-
532
-    /**
533
-     * @param $filename
534
-     *
535
-     * @return bool
536
-     */
537
-    public function template_exists($filename)
538
-    {
539
-        if (!is_array($this->template_dir)) {
540
-            return file_exists($this->template_dir . DIRECTORY_SEPARATOR . $filename);
541
-        } else {
542
-            foreach ($this->template_dir as $tpl_dir) {
543
-                if (file_exists($tpl_dir . DIRECTORY_SEPARATOR . $filename)) {
544
-                    return true;
545
-                }
546
-            }
547
-
548
-            return false;
549
-        }
550
-    }
551
-
552
-    /**
553
-     * @param      $tpl
554
-     * @param null $cacheId
555
-     * @param null $compileId
556
-     *
557
-     * @return bool
558
-     */
559
-    public function is_cached($tpl, $cacheId = null, $compileId = null)
560
-    {
561
-        return $this->isCached($this->makeTemplate($tpl, $cacheId, $compileId));
562
-    }
563
-
564
-    /**
565
-     * @param      $var
566
-     * @param      $value
567
-     * @param bool $merge
568
-     */
569
-    public function append_by_ref($var, &$value, $merge = false)
570
-    {
571
-        $this->dataProvider->appendByRef($var, $value, $merge);
572
-    }
573
-
574
-    /**
575
-     * @param $name
576
-     * @param $val
577
-     */
578
-    public function assign_by_ref($name, &$val)
579
-    {
580
-        $this->dataProvider->assignByRef($name, $val);
581
-    }
582
-
583
-    /**
584
-     * @param $var
585
-     */
586
-    public function clear_assign($var)
587
-    {
588
-        $this->dataProvider->clear($var);
589
-    }
590
-
591
-    /**
592
-     *
593
-     */
594
-    public function clear_all_assign()
595
-    {
596
-        $this->dataProvider->clear();
597
-    }
598
-
599
-    /**
600
-     * @param null $name
601
-     *
602
-     * @return array|null
603
-     */
604
-    public function get_template_vars($name = null)
605
-    {
606
-        if ($this->show_compat_errors) {
607
-            trigger_error('get_template_vars does not return values by reference, if you try to modify the data that way you should modify your code.', E_USER_NOTICE);
608
-        }
609
-
610
-        $data = $this->dataProvider->getData();
611
-        if ($name === null) {
612
-            return $data;
613
-        } elseif (isset($data[$name])) {
614
-            return $data[$name];
615
-        }
616
-
617
-        return null;
618
-    }
619
-
620
-    /**
621
-     * @param int $olderThan
622
-     */
623
-    public function clear_all_cache($olderThan = 0)
624
-    {
625
-        $this->clearCache($olderThan);
626
-    }
627
-
628
-    /**
629
-     * @param      $template
630
-     * @param null $cacheId
631
-     * @param null $compileId
632
-     * @param int  $olderThan
633
-     */
634
-    public function clear_cache($template, $cacheId = null, $compileId = null, $olderThan = 0)
635
-    {
636
-        $this->makeTemplate($template, $cacheId, $compileId)->clearCache($olderThan);
637
-    }
638
-
639
-    /**
640
-     * @param     $error_msg
641
-     * @param int $error_type
642
-     */
643
-    public function trigger_error($error_msg, $error_type = E_USER_WARNING)
644
-    {
645
-        $this->triggerError($error_msg, $error_type);
646
-    }
647
-
648
-    /**
649
-     *
650
-     */
651
-    protected function initGlobals()
652
-    {
653
-        parent::initGlobals();
654
-        $this->globals['ldelim'] = '{';
655
-        $this->globals['rdelim'] = '}';
656
-    }
657
-
658
-    /**
659
-     * @param $file
660
-     * @param $cacheId
661
-     * @param $compileId
662
-     *
663
-     * @return mixed
664
-     * @throws Exception
665
-     */
666
-    protected function makeTemplate($file, $cacheId, $compileId)
667
-    {
668
-        if ($compileId === null) {
669
-            $compileId = $this->compile_id;
670
-        }
671
-
672
-        $hash = bin2hex(md5($file . $cacheId . $compileId, true));
673
-        if (!isset(self::$tplCache[$hash])) {
674
-            // abs path
675
-            if (substr($file, 0, 1) === '/' || substr($file, 1, 1) === ':') {
676
-                self::$tplCache[$hash] = new TemplateFile($file, null, $cacheId, $compileId);
677
-            } elseif (is_string($this->template_dir) || is_array($this->template_dir)) {
678
-                self::$tplCache[$hash] = new TemplateFile($file, null, $cacheId, $compileId, $this->template_dir);
679
-            } else {
680
-                throw new Exception('Unable to load "' . $file . '", check the template_dir');
681
-            }
682
-        }
683
-
684
-        return self::$tplCache[$hash];
685
-    }
686
-
687
-    /**
688
-     * @param string $message
689
-     * @param int    $level
690
-     */
691
-    public function triggerError($message, $level = E_USER_NOTICE)
692
-    {
693
-        if (is_object($this->template)) {
694
-            parent::triggerError($message, $level);
695
-        }
696
-        trigger_error('Dwoo error : ' . $message, $level);
697
-    }
46
+	/**
47
+	 * Magic get/set/call functions that handle unsupported features
48
+	 *
49
+	 * @param string $p
50
+	 * @param string $v
51
+	 */
52
+	public function __set($p, $v)
53
+	{
54
+		if ($p === 'scope') {
55
+			$this->scope = $v;
56
+
57
+			return;
58
+		}
59
+		if ($p === 'data') {
60
+			$this->data = $v;
61
+
62
+			return;
63
+		}
64
+		if (array_key_exists($p, $this->compat['properties']) !== false) {
65
+			if ($this->show_compat_errors) {
66
+				$this->triggerError('Property ' . $p . ' is not available in the Dwoo\Smarty\Adapter, however it might be implemented in the future, check out http://wiki.dwoo.org/index.php/SmartySupport for more details.', E_USER_NOTICE);
67
+			}
68
+			$this->compat['properties'][$p] = $v;
69
+		} else {
70
+			if ($this->show_compat_errors) {
71
+				$this->triggerError('Property ' . $p . ' is not available in the Dwoo\Smarty\Adapter, but it is not listed as such, so you might want to tell me about it at [email protected]', E_USER_NOTICE);
72
+			}
73
+		}
74
+	}
75
+
76
+	/**
77
+	 * @param $p
78
+	 *
79
+	 * @return mixed
80
+	 */
81
+	public function __get($p)
82
+	{
83
+		if (array_key_exists($p, $this->compat['properties']) !== false) {
84
+			if ($this->show_compat_errors) {
85
+				$this->triggerError('Property ' . $p . ' is not available in the Dwoo\Smarty\Adapter, however it might be implemented in the future, check out http://wiki.dwoo.org/index.php/SmartySupport for more details.', E_USER_NOTICE);
86
+			}
87
+
88
+			return $this->compat['properties'][$p];
89
+		} else {
90
+			if ($this->show_compat_errors) {
91
+				$this->triggerError('Property ' . $p . ' is not available in the Dwoo\Smarty\Adapter, but it is not listed as such, so you might want to tell me about it at [email protected]', E_USER_NOTICE);
92
+			}
93
+		}
94
+	}
95
+
96
+	/**
97
+	 * @param string $m
98
+	 * @param array  $a
99
+	 *
100
+	 * @return mixed|void
101
+	 */
102
+	public function __call($m, $a)
103
+	{
104
+		if (method_exists($this->dataProvider, $m)) {
105
+			call_user_func_array(
106
+				array(
107
+				$this->dataProvider,
108
+				$m
109
+				), $a
110
+			);
111
+		} elseif ($this->show_compat_errors) {
112
+			if (array_search($m, $this->compat['methods']) !== false) {
113
+				$this->triggerError('Method ' . $m . ' is not available in the Dwoo\Smarty\Adapter, however it might be implemented in the future, check out http://wiki.dwoo.org/index.php/SmartySupport for more details.', E_USER_NOTICE);
114
+			} else {
115
+				$this->triggerError('Method ' . $m . ' is not available in the Dwoo\Smarty\Adapter, but it is not listed as such, so you might want to tell me about it at [email protected]', E_USER_NOTICE);
116
+			}
117
+		}
118
+	}
119
+
120
+	/**
121
+	 * List of unsupported properties and methods
122
+	 */
123
+	protected $compat = array(
124
+		'methods'    => array(
125
+			'register_resource',
126
+			'unregister_resource',
127
+			'load_filter',
128
+			'clear_compiled_tpl',
129
+			'clear_config',
130
+			'get_config_vars',
131
+			'config_load',
132
+		),
133
+		'properties' => array(
134
+			'cache_handler_func'            => null,
135
+			'debugging'                     => false,
136
+			'error_reporting'               => null,
137
+			'debugging_ctrl'                => 'NONE',
138
+			'request_vars_order'            => 'EGPCS',
139
+			'request_use_auto_globals'      => true,
140
+			'use_sub_dirs'                  => false,
141
+			'autoload_filters'              => array(),
142
+			'default_template_handler_func' => '',
143
+			'debug_tpl'                     => '',
144
+			'cache_modified_check'          => false,
145
+			'default_modifiers'             => array(),
146
+			'default_resource_type'         => 'file',
147
+			'config_overwrite'              => true,
148
+			'config_booleanize'             => true,
149
+			'config_read_hidden'            => false,
150
+			'config_fix_newlines'           => true,
151
+			'config_class'                  => 'Config_File',
152
+		),
153
+	);
154
+
155
+	/**
156
+	 * Security vars
157
+	 */
158
+	public $security          = false;
159
+	public $trusted_dir       = array();
160
+	public $secure_dir        = array();
161
+	public $php_handling      = SMARTY_PHP_PASSTHRU;
162
+	public $security_settings = array(
163
+		'PHP_HANDLING'    => false,
164
+		'IF_FUNCS'        => array(
165
+			'list',
166
+			'empty',
167
+			'count',
168
+			'sizeof',
169
+			'in_array',
170
+			'is_array',
171
+		),
172
+		'INCLUDE_ANY'     => false,
173
+		'PHP_TAGS'        => false,
174
+		'MODIFIER_FUNCS'  => array(),
175
+		'ALLOW_CONSTANTS' => false,
176
+	);
177
+
178
+	/**
179
+	 * Paths
180
+	 */
181
+	public $template_dir = 'templates';
182
+	public $compile_dir  = 'templates_c';
183
+	public $config_dir   = 'configs';
184
+	public $cache_dir    = 'cache';
185
+	public $plugins_dir  = array();
186
+
187
+	/**
188
+	 * Misc options
189
+	 */
190
+	public $left_delimiter  = '{';
191
+	public $right_delimiter = '}';
192
+	public $compile_check   = true;
193
+	public $force_compile   = false;
194
+	public $caching         = 0;
195
+	public $cache_lifetime  = 3600;
196
+	public $compile_id      = null;
197
+	public $compiler_file   = null;
198
+	public $compiler_class  = null;
199
+
200
+	/**
201
+	 * Dwoo/Smarty compat layer
202
+	 */
203
+	public           $show_compat_errors = false;
204
+	protected        $dataProvider;
205
+	protected        $_filters           = array(
206
+		'pre'    => array(),
207
+		'post'   => array(),
208
+		'output' => array()
209
+	);
210
+	protected static $tplCache           = array();
211
+	protected        $compiler           = null;
212
+
213
+	/**
214
+	 * Adapter constructor.
215
+	 */
216
+	public function __construct()
217
+	{
218
+		parent::__construct();
219
+		$this->charset      = 'iso-8859-1';
220
+		$this->dataProvider = new Data();
221
+		$this->compiler     = new Compiler();
222
+	}
223
+
224
+	/**
225
+	 * @param      $filename
226
+	 * @param null $cacheId
227
+	 * @param null $compileId
228
+	 */
229
+	public function display($filename, $cacheId = null, $compileId = null)
230
+	{
231
+		$this->fetch($filename, $cacheId, $compileId, true);
232
+	}
233
+
234
+	/**
235
+	 * @param      $filename
236
+	 * @param null $cacheId
237
+	 * @param null $compileId
238
+	 * @param bool $display
239
+	 *
240
+	 * @return string|void
241
+	 */
242
+	public function fetch($filename, $cacheId = null, $compileId = null, $display = false)
243
+	{
244
+		$this->setCacheDir($this->cache_dir);
245
+		$this->setCompileDir($this->compile_dir);
246
+
247
+		if ($this->security) {
248
+			$policy = new SecurityPolicy();
249
+			$policy->addPhpFunction(array_merge($this->security_settings['IF_FUNCS'], $this->security_settings['MODIFIER_FUNCS']));
250
+
251
+			$phpTags = $this->security_settings['PHP_HANDLING'] ? SMARTY_PHP_ALLOW : $this->php_handling;
252
+			if ($this->security_settings['PHP_TAGS']) {
253
+				$phpTags = SMARTY_PHP_ALLOW;
254
+			}
255
+			switch ($phpTags) {
256
+			case SMARTY_PHP_ALLOW:
257
+			case SMARTY_PHP_PASSTHRU:
258
+				$phpTags = SecurityPolicy::PHP_ALLOW;
259
+				break;
260
+			case SMARTY_PHP_QUOTE:
261
+				$phpTags = SecurityPolicy::PHP_ENCODE;
262
+				break;
263
+			case SMARTY_PHP_REMOVE:
264
+			default:
265
+				$phpTags = SecurityPolicy::PHP_REMOVE;
266
+				break;
267
+			}
268
+			$policy->setPhpHandling($phpTags);
269
+
270
+			$policy->setConstantHandling($this->security_settings['ALLOW_CONSTANTS']);
271
+
272
+			if ($this->security_settings['INCLUDE_ANY']) {
273
+				$policy->allowDirectory(preg_replace('{^((?:[a-z]:)?[\\\\/]).*}i', '$1', __FILE__));
274
+			} else {
275
+				$policy->allowDirectory($this->secure_dir);
276
+			}
277
+
278
+			$this->setSecurityPolicy($policy);
279
+		}
280
+
281
+		if (!empty($this->plugins_dir)) {
282
+			foreach ($this->plugins_dir as $dir) {
283
+				$this->getLoader()->addDirectory(rtrim($dir, '\\/'));
284
+			}
285
+		}
286
+
287
+		$tpl = $this->makeTemplate($filename, $cacheId, $compileId);
288
+		if ($this->force_compile) {
289
+			$tpl->forceCompilation();
290
+		}
291
+
292
+		if ($this->caching > 0) {
293
+			$this->cacheTime = $this->cache_lifetime;
294
+		} else {
295
+			$this->cacheTime = 0;
296
+		}
297
+
298
+		if ($this->compiler_class !== null) {
299
+			if ($this->compiler_file !== null && !class_exists($this->compiler_class)) {
300
+				include $this->compiler_file;
301
+			}
302
+			$this->compiler = new $this->compiler_class();
303
+		} else {
304
+			$this->compiler->addPreProcessor('PluginSmartyCompatible', true);
305
+			$this->compiler->setLooseOpeningHandling(true);
306
+		}
307
+
308
+		$this->compiler->setDelimiters($this->left_delimiter, $this->right_delimiter);
309
+
310
+		return $this->get($tpl, $this->dataProvider, $this->compiler, $display === true);
311
+	}
312
+
313
+	/**
314
+	 * @param mixed $_tpl
315
+	 * @param array $data
316
+	 * @param null  $_compiler
317
+	 * @param bool  $_output
318
+	 *
319
+	 * @return string|void
320
+	 */
321
+	public function get($_tpl, $data = array(), $_compiler = null, $_output = false)
322
+	{
323
+		if ($_compiler === null) {
324
+			$_compiler = $this->compiler;
325
+		}
326
+
327
+		return parent::get($_tpl, $data, $_compiler, $_output);
328
+	}
329
+
330
+	/**
331
+	 * @param      $name
332
+	 * @param      $callback
333
+	 * @param bool $cacheable
334
+	 * @param null $cache_attrs
335
+	 *
336
+	 * @throws Exception
337
+	 */
338
+	public function register_function($name, $callback, $cacheable = true, $cache_attrs = null)
339
+	{
340
+		if (isset($this->plugins[$name]) && $this->plugins[$name][0] !== self::SMARTY_FUNCTION) {
341
+			throw new Exception('Multiple plugins of different types can not share the same name');
342
+		}
343
+		$this->plugins[$name] = array(
344
+			'type'     => self::SMARTY_FUNCTION,
345
+			'callback' => $callback
346
+		);
347
+	}
348
+
349
+	/**
350
+	 * @param $name
351
+	 */
352
+	public function unregister_function($name)
353
+	{
354
+		unset($this->plugins[$name]);
355
+	}
356
+
357
+	/**
358
+	 * @param      $name
359
+	 * @param      $callback
360
+	 * @param bool $cacheable
361
+	 * @param null $cache_attrs
362
+	 *
363
+	 * @throws Exception
364
+	 */
365
+	public function register_block($name, $callback, $cacheable = true, $cache_attrs = null)
366
+	{
367
+		if (isset($this->plugins[$name]) && $this->plugins[$name][0] !== self::SMARTY_BLOCK) {
368
+			throw new Exception('Multiple plugins of different types can not share the same name');
369
+		}
370
+		$this->plugins[$name] = array(
371
+			'type'     => self::SMARTY_BLOCK,
372
+			'callback' => $callback
373
+		);
374
+	}
375
+
376
+	/**
377
+	 * @param $name
378
+	 */
379
+	public function unregister_block($name)
380
+	{
381
+		unset($this->plugins[$name]);
382
+	}
383
+
384
+	/**
385
+	 * @param $name
386
+	 * @param $callback
387
+	 *
388
+	 * @throws Exception
389
+	 */
390
+	public function register_modifier($name, $callback)
391
+	{
392
+		if (isset($this->plugins[$name]) && $this->plugins[$name][0] !== self::SMARTY_MODIFIER) {
393
+			throw new Exception('Multiple plugins of different types can not share the same name');
394
+		}
395
+		$this->plugins[$name] = array(
396
+			'type'     => self::SMARTY_MODIFIER,
397
+			'callback' => $callback
398
+		);
399
+	}
400
+
401
+	/**
402
+	 * @param $name
403
+	 */
404
+	public function unregister_modifier($name)
405
+	{
406
+		unset($this->plugins[$name]);
407
+	}
408
+
409
+	/**
410
+	 * @param $callback
411
+	 */
412
+	public function register_prefilter($callback)
413
+	{
414
+		$processor = new ProcessorAdapter($this->compiler);
415
+		$processor->registerCallback($callback);
416
+		$this->_filters['pre'][] = $processor;
417
+		$this->compiler->addPreProcessor($processor);
418
+	}
419
+
420
+	/**
421
+	 * @param $callback
422
+	 */
423
+	public function unregister_prefilter($callback)
424
+	{
425
+		foreach ($this->_filters['pre'] as $index => $processor) {
426
+			if ($processor->callback === $callback) {
427
+				$this->compiler->removePostProcessor($processor);
428
+				unset($this->_filters['pre'][$index]);
429
+			}
430
+		}
431
+	}
432
+
433
+	/**
434
+	 * @param $callback
435
+	 */
436
+	public function register_postfilter($callback)
437
+	{
438
+		$processor = new ProcessorAdapter($this->compiler);
439
+		$processor->registerCallback($callback);
440
+		$this->_filters['post'][] = $processor;
441
+		$this->compiler->addPostProcessor($processor);
442
+	}
443
+
444
+	/**
445
+	 * @param $callback
446
+	 */
447
+	public function unregister_postfilter($callback)
448
+	{
449
+		foreach ($this->_filters['post'] as $index => $processor) {
450
+			if ($processor->callback === $callback) {
451
+				$this->compiler->removePostProcessor($processor);
452
+				unset($this->_filters['post'][$index]);
453
+			}
454
+		}
455
+	}
456
+
457
+	/**
458
+	 * @param $callback
459
+	 */
460
+	public function register_outputfilter($callback)
461
+	{
462
+		$filter = new FilterAdapter($this);
463
+		$filter->registerCallback($callback);
464
+		$this->_filters['output'][] = $filter;
465
+		$this->addFilter($filter);
466
+	}
467
+
468
+	/**
469
+	 * @param $callback
470
+	 */
471
+	public function unregister_outputfilter($callback)
472
+	{
473
+		foreach ($this->_filters['output'] as $index => $filter) {
474
+			if ($filter->callback === $callback) {
475
+				$this->removeOutputFilter($filter);
476
+				unset($this->_filters['output'][$index]);
477
+			}
478
+		}
479
+	}
480
+
481
+	/**
482
+	 * @param       $object
483
+	 * @param       $object_impl
484
+	 * @param array $allowed
485
+	 * @param bool  $smarty_args
486
+	 * @param array $block_methods
487
+	 */
488
+	public function register_object($object, $object_impl, $allowed = array(), $smarty_args = false, $block_methods = array())
489
+	{
490
+		settype($allowed, 'array');
491
+		settype($block_methods, 'array');
492
+		settype($smarty_args, 'boolean');
493
+
494
+		if (!empty($allowed) && $this->show_compat_errors) {
495
+			$this->triggerError('You can register objects but can not restrict the method/properties used, this is PHP5, you have proper OOP access restrictions so use them.', E_USER_NOTICE);
496
+		}
497
+
498
+		if ($smarty_args) {
499
+			$this->triggerError('You can register objects but methods will be called using method($arg1, $arg2, $arg3), not as an argument array like smarty did.', E_USER_NOTICE);
500
+		}
501
+
502
+		if (!empty($block_methods)) {
503
+			$this->triggerError('You can register objects but can not use methods as being block methods, you have to build a plugin for that.', E_USER_NOTICE);
504
+		}
505
+
506
+		$this->dataProvider->assign($object, $object_impl);
507
+	}
508
+
509
+	/**
510
+	 * @param $object
511
+	 */
512
+	public function unregister_object($object)
513
+	{
514
+		$this->dataProvider->clear($object);
515
+	}
516
+
517
+	/**
518
+	 * @param $name
519
+	 *
520
+	 * @return mixed
521
+	 */
522
+	public function get_registered_object($name)
523
+	{
524
+		$data = $this->dataProvider->getData();
525
+		if (isset($data[$name]) && is_object($data[$name])) {
526
+			return $data[$name];
527
+		} else {
528
+			trigger_error('Dwoo_Compiler: object "' . $name . '" was not registered or is not an object', E_USER_ERROR);
529
+		}
530
+	}
531
+
532
+	/**
533
+	 * @param $filename
534
+	 *
535
+	 * @return bool
536
+	 */
537
+	public function template_exists($filename)
538
+	{
539
+		if (!is_array($this->template_dir)) {
540
+			return file_exists($this->template_dir . DIRECTORY_SEPARATOR . $filename);
541
+		} else {
542
+			foreach ($this->template_dir as $tpl_dir) {
543
+				if (file_exists($tpl_dir . DIRECTORY_SEPARATOR . $filename)) {
544
+					return true;
545
+				}
546
+			}
547
+
548
+			return false;
549
+		}
550
+	}
551
+
552
+	/**
553
+	 * @param      $tpl
554
+	 * @param null $cacheId
555
+	 * @param null $compileId
556
+	 *
557
+	 * @return bool
558
+	 */
559
+	public function is_cached($tpl, $cacheId = null, $compileId = null)
560
+	{
561
+		return $this->isCached($this->makeTemplate($tpl, $cacheId, $compileId));
562
+	}
563
+
564
+	/**
565
+	 * @param      $var
566
+	 * @param      $value
567
+	 * @param bool $merge
568
+	 */
569
+	public function append_by_ref($var, &$value, $merge = false)
570
+	{
571
+		$this->dataProvider->appendByRef($var, $value, $merge);
572
+	}
573
+
574
+	/**
575
+	 * @param $name
576
+	 * @param $val
577
+	 */
578
+	public function assign_by_ref($name, &$val)
579
+	{
580
+		$this->dataProvider->assignByRef($name, $val);
581
+	}
582
+
583
+	/**
584
+	 * @param $var
585
+	 */
586
+	public function clear_assign($var)
587
+	{
588
+		$this->dataProvider->clear($var);
589
+	}
590
+
591
+	/**
592
+	 *
593
+	 */
594
+	public function clear_all_assign()
595
+	{
596
+		$this->dataProvider->clear();
597
+	}
598
+
599
+	/**
600
+	 * @param null $name
601
+	 *
602
+	 * @return array|null
603
+	 */
604
+	public function get_template_vars($name = null)
605
+	{
606
+		if ($this->show_compat_errors) {
607
+			trigger_error('get_template_vars does not return values by reference, if you try to modify the data that way you should modify your code.', E_USER_NOTICE);
608
+		}
609
+
610
+		$data = $this->dataProvider->getData();
611
+		if ($name === null) {
612
+			return $data;
613
+		} elseif (isset($data[$name])) {
614
+			return $data[$name];
615
+		}
616
+
617
+		return null;
618
+	}
619
+
620
+	/**
621
+	 * @param int $olderThan
622
+	 */
623
+	public function clear_all_cache($olderThan = 0)
624
+	{
625
+		$this->clearCache($olderThan);
626
+	}
627
+
628
+	/**
629
+	 * @param      $template
630
+	 * @param null $cacheId
631
+	 * @param null $compileId
632
+	 * @param int  $olderThan
633
+	 */
634
+	public function clear_cache($template, $cacheId = null, $compileId = null, $olderThan = 0)
635
+	{
636
+		$this->makeTemplate($template, $cacheId, $compileId)->clearCache($olderThan);
637
+	}
638
+
639
+	/**
640
+	 * @param     $error_msg
641
+	 * @param int $error_type
642
+	 */
643
+	public function trigger_error($error_msg, $error_type = E_USER_WARNING)
644
+	{
645
+		$this->triggerError($error_msg, $error_type);
646
+	}
647
+
648
+	/**
649
+	 *
650
+	 */
651
+	protected function initGlobals()
652
+	{
653
+		parent::initGlobals();
654
+		$this->globals['ldelim'] = '{';
655
+		$this->globals['rdelim'] = '}';
656
+	}
657
+
658
+	/**
659
+	 * @param $file
660
+	 * @param $cacheId
661
+	 * @param $compileId
662
+	 *
663
+	 * @return mixed
664
+	 * @throws Exception
665
+	 */
666
+	protected function makeTemplate($file, $cacheId, $compileId)
667
+	{
668
+		if ($compileId === null) {
669
+			$compileId = $this->compile_id;
670
+		}
671
+
672
+		$hash = bin2hex(md5($file . $cacheId . $compileId, true));
673
+		if (!isset(self::$tplCache[$hash])) {
674
+			// abs path
675
+			if (substr($file, 0, 1) === '/' || substr($file, 1, 1) === ':') {
676
+				self::$tplCache[$hash] = new TemplateFile($file, null, $cacheId, $compileId);
677
+			} elseif (is_string($this->template_dir) || is_array($this->template_dir)) {
678
+				self::$tplCache[$hash] = new TemplateFile($file, null, $cacheId, $compileId, $this->template_dir);
679
+			} else {
680
+				throw new Exception('Unable to load "' . $file . '", check the template_dir');
681
+			}
682
+		}
683
+
684
+		return self::$tplCache[$hash];
685
+	}
686
+
687
+	/**
688
+	 * @param string $message
689
+	 * @param int    $level
690
+	 */
691
+	public function triggerError($message, $level = E_USER_NOTICE)
692
+	{
693
+		if (is_object($this->template)) {
694
+			parent::triggerError($message, $level);
695
+		}
696
+		trigger_error('Dwoo error : ' . $message, $level);
697
+	}
698 698
 }
Please login to merge, or discard this patch.