Completed
Push — master ( 624651...67fff9 )
by David
03:58
created
lib/Dwoo/Smarty/Adapter.php 1 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.
lib/Dwoo/Smarty/Processor/Adapter.php 1 patch
Indentation   +17 added lines, -17 removed lines patch added patch discarded remove patch
@@ -23,23 +23,23 @@
 block discarded – undo
23 23
  */
24 24
 class Adapter extends Processor
25 25
 {
26
-    public $callback;
26
+	public $callback;
27 27
 
28
-    /**
29
-     * @param string $input
30
-     *
31
-     * @return mixed
32
-     */
33
-    public function process($input)
34
-    {
35
-        return call_user_func($this->callback, $input);
36
-    }
28
+	/**
29
+	 * @param string $input
30
+	 *
31
+	 * @return mixed
32
+	 */
33
+	public function process($input)
34
+	{
35
+		return call_user_func($this->callback, $input);
36
+	}
37 37
 
38
-    /**
39
-     * @param $callback
40
-     */
41
-    public function registerCallback($callback)
42
-    {
43
-        $this->callback = $callback;
44
-    }
38
+	/**
39
+	 * @param $callback
40
+	 */
41
+	public function registerCallback($callback)
42
+	{
43
+		$this->callback = $callback;
44
+	}
45 45
 }
46 46
\ No newline at end of file
Please login to merge, or discard this patch.
lib/Dwoo/Compilation/Exception.php 1 patch
Indentation   +28 added lines, -28 removed lines patch added patch discarded remove patch
@@ -26,35 +26,35 @@
 block discarded – undo
26 26
  */
27 27
 class Exception extends DwooException
28 28
 {
29
-    protected $compiler;
30
-    protected $template;
29
+	protected $compiler;
30
+	protected $template;
31 31
 
32
-    /**
33
-     * Exception constructor.
34
-     *
35
-     * @param DwooCompiler $compiler
36
-     * @param int          $message
37
-     */
38
-    public function __construct(DwooCompiler $compiler, $message)
39
-    {
40
-        $this->compiler = $compiler;
41
-        $this->template = $compiler->getDwoo()->getTemplate();
42
-        parent::__construct('Compilation error at line ' . $compiler->getLine() . ' in "' . $this->template->getResourceName() . ':' . $this->template->getResourceIdentifier() . '" : ' . $message);
43
-    }
32
+	/**
33
+	 * Exception constructor.
34
+	 *
35
+	 * @param DwooCompiler $compiler
36
+	 * @param int          $message
37
+	 */
38
+	public function __construct(DwooCompiler $compiler, $message)
39
+	{
40
+		$this->compiler = $compiler;
41
+		$this->template = $compiler->getDwoo()->getTemplate();
42
+		parent::__construct('Compilation error at line ' . $compiler->getLine() . ' in "' . $this->template->getResourceName() . ':' . $this->template->getResourceIdentifier() . '" : ' . $message);
43
+	}
44 44
 
45
-    /**
46
-     * @return DwooCompiler
47
-     */
48
-    public function getCompiler()
49
-    {
50
-        return $this->compiler;
51
-    }
45
+	/**
46
+	 * @return DwooCompiler
47
+	 */
48
+	public function getCompiler()
49
+	{
50
+		return $this->compiler;
51
+	}
52 52
 
53
-    /**
54
-     * @return \Dwoo\ITemplate|null
55
-     */
56
-    public function getTemplate()
57
-    {
58
-        return $this->template;
59
-    }
53
+	/**
54
+	 * @return \Dwoo\ITemplate|null
55
+	 */
56
+	public function getTemplate()
57
+	{
58
+		return $this->template;
59
+	}
60 60
 }
Please login to merge, or discard this patch.
lib/Dwoo/IPluginProxy.php 1 patch
Indentation   +45 added lines, -45 removed lines patch added patch discarded remove patch
@@ -23,52 +23,52 @@
 block discarded – undo
23 23
  */
24 24
 interface IPluginProxy
25 25
 {
26
-    /**
27
-     * Returns true or false to say whether the given plugin is handled by this proxy or not.
28
-     *
29
-     * @param string $name the plugin name
30
-     *
31
-     * @return bool true if the plugin is known and usable, otherwise false
32
-     */
33
-    public function handles($name);
26
+	/**
27
+	 * Returns true or false to say whether the given plugin is handled by this proxy or not.
28
+	 *
29
+	 * @param string $name the plugin name
30
+	 *
31
+	 * @return bool true if the plugin is known and usable, otherwise false
32
+	 */
33
+	public function handles($name);
34 34
 
35
-    /**
36
-     * Returns the code (as a string) to call the plugin
37
-     * (this will be executed at runtime inside the Dwoo class).
38
-     *
39
-     * @param string $name   the plugin name
40
-     * @param array  $params a parameter array, array key "*" is the rest array
41
-     *
42
-     * @return string
43
-     */
44
-    public function getCode($name, $params);
35
+	/**
36
+	 * Returns the code (as a string) to call the plugin
37
+	 * (this will be executed at runtime inside the Dwoo class).
38
+	 *
39
+	 * @param string $name   the plugin name
40
+	 * @param array  $params a parameter array, array key "*" is the rest array
41
+	 *
42
+	 * @return string
43
+	 */
44
+	public function getCode($name, $params);
45 45
 
46
-    /**
47
-     * Returns a callback to the plugin, this is used with the reflection API to
48
-     * find out about the plugin's parameter names etc.
49
-     * should you need a rest array without the possibility to edit the
50
-     * plugin's code, you can provide a callback to some
51
-     * other function with the correct parameter signature, i.e. :
52
-     * <code>
53
-     * return array($this, "callbackHelper");
54
-     * // and callbackHelper would be as such:
55
-     * public function callbackHelper(array $rest=array()){}
56
-     * </code>
57
-     *
58
-     * @param string $name the plugin name
59
-     *
60
-     * @return callback
61
-     */
62
-    public function getCallback($name);
46
+	/**
47
+	 * Returns a callback to the plugin, this is used with the reflection API to
48
+	 * find out about the plugin's parameter names etc.
49
+	 * should you need a rest array without the possibility to edit the
50
+	 * plugin's code, you can provide a callback to some
51
+	 * other function with the correct parameter signature, i.e. :
52
+	 * <code>
53
+	 * return array($this, "callbackHelper");
54
+	 * // and callbackHelper would be as such:
55
+	 * public function callbackHelper(array $rest=array()){}
56
+	 * </code>
57
+	 *
58
+	 * @param string $name the plugin name
59
+	 *
60
+	 * @return callback
61
+	 */
62
+	public function getCallback($name);
63 63
 
64
-    /**
65
-     * Returns some code that will check if the plugin is loaded and if not load it
66
-     * this is optional, if your plugins are autoloaded or whatever, just return an
67
-     * empty string.
68
-     *
69
-     * @param string $name the plugin name
70
-     *
71
-     * @return string
72
-     */
73
-    public function getLoader($name);
64
+	/**
65
+	 * Returns some code that will check if the plugin is loaded and if not load it
66
+	 * this is optional, if your plugins are autoloaded or whatever, just return an
67
+	 * empty string.
68
+	 *
69
+	 * @param string $name the plugin name
70
+	 *
71
+	 * @return string
72
+	 */
73
+	public function getLoader($name);
74 74
 }
Please login to merge, or discard this patch.
lib/Dwoo/ITemplate.php 1 patch
Indentation   +120 added lines, -120 removed lines patch added patch discarded remove patch
@@ -23,137 +23,137 @@
 block discarded – undo
23 23
  */
24 24
 interface ITemplate
25 25
 {
26
-    /**
27
-     * Returns the cache duration for this template.
28
-     * defaults to null if it was not provided
29
-     *
30
-     * @return int|null
31
-     */
32
-    public function getCacheTime();
26
+	/**
27
+	 * Returns the cache duration for this template.
28
+	 * defaults to null if it was not provided
29
+	 *
30
+	 * @return int|null
31
+	 */
32
+	public function getCacheTime();
33 33
 
34
-    /**
35
-     * Sets the cache duration for this template.
36
-     * can be used to set it after the object is created if you did not provide
37
-     * it in the constructor
38
-     *
39
-     * @param int $seconds duration of the cache validity for this template, if
40
-     *                     null it defaults to the Dwoo instance's cache time. 0 = disable and
41
-     *                     -1 = infinite cache
42
-     */
43
-    public function setCacheTime($seconds = null);
34
+	/**
35
+	 * Sets the cache duration for this template.
36
+	 * can be used to set it after the object is created if you did not provide
37
+	 * it in the constructor
38
+	 *
39
+	 * @param int $seconds duration of the cache validity for this template, if
40
+	 *                     null it defaults to the Dwoo instance's cache time. 0 = disable and
41
+	 *                     -1 = infinite cache
42
+	 */
43
+	public function setCacheTime($seconds = null);
44 44
 
45
-    /**
46
-     * Returns the cached template output file name, true if it's cache-able but not cached
47
-     * or false if it's not cached.
48
-     *
49
-     * @param Core $dwoo the dwoo instance that requests it
50
-     *
51
-     * @return string|bool
52
-     */
53
-    public function getCachedTemplate(Core $dwoo);
45
+	/**
46
+	 * Returns the cached template output file name, true if it's cache-able but not cached
47
+	 * or false if it's not cached.
48
+	 *
49
+	 * @param Core $dwoo the dwoo instance that requests it
50
+	 *
51
+	 * @return string|bool
52
+	 */
53
+	public function getCachedTemplate(Core $dwoo);
54 54
 
55
-    /**
56
-     * Caches the provided output into the cache file.
57
-     *
58
-     * @param Core   $dwoo   the dwoo instance that requests it
59
-     * @param string $output the template output
60
-     *
61
-     * @return mixed full path of the cached file or false upon failure
62
-     */
63
-    public function cache(Core $dwoo, $output);
55
+	/**
56
+	 * Caches the provided output into the cache file.
57
+	 *
58
+	 * @param Core   $dwoo   the dwoo instance that requests it
59
+	 * @param string $output the template output
60
+	 *
61
+	 * @return mixed full path of the cached file or false upon failure
62
+	 */
63
+	public function cache(Core $dwoo, $output);
64 64
 
65
-    /**
66
-     * Clears the cached template if it's older than the given time.
67
-     *
68
-     * @param Core $dwoo      the dwoo instance that was used to cache that template
69
-     * @param int  $olderThan minimum time (in seconds) required for the cache to be cleared
70
-     *
71
-     * @return bool true if the cache was not present or if it was deleted, false if it remains there
72
-     */
73
-    public function clearCache(Core $dwoo, $olderThan = - 1);
65
+	/**
66
+	 * Clears the cached template if it's older than the given time.
67
+	 *
68
+	 * @param Core $dwoo      the dwoo instance that was used to cache that template
69
+	 * @param int  $olderThan minimum time (in seconds) required for the cache to be cleared
70
+	 *
71
+	 * @return bool true if the cache was not present or if it was deleted, false if it remains there
72
+	 */
73
+	public function clearCache(Core $dwoo, $olderThan = - 1);
74 74
 
75
-    /**
76
-     * Returns the compiled template file name.
77
-     *
78
-     * @param Core      $dwoo     the dwoo instance that requests it
79
-     * @param ICompiler $compiler the compiler that must be used
80
-     *
81
-     * @return string
82
-     */
83
-    public function getCompiledTemplate(Core $dwoo, ICompiler $compiler = null);
75
+	/**
76
+	 * Returns the compiled template file name.
77
+	 *
78
+	 * @param Core      $dwoo     the dwoo instance that requests it
79
+	 * @param ICompiler $compiler the compiler that must be used
80
+	 *
81
+	 * @return string
82
+	 */
83
+	public function getCompiledTemplate(Core $dwoo, ICompiler $compiler = null);
84 84
 
85
-    /**
86
-     * Returns the template name.
87
-     *
88
-     * @return string
89
-     */
90
-    public function getName();
85
+	/**
86
+	 * Returns the template name.
87
+	 *
88
+	 * @return string
89
+	 */
90
+	public function getName();
91 91
 
92
-    /**
93
-     * Returns the resource name for this template class.
94
-     *
95
-     * @return string
96
-     */
97
-    public function getResourceName();
92
+	/**
93
+	 * Returns the resource name for this template class.
94
+	 *
95
+	 * @return string
96
+	 */
97
+	public function getResourceName();
98 98
 
99
-    /**
100
-     * Returns the resource identifier for this template or false if it has no identifier.
101
-     *
102
-     * @return string|false
103
-     */
104
-    public function getResourceIdentifier();
99
+	/**
100
+	 * Returns the resource identifier for this template or false if it has no identifier.
101
+	 *
102
+	 * @return string|false
103
+	 */
104
+	public function getResourceIdentifier();
105 105
 
106
-    /**
107
-     * Returns the template source of this template.
108
-     *
109
-     * @return string
110
-     */
111
-    public function getSource();
106
+	/**
107
+	 * Returns the template source of this template.
108
+	 *
109
+	 * @return string
110
+	 */
111
+	public function getSource();
112 112
 
113
-    /**
114
-     * Returns an unique string identifying the current version of this template,
115
-     * for example a timestamp of the last modified date or a hash of the template source.
116
-     *
117
-     * @return string
118
-     */
119
-    public function getUid();
113
+	/**
114
+	 * Returns an unique string identifying the current version of this template,
115
+	 * for example a timestamp of the last modified date or a hash of the template source.
116
+	 *
117
+	 * @return string
118
+	 */
119
+	public function getUid();
120 120
 
121
-    /**
122
-     * Returns the compiler used by this template, if it was just compiled, or null.
123
-     *
124
-     * @return ICompiler
125
-     */
126
-    public function getCompiler();
121
+	/**
122
+	 * Returns the compiler used by this template, if it was just compiled, or null.
123
+	 *
124
+	 * @return ICompiler
125
+	 */
126
+	public function getCompiler();
127 127
 
128
-    /**
129
-     * Returns some php code that will check if this template has been modified or not.
130
-     * if the function returns null, the template will be instanciated and then the Uid checked
131
-     *
132
-     * @return string
133
-     */
134
-    public function getIsModifiedCode();
128
+	/**
129
+	 * Returns some php code that will check if this template has been modified or not.
130
+	 * if the function returns null, the template will be instanciated and then the Uid checked
131
+	 *
132
+	 * @return string
133
+	 */
134
+	public function getIsModifiedCode();
135 135
 
136
-    /**
137
-     * Returns a new template object from the given resource identifier, null if no include is
138
-     * possible (resource not found), or false if include is not permitted by this resource type.
139
-     * this method should also check if $dwoo->getSecurityPolicy() is null or not and do the
140
-     * necessary permission checks if required, if the security policy prevents the template
141
-     * generation it should throw a new Security\Exception with a relevant message
142
-     *
143
-     * @param mixed     $resourceId     the resource identifier
144
-     * @param int       $cacheTime      duration of the cache validity for this template, if null it defaults to the
145
-     *                                  Dwoo instance that will render this template if null it defaults to the Dwoo
146
-     *                                  instance that will render this template
147
-     * @param string    $cacheId        the unique cache identifier of this page or anything else that makes this
148
-     *                                  template's content unique, if null it defaults to the current url makes this
149
-     *                                  template's content unique, if null it defaults to the current url
150
-     * @param string    $compileId      the unique compiled identifier, which is used to distinguish this template from
151
-     *                                  others, if null it defaults to the filename+bits of the path template from
152
-     *                                  others, if null it defaults to the filename+bits of the path
153
-     * @param ITemplate $parentTemplate the template that is requesting a new template object (through an include,
154
-     *                                  extends or any other plugin) an include, extends or any other plugin)
155
-     *
156
-     * @return ITemplate|null|false
157
-     */
158
-    public static function templateFactory(Core $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, ITemplate $parentTemplate = null);
136
+	/**
137
+	 * Returns a new template object from the given resource identifier, null if no include is
138
+	 * possible (resource not found), or false if include is not permitted by this resource type.
139
+	 * this method should also check if $dwoo->getSecurityPolicy() is null or not and do the
140
+	 * necessary permission checks if required, if the security policy prevents the template
141
+	 * generation it should throw a new Security\Exception with a relevant message
142
+	 *
143
+	 * @param mixed     $resourceId     the resource identifier
144
+	 * @param int       $cacheTime      duration of the cache validity for this template, if null it defaults to the
145
+	 *                                  Dwoo instance that will render this template if null it defaults to the Dwoo
146
+	 *                                  instance that will render this template
147
+	 * @param string    $cacheId        the unique cache identifier of this page or anything else that makes this
148
+	 *                                  template's content unique, if null it defaults to the current url makes this
149
+	 *                                  template's content unique, if null it defaults to the current url
150
+	 * @param string    $compileId      the unique compiled identifier, which is used to distinguish this template from
151
+	 *                                  others, if null it defaults to the filename+bits of the path template from
152
+	 *                                  others, if null it defaults to the filename+bits of the path
153
+	 * @param ITemplate $parentTemplate the template that is requesting a new template object (through an include,
154
+	 *                                  extends or any other plugin) an include, extends or any other plugin)
155
+	 *
156
+	 * @return ITemplate|null|false
157
+	 */
158
+	public static function templateFactory(Core $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, ITemplate $parentTemplate = null);
159 159
 }
Please login to merge, or discard this patch.
lib/Dwoo/Core.php 1 patch
Indentation   +1671 added lines, -1671 removed lines patch added patch discarded remove patch
@@ -44,1683 +44,1683 @@
 block discarded – undo
44 44
  */
45 45
 class Core
46 46
 {
47
-    /**
48
-     * Current version number.
49
-     *
50
-     * @var string
51
-     */
52
-    const VERSION = '1.3.0';
53
-
54
-    /**
55
-     * Unique number of this dwoo release, based on version number.
56
-     * this can be used by templates classes to check whether the compiled template
57
-     * has been compiled before this release or not, so that old templates are
58
-     * recompiled automatically when Dwoo is updated
59
-     */
60
-    const RELEASE_TAG = 130;
61
-
62
-    /**
63
-     * Constants that represents all plugin types
64
-     * these are bitwise-operation-safe values to allow multiple types
65
-     * on a single plugin
66
-     *
67
-     * @var int
68
-     */
69
-    const CLASS_PLUGIN      = 1;
70
-    const FUNC_PLUGIN       = 2;
71
-    const NATIVE_PLUGIN     = 4;
72
-    const BLOCK_PLUGIN      = 8;
73
-    const COMPILABLE_PLUGIN = 16;
74
-    const CUSTOM_PLUGIN     = 32;
75
-    const SMARTY_MODIFIER   = 64;
76
-    const SMARTY_BLOCK      = 128;
77
-    const SMARTY_FUNCTION   = 256;
78
-    const PROXY_PLUGIN      = 512;
79
-    const TEMPLATE_PLUGIN   = 1024;
80
-
81
-    /**
82
-     * Constant to default namespaces of builtin plugins
83
-     *
84
-     * @var string
85
-     */
86
-    const NAMESPACE_PLUGINS_BLOCKS     = 'Dwoo\Plugins\Blocks\\';
87
-    const NAMESPACE_PLUGINS_FILTERS    = 'Dwoo\Plugins\Filters\\';
88
-    const NAMESPACE_PLUGINS_FUNCTIONS  = 'Dwoo\Plugins\Functions\\';
89
-    const NAMESPACE_PLUGINS_HELPERS    = 'Dwoo\Plugins\Helpers\\';
90
-    const NAMESPACE_PLUGINS_PROCESSORS = 'Dwoo\Plugins\Processors\\';
91
-
92
-    /**
93
-     * Character set of the template, used by string manipulation plugins.
94
-     * it must be lowercase, but setCharset() will take care of that
95
-     *
96
-     * @see setCharset
97
-     * @see getCharset
98
-     * @var string
99
-     */
100
-    protected $charset = 'UTF-8';
101
-
102
-    /**
103
-     * Global variables that are accessible through $dwoo.* in the templates.
104
-     * default values include:
105
-     * $dwoo.version - current version number
106
-     * $dwoo.ad - a Powered by Dwoo link pointing to dwoo.org
107
-     * $dwoo.now - the current time
108
-     * $dwoo.template - the current template filename
109
-     * $dwoo.charset - the character set used by the template
110
-     * on top of that, foreach and other plugins can store special values in there,
111
-     * see their documentation for more details.
112
-     *
113
-     * @var array
114
-     */
115
-    public $globals;
116
-
117
-    /**
118
-     * Directory where the compiled templates are stored.
119
-     * defaults to DWOO_COMPILEDIR (= dwoo_dir/compiled by default)
120
-     *
121
-     * @var string
122
-     */
123
-    protected $compileDir;
124
-
125
-    /**
126
-     * Directory where the cached templates are stored.
127
-     * defaults to DWOO_CACHEDIR (= dwoo_dir/cache by default)
128
-     *
129
-     * @var string
130
-     */
131
-    protected $cacheDir;
132
-
133
-    /**
134
-     * Defines how long (in seconds) the cached files must remain valid.
135
-     * can be overriden on a per-template basis
136
-     * -1 = never delete
137
-     * 0 = disabled
138
-     * >0 = duration in seconds
139
-     *
140
-     * @var int
141
-     */
142
-    protected $cacheTime = 0;
143
-
144
-    /**
145
-     * Security policy object.
146
-     *
147
-     * @var SecurityPolicy
148
-     */
149
-    protected $securityPolicy = null;
150
-
151
-    /**
152
-     * Stores the custom plugins callbacks.
153
-     *
154
-     * @see addPlugin
155
-     * @see removePlugin
156
-     * @var array
157
-     */
158
-    protected $plugins = array();
159
-
160
-    /**
161
-     * Stores the filter callbacks.
162
-     *
163
-     * @see addFilter
164
-     * @see removeFilter
165
-     * @var array
166
-     */
167
-    protected $filters = array();
168
-
169
-    /**
170
-     * Stores the resource types and associated
171
-     * classes / compiler classes.
172
-     *
173
-     * @var array
174
-     */
175
-    protected $resources = array(
176
-        'file'   => array(
177
-            'class'    => 'Dwoo\Template\File',
178
-            'compiler' => null,
179
-        ),
180
-        'string' => array(
181
-            'class'    => 'Dwoo\Template\String',
182
-            'compiler' => null,
183
-        ),
184
-    );
185
-
186
-    /**
187
-     * The dwoo loader object used to load plugins by this dwoo instance.
188
-     *
189
-     * @var ILoader
190
-     */
191
-    protected $loader = null;
192
-
193
-    /**
194
-     * Currently rendered template, set to null when not-rendering.
195
-     *
196
-     * @var ITemplate
197
-     */
198
-    protected $template = null;
199
-
200
-    /**
201
-     * Stores the instances of the class plugins during template runtime.
202
-     *
203
-     * @var array
204
-     */
205
-    protected $runtimePlugins;
206
-
207
-    /**
208
-     * Stores the returned values during template runtime.
209
-     *
210
-     * @var array
211
-     */
212
-    protected $returnData;
213
-
214
-    /**
215
-     * Stores the data during template runtime.
216
-     *
217
-     * @var array
218
-     */
219
-    public $data;
220
-
221
-    /**
222
-     * Stores the current scope during template runtime.
223
-     * this should ideally not be accessed directly from outside template code
224
-     *
225
-     * @var mixed
226
-     */
227
-    public $scope;
228
-
229
-    /**
230
-     * Stores the scope tree during template runtime.
231
-     *
232
-     * @var array
233
-     */
234
-    protected $scopeTree;
235
-
236
-    /**
237
-     * Stores the block plugins stack during template runtime.
238
-     *
239
-     * @var array
240
-     */
241
-    protected $stack;
242
-
243
-    /**
244
-     * Stores the current block plugin at the top of the stack during template runtime.
245
-     *
246
-     * @var BlockPlugin
247
-     */
248
-    protected $curBlock;
249
-
250
-    /**
251
-     * Stores the output buffer during template runtime.
252
-     *
253
-     * @var string
254
-     */
255
-    protected $buffer;
256
-
257
-    /**
258
-     * Stores plugin proxy.
259
-     *
260
-     * @var IPluginProxy
261
-     */
262
-    protected $pluginProxy;
263
-
264
-    /**
265
-     * Constructor, sets the cache and compile dir to the default values if not provided.
266
-     *
267
-     * @param string $compileDir path to the compiled directory, defaults to lib/compiled
268
-     * @param string $cacheDir   path to the cache directory, defaults to lib/cache
269
-     */
270
-    public function __construct($compileDir = null, $cacheDir = null)
271
-    {
272
-        if ($compileDir !== null) {
273
-            $this->setCompileDir($compileDir);
274
-        }
275
-        if ($cacheDir !== null) {
276
-            $this->setCacheDir($cacheDir);
277
-        }
278
-        $this->initGlobals();
279
-    }
280
-
281
-    /**
282
-     * Resets some runtime variables to allow a cloned object to be used to render sub-templates.
283
-     *
284
-     * @return void
285
-     */
286
-    public function __clone()
287
-    {
288
-        $this->template = null;
289
-        unset($this->data);
290
-        unset($this->returnData);
291
-    }
292
-
293
-    /**
294
-     * Returns the given template rendered using the provided data and optional compiler.
295
-     *
296
-     * @param mixed     $_tpl      template, can either be a ITemplate object (i.e. TemplateFile), a
297
-     *                             valid path to a template, or a template as a string it is recommended to
298
-     *                             provide a ITemplate as it will probably make things faster, especially if
299
-     *                             you render a template multiple times
300
-     * @param mixed     $data      the data to use, can either be a IDataProvider object (i.e. Data) or
301
-     *                             an associative array. if you're rendering the template from cache, it can be
302
-     *                             left null
303
-     * @param ICompiler $_compiler the compiler that must be used to compile the template, if left empty a default
304
-     *                             Compiler will be used
305
-     *
306
-     * @return string|void or the template output if $output is false
307
-     * @throws Exception
308
-     */
309
-    public function get($_tpl, $data = array(), $_compiler = null)
310
-    {
311
-        // a render call came from within a template, so we need a new dwoo instance in order to avoid breaking this one
312
-        if ($this->template instanceof ITemplate) {
313
-            $clone = clone $this;
314
-
315
-            return $clone->get($_tpl, $data, $_compiler);
316
-        }
317
-
318
-        // auto-create template if required
319
-        if ($_tpl instanceof ITemplate) {
320
-            // valid, skip
321
-        } elseif (is_string($_tpl) && file_exists($_tpl)) {
322
-            $_tpl = new TemplateFile($_tpl);
323
-        } else {
324
-            throw new Exception(
325
-                'Dwoo->get\'s first argument must be a ITemplate (i.e. TemplateFile) or 
47
+	/**
48
+	 * Current version number.
49
+	 *
50
+	 * @var string
51
+	 */
52
+	const VERSION = '1.3.0';
53
+
54
+	/**
55
+	 * Unique number of this dwoo release, based on version number.
56
+	 * this can be used by templates classes to check whether the compiled template
57
+	 * has been compiled before this release or not, so that old templates are
58
+	 * recompiled automatically when Dwoo is updated
59
+	 */
60
+	const RELEASE_TAG = 130;
61
+
62
+	/**
63
+	 * Constants that represents all plugin types
64
+	 * these are bitwise-operation-safe values to allow multiple types
65
+	 * on a single plugin
66
+	 *
67
+	 * @var int
68
+	 */
69
+	const CLASS_PLUGIN      = 1;
70
+	const FUNC_PLUGIN       = 2;
71
+	const NATIVE_PLUGIN     = 4;
72
+	const BLOCK_PLUGIN      = 8;
73
+	const COMPILABLE_PLUGIN = 16;
74
+	const CUSTOM_PLUGIN     = 32;
75
+	const SMARTY_MODIFIER   = 64;
76
+	const SMARTY_BLOCK      = 128;
77
+	const SMARTY_FUNCTION   = 256;
78
+	const PROXY_PLUGIN      = 512;
79
+	const TEMPLATE_PLUGIN   = 1024;
80
+
81
+	/**
82
+	 * Constant to default namespaces of builtin plugins
83
+	 *
84
+	 * @var string
85
+	 */
86
+	const NAMESPACE_PLUGINS_BLOCKS     = 'Dwoo\Plugins\Blocks\\';
87
+	const NAMESPACE_PLUGINS_FILTERS    = 'Dwoo\Plugins\Filters\\';
88
+	const NAMESPACE_PLUGINS_FUNCTIONS  = 'Dwoo\Plugins\Functions\\';
89
+	const NAMESPACE_PLUGINS_HELPERS    = 'Dwoo\Plugins\Helpers\\';
90
+	const NAMESPACE_PLUGINS_PROCESSORS = 'Dwoo\Plugins\Processors\\';
91
+
92
+	/**
93
+	 * Character set of the template, used by string manipulation plugins.
94
+	 * it must be lowercase, but setCharset() will take care of that
95
+	 *
96
+	 * @see setCharset
97
+	 * @see getCharset
98
+	 * @var string
99
+	 */
100
+	protected $charset = 'UTF-8';
101
+
102
+	/**
103
+	 * Global variables that are accessible through $dwoo.* in the templates.
104
+	 * default values include:
105
+	 * $dwoo.version - current version number
106
+	 * $dwoo.ad - a Powered by Dwoo link pointing to dwoo.org
107
+	 * $dwoo.now - the current time
108
+	 * $dwoo.template - the current template filename
109
+	 * $dwoo.charset - the character set used by the template
110
+	 * on top of that, foreach and other plugins can store special values in there,
111
+	 * see their documentation for more details.
112
+	 *
113
+	 * @var array
114
+	 */
115
+	public $globals;
116
+
117
+	/**
118
+	 * Directory where the compiled templates are stored.
119
+	 * defaults to DWOO_COMPILEDIR (= dwoo_dir/compiled by default)
120
+	 *
121
+	 * @var string
122
+	 */
123
+	protected $compileDir;
124
+
125
+	/**
126
+	 * Directory where the cached templates are stored.
127
+	 * defaults to DWOO_CACHEDIR (= dwoo_dir/cache by default)
128
+	 *
129
+	 * @var string
130
+	 */
131
+	protected $cacheDir;
132
+
133
+	/**
134
+	 * Defines how long (in seconds) the cached files must remain valid.
135
+	 * can be overriden on a per-template basis
136
+	 * -1 = never delete
137
+	 * 0 = disabled
138
+	 * >0 = duration in seconds
139
+	 *
140
+	 * @var int
141
+	 */
142
+	protected $cacheTime = 0;
143
+
144
+	/**
145
+	 * Security policy object.
146
+	 *
147
+	 * @var SecurityPolicy
148
+	 */
149
+	protected $securityPolicy = null;
150
+
151
+	/**
152
+	 * Stores the custom plugins callbacks.
153
+	 *
154
+	 * @see addPlugin
155
+	 * @see removePlugin
156
+	 * @var array
157
+	 */
158
+	protected $plugins = array();
159
+
160
+	/**
161
+	 * Stores the filter callbacks.
162
+	 *
163
+	 * @see addFilter
164
+	 * @see removeFilter
165
+	 * @var array
166
+	 */
167
+	protected $filters = array();
168
+
169
+	/**
170
+	 * Stores the resource types and associated
171
+	 * classes / compiler classes.
172
+	 *
173
+	 * @var array
174
+	 */
175
+	protected $resources = array(
176
+		'file'   => array(
177
+			'class'    => 'Dwoo\Template\File',
178
+			'compiler' => null,
179
+		),
180
+		'string' => array(
181
+			'class'    => 'Dwoo\Template\String',
182
+			'compiler' => null,
183
+		),
184
+	);
185
+
186
+	/**
187
+	 * The dwoo loader object used to load plugins by this dwoo instance.
188
+	 *
189
+	 * @var ILoader
190
+	 */
191
+	protected $loader = null;
192
+
193
+	/**
194
+	 * Currently rendered template, set to null when not-rendering.
195
+	 *
196
+	 * @var ITemplate
197
+	 */
198
+	protected $template = null;
199
+
200
+	/**
201
+	 * Stores the instances of the class plugins during template runtime.
202
+	 *
203
+	 * @var array
204
+	 */
205
+	protected $runtimePlugins;
206
+
207
+	/**
208
+	 * Stores the returned values during template runtime.
209
+	 *
210
+	 * @var array
211
+	 */
212
+	protected $returnData;
213
+
214
+	/**
215
+	 * Stores the data during template runtime.
216
+	 *
217
+	 * @var array
218
+	 */
219
+	public $data;
220
+
221
+	/**
222
+	 * Stores the current scope during template runtime.
223
+	 * this should ideally not be accessed directly from outside template code
224
+	 *
225
+	 * @var mixed
226
+	 */
227
+	public $scope;
228
+
229
+	/**
230
+	 * Stores the scope tree during template runtime.
231
+	 *
232
+	 * @var array
233
+	 */
234
+	protected $scopeTree;
235
+
236
+	/**
237
+	 * Stores the block plugins stack during template runtime.
238
+	 *
239
+	 * @var array
240
+	 */
241
+	protected $stack;
242
+
243
+	/**
244
+	 * Stores the current block plugin at the top of the stack during template runtime.
245
+	 *
246
+	 * @var BlockPlugin
247
+	 */
248
+	protected $curBlock;
249
+
250
+	/**
251
+	 * Stores the output buffer during template runtime.
252
+	 *
253
+	 * @var string
254
+	 */
255
+	protected $buffer;
256
+
257
+	/**
258
+	 * Stores plugin proxy.
259
+	 *
260
+	 * @var IPluginProxy
261
+	 */
262
+	protected $pluginProxy;
263
+
264
+	/**
265
+	 * Constructor, sets the cache and compile dir to the default values if not provided.
266
+	 *
267
+	 * @param string $compileDir path to the compiled directory, defaults to lib/compiled
268
+	 * @param string $cacheDir   path to the cache directory, defaults to lib/cache
269
+	 */
270
+	public function __construct($compileDir = null, $cacheDir = null)
271
+	{
272
+		if ($compileDir !== null) {
273
+			$this->setCompileDir($compileDir);
274
+		}
275
+		if ($cacheDir !== null) {
276
+			$this->setCacheDir($cacheDir);
277
+		}
278
+		$this->initGlobals();
279
+	}
280
+
281
+	/**
282
+	 * Resets some runtime variables to allow a cloned object to be used to render sub-templates.
283
+	 *
284
+	 * @return void
285
+	 */
286
+	public function __clone()
287
+	{
288
+		$this->template = null;
289
+		unset($this->data);
290
+		unset($this->returnData);
291
+	}
292
+
293
+	/**
294
+	 * Returns the given template rendered using the provided data and optional compiler.
295
+	 *
296
+	 * @param mixed     $_tpl      template, can either be a ITemplate object (i.e. TemplateFile), a
297
+	 *                             valid path to a template, or a template as a string it is recommended to
298
+	 *                             provide a ITemplate as it will probably make things faster, especially if
299
+	 *                             you render a template multiple times
300
+	 * @param mixed     $data      the data to use, can either be a IDataProvider object (i.e. Data) or
301
+	 *                             an associative array. if you're rendering the template from cache, it can be
302
+	 *                             left null
303
+	 * @param ICompiler $_compiler the compiler that must be used to compile the template, if left empty a default
304
+	 *                             Compiler will be used
305
+	 *
306
+	 * @return string|void or the template output if $output is false
307
+	 * @throws Exception
308
+	 */
309
+	public function get($_tpl, $data = array(), $_compiler = null)
310
+	{
311
+		// a render call came from within a template, so we need a new dwoo instance in order to avoid breaking this one
312
+		if ($this->template instanceof ITemplate) {
313
+			$clone = clone $this;
314
+
315
+			return $clone->get($_tpl, $data, $_compiler);
316
+		}
317
+
318
+		// auto-create template if required
319
+		if ($_tpl instanceof ITemplate) {
320
+			// valid, skip
321
+		} elseif (is_string($_tpl) && file_exists($_tpl)) {
322
+			$_tpl = new TemplateFile($_tpl);
323
+		} else {
324
+			throw new Exception(
325
+				'Dwoo->get\'s first argument must be a ITemplate (i.e. TemplateFile) or 
326 326
             a valid path to a template file', E_USER_NOTICE
327
-            );
328
-        }
329
-
330
-        // save the current template, enters render mode at the same time
331
-        // if another rendering is requested it will be proxied to a new Core(instance
332
-        $this->template = $_tpl;
333
-
334
-        // load data
335
-        if ($data instanceof IDataProvider) {
336
-            $this->data = $data->getData();
337
-        } elseif (is_array($data)) {
338
-            $this->data = $data;
339
-        } elseif ($data instanceof ArrayAccess) {
340
-            $this->data = $data;
341
-        } else {
342
-            throw new Exception(
343
-                'Dwoo->get/Dwoo->output\'s data argument must be a IDataProvider object (i.e. Data) or
327
+			);
328
+		}
329
+
330
+		// save the current template, enters render mode at the same time
331
+		// if another rendering is requested it will be proxied to a new Core(instance
332
+		$this->template = $_tpl;
333
+
334
+		// load data
335
+		if ($data instanceof IDataProvider) {
336
+			$this->data = $data->getData();
337
+		} elseif (is_array($data)) {
338
+			$this->data = $data;
339
+		} elseif ($data instanceof ArrayAccess) {
340
+			$this->data = $data;
341
+		} else {
342
+			throw new Exception(
343
+				'Dwoo->get/Dwoo->output\'s data argument must be a IDataProvider object (i.e. Data) or
344 344
             an associative array', E_USER_NOTICE
345
-            );
346
-        }
347
-
348
-        $this->globals['template'] = $_tpl->getName();
349
-        $this->initRuntimeVars($_tpl);
350
-
351
-        // try to get cached template
352
-        $file        = $_tpl->getCachedTemplate($this);
353
-        $doCache     = $file === true;
354
-        $cacheLoaded = is_string($file);
355
-
356
-        if ($cacheLoaded === true) {
357
-            // cache is present, run it
358
-            ob_start();
359
-            include $file;
360
-            $this->template = null;
361
-
362
-            return ob_get_clean();
363
-        } else {
364
-            $dynamicId = uniqid();
365
-
366
-            // render template
367
-            $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
368
-            $out              = include $compiledTemplate;
369
-
370
-            // template returned false so it needs to be recompiled
371
-            if ($out === false) {
372
-                $_tpl->forceCompilation();
373
-                $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
374
-                $out              = include $compiledTemplate;
375
-            }
376
-
377
-            if ($doCache === true) {
378
-                $out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php /*' . $dynamicId . '*/ echo \'$1\'; ?>', $out);
379
-                if (!class_exists(self::NAMESPACE_PLUGINS_BLOCKS . 'PluginDynamic')) {
380
-                    $this->getLoader()->loadPlugin('PluginDynamic');
381
-                }
382
-                $out = PluginDynamic::unescape($out, $dynamicId, $compiledTemplate);
383
-            }
384
-
385
-            // process filters
386
-            foreach ($this->filters as $filter) {
387
-                if (is_array($filter) && $filter[0] instanceof Filter) {
388
-                    $out = call_user_func($filter, $out);
389
-                } else {
390
-                    $out = call_user_func($filter, $this, $out);
391
-                }
392
-            }
393
-
394
-            if ($doCache === true) {
395
-                // building cache
396
-                $file = $_tpl->cache($this, $out);
397
-
398
-                // run it from the cache to be sure dynamics are rendered
399
-                ob_start();
400
-                include $file;
401
-                // exit render mode
402
-                $this->template = null;
403
-
404
-                return ob_get_clean();
405
-            } else {
406
-                // no need to build cache
407
-                // exit render mode
408
-                $this->template = null;
409
-
410
-                return $out;
411
-            }
412
-        }
413
-    }
414
-
415
-    /**
416
-     * Re-initializes the globals array before each template run.
417
-     * this method is only callede once when the Dwoo object is created
418
-     *
419
-     * @return void
420
-     */
421
-    protected function initGlobals()
422
-    {
423
-        $this->globals = array(
424
-            'version' => self::VERSION,
425
-            'ad'      => '<a href="http://dwoo.org/">Powered by Dwoo</a>',
426
-            'now'     => $_SERVER['REQUEST_TIME'],
427
-            'charset' => $this->charset,
428
-        );
429
-    }
430
-
431
-    /**
432
-     * Re-initializes the runtime variables before each template run.
433
-     * override this method to inject data in the globals array if needed, this
434
-     * method is called before each template execution
435
-     *
436
-     * @param ITemplate $tpl the template that is going to be rendered
437
-     *
438
-     * @return void
439
-     */
440
-    protected function initRuntimeVars(ITemplate $tpl)
441
-    {
442
-        $this->runtimePlugins = array();
443
-        $this->scope          = &$this->data;
444
-        $this->scopeTree      = array();
445
-        $this->stack          = array();
446
-        $this->curBlock       = null;
447
-        $this->buffer         = '';
448
-        $this->returnData     = array();
449
-    }
450
-
451
-    /**
452
-     * Adds a custom plugin that is not in one of the plugin directories.
453
-     *
454
-     * @param string   $name       the plugin name to be used in the templates
455
-     * @param callback $callback   the plugin callback, either a function name,
456
-     *                             a class name or an array containing an object
457
-     *                             or class name and a method name
458
-     * @param bool     $compilable if set to true, the plugin is assumed to be compilable
459
-     *
460
-     * @return void
461
-     * @throws Exception
462
-     */
463
-    public function addPlugin($name, $callback, $compilable = false)
464
-    {
465
-        $compilable = $compilable ? self::COMPILABLE_PLUGIN : 0;
466
-        if (is_array($callback)) {
467
-            if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo\Block\Plugin')) {
468
-                $this->plugins[$name] = array(
469
-                    'type'     => self::BLOCK_PLUGIN | $compilable,
470
-                    'callback' => $callback,
471
-                    'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0])
472
-                );
473
-            } else {
474
-                $this->plugins[$name] = array(
475
-                    'type'     => self::CLASS_PLUGIN | $compilable,
476
-                    'callback' => $callback,
477
-                    'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0]),
478
-                    'function' => $callback[1]
479
-                );
480
-            }
481
-        } elseif (is_string($callback)) {
482
-            if (class_exists($callback)) {
483
-                if (is_subclass_of($callback, 'Dwoo\Block\Plugin')) {
484
-                    $this->plugins[$name] = array(
485
-                        'type'     => self::BLOCK_PLUGIN | $compilable,
486
-                        'callback' => $callback,
487
-                        'class'    => $callback
488
-                    );
489
-                } else {
490
-                    $this->plugins[$name] = array(
491
-                        'type'     => self::CLASS_PLUGIN | $compilable,
492
-                        'callback' => $callback,
493
-                        'class'    => $callback,
494
-                        'function' => ($compilable ? 'compile' : 'process')
495
-                    );
496
-                }
497
-            } elseif (function_exists($callback)) {
498
-                $this->plugins[$name] = array(
499
-                    'type'     => self::FUNC_PLUGIN | $compilable,
500
-                    'callback' => $callback
501
-                );
502
-            } else {
503
-                throw new Exception(
504
-                    'Callback could not be processed correctly, please check that the function/class 
345
+			);
346
+		}
347
+
348
+		$this->globals['template'] = $_tpl->getName();
349
+		$this->initRuntimeVars($_tpl);
350
+
351
+		// try to get cached template
352
+		$file        = $_tpl->getCachedTemplate($this);
353
+		$doCache     = $file === true;
354
+		$cacheLoaded = is_string($file);
355
+
356
+		if ($cacheLoaded === true) {
357
+			// cache is present, run it
358
+			ob_start();
359
+			include $file;
360
+			$this->template = null;
361
+
362
+			return ob_get_clean();
363
+		} else {
364
+			$dynamicId = uniqid();
365
+
366
+			// render template
367
+			$compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
368
+			$out              = include $compiledTemplate;
369
+
370
+			// template returned false so it needs to be recompiled
371
+			if ($out === false) {
372
+				$_tpl->forceCompilation();
373
+				$compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
374
+				$out              = include $compiledTemplate;
375
+			}
376
+
377
+			if ($doCache === true) {
378
+				$out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php /*' . $dynamicId . '*/ echo \'$1\'; ?>', $out);
379
+				if (!class_exists(self::NAMESPACE_PLUGINS_BLOCKS . 'PluginDynamic')) {
380
+					$this->getLoader()->loadPlugin('PluginDynamic');
381
+				}
382
+				$out = PluginDynamic::unescape($out, $dynamicId, $compiledTemplate);
383
+			}
384
+
385
+			// process filters
386
+			foreach ($this->filters as $filter) {
387
+				if (is_array($filter) && $filter[0] instanceof Filter) {
388
+					$out = call_user_func($filter, $out);
389
+				} else {
390
+					$out = call_user_func($filter, $this, $out);
391
+				}
392
+			}
393
+
394
+			if ($doCache === true) {
395
+				// building cache
396
+				$file = $_tpl->cache($this, $out);
397
+
398
+				// run it from the cache to be sure dynamics are rendered
399
+				ob_start();
400
+				include $file;
401
+				// exit render mode
402
+				$this->template = null;
403
+
404
+				return ob_get_clean();
405
+			} else {
406
+				// no need to build cache
407
+				// exit render mode
408
+				$this->template = null;
409
+
410
+				return $out;
411
+			}
412
+		}
413
+	}
414
+
415
+	/**
416
+	 * Re-initializes the globals array before each template run.
417
+	 * this method is only callede once when the Dwoo object is created
418
+	 *
419
+	 * @return void
420
+	 */
421
+	protected function initGlobals()
422
+	{
423
+		$this->globals = array(
424
+			'version' => self::VERSION,
425
+			'ad'      => '<a href="http://dwoo.org/">Powered by Dwoo</a>',
426
+			'now'     => $_SERVER['REQUEST_TIME'],
427
+			'charset' => $this->charset,
428
+		);
429
+	}
430
+
431
+	/**
432
+	 * Re-initializes the runtime variables before each template run.
433
+	 * override this method to inject data in the globals array if needed, this
434
+	 * method is called before each template execution
435
+	 *
436
+	 * @param ITemplate $tpl the template that is going to be rendered
437
+	 *
438
+	 * @return void
439
+	 */
440
+	protected function initRuntimeVars(ITemplate $tpl)
441
+	{
442
+		$this->runtimePlugins = array();
443
+		$this->scope          = &$this->data;
444
+		$this->scopeTree      = array();
445
+		$this->stack          = array();
446
+		$this->curBlock       = null;
447
+		$this->buffer         = '';
448
+		$this->returnData     = array();
449
+	}
450
+
451
+	/**
452
+	 * Adds a custom plugin that is not in one of the plugin directories.
453
+	 *
454
+	 * @param string   $name       the plugin name to be used in the templates
455
+	 * @param callback $callback   the plugin callback, either a function name,
456
+	 *                             a class name or an array containing an object
457
+	 *                             or class name and a method name
458
+	 * @param bool     $compilable if set to true, the plugin is assumed to be compilable
459
+	 *
460
+	 * @return void
461
+	 * @throws Exception
462
+	 */
463
+	public function addPlugin($name, $callback, $compilable = false)
464
+	{
465
+		$compilable = $compilable ? self::COMPILABLE_PLUGIN : 0;
466
+		if (is_array($callback)) {
467
+			if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo\Block\Plugin')) {
468
+				$this->plugins[$name] = array(
469
+					'type'     => self::BLOCK_PLUGIN | $compilable,
470
+					'callback' => $callback,
471
+					'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0])
472
+				);
473
+			} else {
474
+				$this->plugins[$name] = array(
475
+					'type'     => self::CLASS_PLUGIN | $compilable,
476
+					'callback' => $callback,
477
+					'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0]),
478
+					'function' => $callback[1]
479
+				);
480
+			}
481
+		} elseif (is_string($callback)) {
482
+			if (class_exists($callback)) {
483
+				if (is_subclass_of($callback, 'Dwoo\Block\Plugin')) {
484
+					$this->plugins[$name] = array(
485
+						'type'     => self::BLOCK_PLUGIN | $compilable,
486
+						'callback' => $callback,
487
+						'class'    => $callback
488
+					);
489
+				} else {
490
+					$this->plugins[$name] = array(
491
+						'type'     => self::CLASS_PLUGIN | $compilable,
492
+						'callback' => $callback,
493
+						'class'    => $callback,
494
+						'function' => ($compilable ? 'compile' : 'process')
495
+					);
496
+				}
497
+			} elseif (function_exists($callback)) {
498
+				$this->plugins[$name] = array(
499
+					'type'     => self::FUNC_PLUGIN | $compilable,
500
+					'callback' => $callback
501
+				);
502
+			} else {
503
+				throw new Exception(
504
+					'Callback could not be processed correctly, please check that the function/class 
505 505
                 you used exists'
506
-                );
507
-            }
508
-        } elseif ($callback instanceof Closure) {
509
-            $this->plugins[$name] = array(
510
-                'type'     => self::FUNC_PLUGIN | $compilable,
511
-                'callback' => $callback
512
-            );
513
-        } else {
514
-            throw new Exception(
515
-                'Callback could not be processed correctly, please check that the function/class you 
506
+				);
507
+			}
508
+		} elseif ($callback instanceof Closure) {
509
+			$this->plugins[$name] = array(
510
+				'type'     => self::FUNC_PLUGIN | $compilable,
511
+				'callback' => $callback
512
+			);
513
+		} else {
514
+			throw new Exception(
515
+				'Callback could not be processed correctly, please check that the function/class you 
516 516
             used exists'
517
-            );
518
-        }
519
-    }
520
-
521
-    /**
522
-     * Removes a custom plugin.
523
-     *
524
-     * @param string $name the plugin name
525
-     *
526
-     * @return void
527
-     */
528
-    public function removePlugin($name)
529
-    {
530
-        if (isset($this->plugins[$name])) {
531
-            unset($this->plugins[$name]);
532
-        }
533
-    }
534
-
535
-    /**
536
-     * Adds a filter to this Dwoo instance, it will be used to filter the output of all the templates rendered by this
537
-     * instance.
538
-     *
539
-     * @param mixed $callback a callback or a filter name if it is autoloaded from a plugin directory
540
-     * @param bool  $autoload if true, the first parameter must be a filter name from one of the plugin directories
541
-     *
542
-     * @return void
543
-     * @throws Exception
544
-     */
545
-    public function addFilter($callback, $autoload = false)
546
-    {
547
-        if ($autoload) {
548
-            $class = self::NAMESPACE_PLUGINS_FILTERS . self::toCamelCase($callback);
549
-            if (!class_exists($class) && !function_exists($class)) {
550
-                try {
551
-                    $this->getLoader()->loadPlugin($callback);
552
-                }
553
-                catch (Exception $e) {
554
-                    if (strstr($callback, self::NAMESPACE_PLUGINS_FILTERS)) {
555
-                        throw new Exception(
556
-                            'Wrong filter name : ' . $callback . ', the "Dwoo_Filter_" prefix should 
517
+			);
518
+		}
519
+	}
520
+
521
+	/**
522
+	 * Removes a custom plugin.
523
+	 *
524
+	 * @param string $name the plugin name
525
+	 *
526
+	 * @return void
527
+	 */
528
+	public function removePlugin($name)
529
+	{
530
+		if (isset($this->plugins[$name])) {
531
+			unset($this->plugins[$name]);
532
+		}
533
+	}
534
+
535
+	/**
536
+	 * Adds a filter to this Dwoo instance, it will be used to filter the output of all the templates rendered by this
537
+	 * instance.
538
+	 *
539
+	 * @param mixed $callback a callback or a filter name if it is autoloaded from a plugin directory
540
+	 * @param bool  $autoload if true, the first parameter must be a filter name from one of the plugin directories
541
+	 *
542
+	 * @return void
543
+	 * @throws Exception
544
+	 */
545
+	public function addFilter($callback, $autoload = false)
546
+	{
547
+		if ($autoload) {
548
+			$class = self::NAMESPACE_PLUGINS_FILTERS . self::toCamelCase($callback);
549
+			if (!class_exists($class) && !function_exists($class)) {
550
+				try {
551
+					$this->getLoader()->loadPlugin($callback);
552
+				}
553
+				catch (Exception $e) {
554
+					if (strstr($callback, self::NAMESPACE_PLUGINS_FILTERS)) {
555
+						throw new Exception(
556
+							'Wrong filter name : ' . $callback . ', the "Dwoo_Filter_" prefix should 
557 557
                         not be used, please only use "' . str_replace('Dwoo_Filter_', '', $callback) . '"'
558
-                        );
559
-                    } else {
560
-                        throw new Exception(
561
-                            'Wrong filter name : ' . $callback . ', when using autoload the filter must
558
+						);
559
+					} else {
560
+						throw new Exception(
561
+							'Wrong filter name : ' . $callback . ', when using autoload the filter must
562 562
                          be in one of your plugin dir as "name.php" containig a class or function named
563 563
                          "Dwoo_Filter_name"'
564
-                        );
565
-                    }
566
-                }
567
-            }
568
-
569
-            if (class_exists($class)) {
570
-                $callback = array(new $class($this), 'process');
571
-            } elseif (function_exists($class)) {
572
-                $callback = $class;
573
-            } else {
574
-                throw new Exception(
575
-                    'Wrong filter name : ' . $callback . ', when using autoload the filter must be in
564
+						);
565
+					}
566
+				}
567
+			}
568
+
569
+			if (class_exists($class)) {
570
+				$callback = array(new $class($this), 'process');
571
+			} elseif (function_exists($class)) {
572
+				$callback = $class;
573
+			} else {
574
+				throw new Exception(
575
+					'Wrong filter name : ' . $callback . ', when using autoload the filter must be in
576 576
                 one of your plugin dir as "name.php" containig a class or function named "Dwoo_Filter_name"'
577
-                );
578
-            }
579
-
580
-            $this->filters[] = $callback;
581
-        } else {
582
-            $this->filters[] = $callback;
583
-        }
584
-    }
585
-
586
-    /**
587
-     * Removes a filter.
588
-     *
589
-     * @param mixed $callback callback or filter name if it was autoloaded
590
-     *
591
-     * @return void
592
-     */
593
-    public function removeFilter($callback)
594
-    {
595
-        if (($index = array_search(self::NAMESPACE_PLUGINS_FILTERS. 'Filter' . self::toCamelCase($callback), $this->filters,
596
-                true)) !==
597
-            false) {
598
-            unset($this->filters[$index]);
599
-        } elseif (($index = array_search($callback, $this->filters, true)) !== false) {
600
-            unset($this->filters[$index]);
601
-        } else {
602
-            $class = self::NAMESPACE_PLUGINS_FILTERS . 'Filter' . $callback;
603
-            foreach ($this->filters as $index => $filter) {
604
-                if (is_array($filter) && $filter[0] instanceof $class) {
605
-                    unset($this->filters[$index]);
606
-                    break;
607
-                }
608
-            }
609
-        }
610
-    }
611
-
612
-    /**
613
-     * Adds a resource or overrides a default one.
614
-     *
615
-     * @param string   $name            the resource name
616
-     * @param string   $class           the resource class (which must implement ITemplate)
617
-     * @param callback $compilerFactory the compiler factory callback, a function that must return a compiler instance
618
-     *                                  used to compile this resource, if none is provided. by default it will produce
619
-     *                                  a Compiler object
620
-     *
621
-     * @return void
622
-     * @throws Exception
623
-     */
624
-    public function addResource($name, $class, $compilerFactory = null)
625
-    {
626
-        if (strlen($name) < 2) {
627
-            throw new Exception('Resource names must be at least two-character long to avoid conflicts with Windows paths');
628
-        }
629
-
630
-        if (!class_exists($class)) {
631
-            throw new Exception('Resource class does not exist');
632
-        }
633
-
634
-        $interfaces = class_implements($class);
635
-        if (in_array('Dwoo\ITemplate', $interfaces) === false) {
636
-            throw new Exception('Resource class must implement ITemplate');
637
-        }
638
-
639
-        $this->resources[$name] = array(
640
-            'class'    => $class,
641
-            'compiler' => $compilerFactory
642
-        );
643
-    }
644
-
645
-    /**
646
-     * Removes a custom resource.
647
-     *
648
-     * @param string $name the resource name
649
-     *
650
-     * @return void
651
-     */
652
-    public function removeResource($name)
653
-    {
654
-        unset($this->resources[$name]);
655
-        if ($name === 'file') {
656
-            $this->resources['file'] = array(
657
-                'class'    => 'Dwoo\Template\File',
658
-                'compiler' => null
659
-            );
660
-        }
661
-    }
662
-
663
-    /**
664
-     * Sets the loader object to use to load plugins.
665
-     *
666
-     * @param ILoader $loader loader
667
-     *
668
-     * @return void
669
-     */
670
-    public function setLoader(ILoader $loader)
671
-    {
672
-        $this->loader = $loader;
673
-    }
674
-
675
-    /**
676
-     * Returns the current loader object or a default one if none is currently found.
677
-     *
678
-     * @return ILoader|Loader
679
-     */
680
-    public function getLoader()
681
-    {
682
-        if ($this->loader === null) {
683
-            $this->loader = new Loader($this->getCompileDir());
684
-        }
685
-
686
-        return $this->loader;
687
-    }
688
-
689
-    /**
690
-     * Returns the custom plugins loaded.
691
-     * Used by the ITemplate classes to pass the custom plugins to their ICompiler instance.
692
-     *
693
-     * @return array
694
-     */
695
-    public function getCustomPlugins()
696
-    {
697
-        return $this->plugins;
698
-    }
699
-
700
-    /**
701
-     * Return a specified custom plugin loaded by his name.
702
-     * Used by the compiler, for executing a Closure.
703
-     *
704
-     * @param string $name
705
-     *
706
-     * @return mixed|null
707
-     */
708
-    public function getCustomPlugin($name)
709
-    {
710
-        if (isset($this->plugins[$name])) {
711
-            return $this->plugins[$name]['callback'];
712
-        }
713
-
714
-        return null;
715
-    }
716
-
717
-    /**
718
-     * Returns the cache directory with a trailing DIRECTORY_SEPARATOR.
719
-     *
720
-     * @return string
721
-     */
722
-    public function getCacheDir()
723
-    {
724
-        if ($this->cacheDir === null) {
725
-            $this->setCacheDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR);
726
-        }
727
-
728
-        return $this->cacheDir;
729
-    }
730
-
731
-    /**
732
-     * Sets the cache directory and automatically appends a DIRECTORY_SEPARATOR.
733
-     *
734
-     * @param string $dir the cache directory
735
-     *
736
-     * @return void
737
-     * @throws Exception
738
-     */
739
-    public function setCacheDir($dir)
740
-    {
741
-        $this->cacheDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
742
-        if (is_writable($this->cacheDir) === false) {
743
-            throw new Exception('The cache directory must be writable, chmod "' . $this->cacheDir . '" to make it writable');
744
-        }
745
-    }
746
-
747
-    /**
748
-     * Returns the compile directory with a trailing DIRECTORY_SEPARATOR.
749
-     *
750
-     * @return string
751
-     */
752
-    public function getCompileDir()
753
-    {
754
-        if ($this->compileDir === null) {
755
-            $this->setCompileDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'compiled' . DIRECTORY_SEPARATOR);
756
-        }
757
-
758
-        return $this->compileDir;
759
-    }
760
-
761
-    /**
762
-     * Sets the compile directory and automatically appends a DIRECTORY_SEPARATOR.
763
-     *
764
-     * @param string $dir the compile directory
765
-     *
766
-     * @return void
767
-     * @throws Exception
768
-     */
769
-    public function setCompileDir($dir)
770
-    {
771
-        $this->compileDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
772
-        if (is_writable($this->compileDir) === false) {
773
-            throw new Exception('The compile directory must be writable, chmod "' . $this->compileDir . '" to make it writable');
774
-        }
775
-    }
776
-
777
-    /**
778
-     * Returns the default cache time that is used with templates that do not have a cache time set.
779
-     *
780
-     * @return int the duration in seconds
781
-     */
782
-    public function getCacheTime()
783
-    {
784
-        return $this->cacheTime;
785
-    }
786
-
787
-    /**
788
-     * Sets the default cache time to use with templates that do not have a cache time set.
789
-     *
790
-     * @param int $seconds the duration in seconds
791
-     *
792
-     * @return void
793
-     */
794
-    public function setCacheTime($seconds)
795
-    {
796
-        $this->cacheTime = (int)$seconds;
797
-    }
798
-
799
-    /**
800
-     * Returns the character set used by the string manipulation plugins.
801
-     * the charset is automatically lowercased
802
-     *
803
-     * @return string
804
-     */
805
-    public function getCharset()
806
-    {
807
-        return $this->charset;
808
-    }
809
-
810
-    /**
811
-     * Sets the character set used by the string manipulation plugins.
812
-     * the charset will be automatically lowercased
813
-     *
814
-     * @param string $charset the character set
815
-     *
816
-     * @return void
817
-     */
818
-    public function setCharset($charset)
819
-    {
820
-        $this->charset = strtolower((string)$charset);
821
-    }
822
-
823
-    /**
824
-     * Returns the current template being rendered, when applicable, or null.
825
-     *
826
-     * @return ITemplate|null
827
-     */
828
-    public function getTemplate()
829
-    {
830
-        return $this->template;
831
-    }
832
-
833
-    /**
834
-     * Sets the current template being rendered.
835
-     *
836
-     * @param ITemplate $tpl template object
837
-     *
838
-     * @return void
839
-     */
840
-    public function setTemplate(ITemplate $tpl)
841
-    {
842
-        $this->template = $tpl;
843
-    }
844
-
845
-    /**
846
-     * Sets the default compiler factory function for the given resource name.
847
-     * a compiler factory must return a ICompiler object pre-configured to fit your needs
848
-     *
849
-     * @param string   $resourceName    the resource name (i.e. file, string)
850
-     * @param callback $compilerFactory the compiler factory callback
851
-     *
852
-     * @return void
853
-     */
854
-    public function setDefaultCompilerFactory($resourceName, $compilerFactory)
855
-    {
856
-        $this->resources[$resourceName]['compiler'] = $compilerFactory;
857
-    }
858
-
859
-    /**
860
-     * Returns the default compiler factory function for the given resource name.
861
-     *
862
-     * @param string $resourceName the resource name
863
-     *
864
-     * @return callback the compiler factory callback
865
-     */
866
-    public function getDefaultCompilerFactory($resourceName)
867
-    {
868
-        return $this->resources[$resourceName]['compiler'];
869
-    }
870
-
871
-    /**
872
-     * Sets the security policy object to enforce some php security settings.
873
-     * use this if untrusted persons can modify templates
874
-     *
875
-     * @param SecurityPolicy $policy the security policy object
876
-     *
877
-     * @return void
878
-     */
879
-    public function setSecurityPolicy(SecurityPolicy $policy = null)
880
-    {
881
-        $this->securityPolicy = $policy;
882
-    }
883
-
884
-    /**
885
-     * Returns the current security policy object or null by default.
886
-     *
887
-     * @return SecurityPolicy|null the security policy object if any
888
-     */
889
-    public function getSecurityPolicy()
890
-    {
891
-        return $this->securityPolicy;
892
-    }
893
-
894
-    /**
895
-     * Sets the object that must be used as a plugin proxy when plugin can't be found
896
-     * by dwoo's loader.
897
-     *
898
-     * @param IPluginProxy $pluginProxy the proxy object
899
-     *
900
-     * @return void
901
-     */
902
-    public function setPluginProxy(IPluginProxy $pluginProxy)
903
-    {
904
-        $this->pluginProxy = $pluginProxy;
905
-    }
906
-
907
-    /**
908
-     * Returns the current plugin proxy object or null by default.
909
-     *
910
-     * @return IPluginProxy
911
-     */
912
-    public function getPluginProxy()
913
-    {
914
-        return $this->pluginProxy;
915
-    }
916
-
917
-    /**
918
-     * Checks whether the given template is cached or not.
919
-     *
920
-     * @param ITemplate $tpl the template object
921
-     *
922
-     * @return bool
923
-     */
924
-    public function isCached(ITemplate $tpl)
925
-    {
926
-        return is_string($tpl->getCachedTemplate($this));
927
-    }
928
-
929
-    /**
930
-     * Clear templates inside the compiled directory.
931
-     *
932
-     * @return int
933
-     */
934
-    public function clearCompiled()
935
-    {
936
-        $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getCompileDir()), \RecursiveIteratorIterator::SELF_FIRST);
937
-        $count    = 0;
938
-        foreach ($iterator as $file) {
939
-            if ($file->isFile()) {
940
-                $count += unlink($file->__toString()) ? 1 : 0;
941
-            }
942
-        }
943
-
944
-        return $count;
945
-    }
946
-
947
-    /**
948
-     * Clears the cached templates if they are older than the given time.
949
-     *
950
-     * @param int $olderThan minimum time (in seconds) required for a cached template to be cleared
951
-     *
952
-     * @return int the amount of templates cleared
953
-     */
954
-    public function clearCache($olderThan = - 1)
955
-    {
956
-        $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getCacheDir()), \RecursiveIteratorIterator::SELF_FIRST);
957
-        $expired  = time() - $olderThan;
958
-        $count    = 0;
959
-        foreach ($iterator as $file) {
960
-            if ($file->isFile() && $file->getCTime() < $expired) {
961
-                $count += unlink((string)$file) ? 1 : 0;
962
-            }
963
-        }
964
-
965
-        return $count;
966
-    }
967
-
968
-    /**
969
-     * Fetches a template object of the given resource.
970
-     *
971
-     * @param string    $resourceName   the resource name (i.e. file, string)
972
-     * @param string    $resourceId     the resource identifier (i.e. file path)
973
-     * @param int       $cacheTime      the cache time setting for this resource
974
-     * @param string    $cacheId        the unique cache identifier
975
-     * @param string    $compileId      the unique compiler identifier
976
-     * @param ITemplate $parentTemplate the parent template
977
-     *
978
-     * @return ITemplate
979
-     * @throws Exception
980
-     */
981
-    public function templateFactory($resourceName, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, ITemplate $parentTemplate = null)
982
-    {
983
-        if (isset($this->resources[$resourceName])) {
984
-            /**
985
-             * Interface ITemplate
986
-             *
987
-             * @var ITemplate $class
988
-             */
989
-            $class = $this->resources[$resourceName]['class'];
990
-
991
-            return $class::templateFactory($this, $resourceId, $cacheTime, $cacheId, $compileId, $parentTemplate);
992
-        }
993
-
994
-        throw new Exception('Unknown resource type : ' . $resourceName);
995
-    }
996
-
997
-    /**
998
-     * Checks if the input is an array or arrayaccess object, optionally it can also check if it's
999
-     * empty.
1000
-     *
1001
-     * @param mixed $value        the variable to check
1002
-     * @param bool  $checkIsEmpty if true, the function will also check if the array|arrayaccess is empty,
1003
-     *                            and return true only if it's not empty
1004
-     *
1005
-     * @return int|bool true if it's an array|arrayaccess (or the item count if $checkIsEmpty is true) or false if it's
1006
-     *                  not an array|arrayaccess (or 0 if $checkIsEmpty is true)
1007
-     */
1008
-    public function isArray($value, $checkIsEmpty = false)
1009
-    {
1010
-        if (is_array($value) === true || $value instanceof ArrayAccess) {
1011
-            if ($checkIsEmpty === false) {
1012
-                return true;
1013
-            }
1014
-
1015
-            return $this->count($value);
1016
-        }
1017
-
1018
-        return false;
1019
-    }
1020
-
1021
-    /**
1022
-     * Checks if the input is an array or a traversable object, optionally it can also check if it's
1023
-     * empty.
1024
-     *
1025
-     * @param mixed $value        the variable to check
1026
-     * @param bool  $checkIsEmpty if true, the function will also check if the array|traversable is empty,
1027
-     *                            and return true only if it's not empty
1028
-     *
1029
-     * @return int|bool true if it's an array|traversable (or the item count if $checkIsEmpty is true) or false if it's
1030
-     *                  not an array|traversable (or 0 if $checkIsEmpty is true)
1031
-     */
1032
-    public function isTraversable($value, $checkIsEmpty = false)
1033
-    {
1034
-        if (is_array($value) === true) {
1035
-            if ($checkIsEmpty === false) {
1036
-                return true;
1037
-            } else {
1038
-                return count($value) > 0;
1039
-            }
1040
-        } elseif ($value instanceof Traversable) {
1041
-            if ($checkIsEmpty === false) {
1042
-                return true;
1043
-            } else {
1044
-                return $this->count($value);
1045
-            }
1046
-        }
1047
-
1048
-        return false;
1049
-    }
1050
-
1051
-    /**
1052
-     * Counts an array or arrayaccess/traversable object.
1053
-     *
1054
-     * @param mixed $value the value to count
1055
-     *
1056
-     * @return int|bool the count for arrays and objects that implement countable, true for other objects that don't,
1057
-     *                  and 0 for empty elements
1058
-     */
1059
-    public function count($value)
1060
-    {
1061
-        if (is_array($value) === true || $value instanceof Countable) {
1062
-            return count($value);
1063
-        } elseif ($value instanceof ArrayAccess) {
1064
-            if ($value->offsetExists(0)) {
1065
-                return true;
1066
-            }
1067
-        } elseif ($value instanceof Iterator) {
1068
-            $value->rewind();
1069
-            if ($value->valid()) {
1070
-                return true;
1071
-            }
1072
-        } elseif ($value instanceof Traversable) {
1073
-            foreach ($value as $dummy) {
1074
-                return true;
1075
-            }
1076
-        }
1077
-
1078
-        return 0;
1079
-    }
1080
-
1081
-    /**
1082
-     * Triggers a dwoo error.
1083
-     *
1084
-     * @param string $message the error message
1085
-     * @param int    $level   the error level, one of the PHP's E_* constants
1086
-     *
1087
-     * @return void
1088
-     */
1089
-    public function triggerError($message, $level = E_USER_NOTICE)
1090
-    {
1091
-        if (!($tplIdentifier = $this->template->getResourceIdentifier())) {
1092
-            $tplIdentifier = $this->template->getResourceName();
1093
-        }
1094
-        trigger_error('Dwoo error (in ' . $tplIdentifier . ') : ' . $message, $level);
1095
-    }
1096
-
1097
-    /**
1098
-     * Adds a block to the block stack.
1099
-     *
1100
-     * @param string $blockName the block name (without Dwoo_Plugin_ prefix)
1101
-     * @param array  $args      the arguments to be passed to the block's init() function
1102
-     *
1103
-     * @return BlockPlugin the newly created block
1104
-     */
1105
-    public function addStack($blockName, array $args = array())
1106
-    {
1107
-        if (isset($this->plugins[$blockName])) {
1108
-            $class = $this->plugins[$blockName]['class'];
1109
-        } else {
1110
-            $class = self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . self::toCamelCase($blockName);
1111
-        }
1112
-
1113
-        if ($this->curBlock !== null) {
1114
-            $this->curBlock->buffer(ob_get_contents());
1115
-            ob_clean();
1116
-        } else {
1117
-            $this->buffer .= ob_get_contents();
1118
-            ob_clean();
1119
-        }
1120
-
1121
-        $block = new $class($this);
1122
-
1123
-        call_user_func_array(array($block, 'init'), $args);
1124
-
1125
-        $this->stack[] = $this->curBlock = $block;
1126
-
1127
-        return $block;
1128
-    }
1129
-
1130
-    /**
1131
-     * Removes the plugin at the top of the block stack.
1132
-     * Calls the block buffer() function, followed by a call to end() and finally a call to process()
1133
-     *
1134
-     * @return void
1135
-     */
1136
-    public function delStack()
1137
-    {
1138
-        $args = func_get_args();
1139
-
1140
-        $this->curBlock->buffer(ob_get_contents());
1141
-        ob_clean();
1142
-
1143
-        call_user_func_array(array($this->curBlock, 'end'), $args);
1144
-
1145
-        $tmp = array_pop($this->stack);
1146
-
1147
-        if (count($this->stack) > 0) {
1148
-            $this->curBlock = end($this->stack);
1149
-            $this->curBlock->buffer($tmp->process());
1150
-        } else {
1151
-            if ($this->buffer !== '') {
1152
-                echo $this->buffer;
1153
-                $this->buffer = '';
1154
-            }
1155
-            $this->curBlock = null;
1156
-            echo $tmp->process();
1157
-        }
1158
-
1159
-        unset($tmp);
1160
-    }
1161
-
1162
-    /**
1163
-     * Returns the parent block of the given block.
1164
-     *
1165
-     * @param BlockPlugin $block the block class plugin
1166
-     *
1167
-     * @return BlockPlugin|false if the given block isn't in the stack
1168
-     */
1169
-    public function getParentBlock(BlockPlugin $block)
1170
-    {
1171
-        $index = array_search($block, $this->stack, true);
1172
-        if ($index !== false && $index > 0) {
1173
-            return $this->stack[$index - 1];
1174
-        }
1175
-
1176
-        return false;
1177
-    }
1178
-
1179
-    /**
1180
-     * Finds the closest block of the given type, starting at the top of the stack.
1181
-     *
1182
-     * @param string $type the type of plugin you want to find
1183
-     *
1184
-     * @return BlockPlugin|false if no plugin of such type is in the stack
1185
-     */
1186
-    public function findBlock($type)
1187
-    {
1188
-        if (isset($this->plugins[$type])) {
1189
-            $type = $this->plugins[$type]['class'];
1190
-        } else {
1191
-            $type = self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin_' . str_replace(self::NAMESPACE_PLUGINS_BLOCKS.'Plugin',
1192
-                    '', $type);
1193
-        }
1194
-
1195
-        $keys = array_keys($this->stack);
1196
-        while (($key = array_pop($keys)) !== false) {
1197
-            if ($this->stack[$key] instanceof $type) {
1198
-                return $this->stack[$key];
1199
-            }
1200
-        }
1201
-
1202
-        return false;
1203
-    }
1204
-
1205
-    /**
1206
-     * Returns a Plugin of the given class.
1207
-     * this is so a single instance of every class plugin is created at each template run,
1208
-     * allowing class plugins to have "per-template-run" static variables
1209
-     *
1210
-     * @param string $class the class name
1211
-     *
1212
-     * @return mixed an object of the given class
1213
-     */
1214
-    public function getObjectPlugin($class)
1215
-    {
1216
-        if (isset($this->runtimePlugins[$class])) {
1217
-            return $this->runtimePlugins[$class];
1218
-        }
1219
-
1220
-        return $this->runtimePlugins[$class] = new $class($this);
1221
-    }
1222
-
1223
-    /**
1224
-     * Calls the process() method of the given class-plugin name.
1225
-     *
1226
-     * @param string $plugName the class plugin name (without Dwoo_Plugin_ prefix)
1227
-     * @param array  $params   an array of parameters to send to the process() method
1228
-     *
1229
-     * @return string the process() return value
1230
-     */
1231
-    public function classCall($plugName, array $params = array())
1232
-    {
1233
-        $class  = self::toCamelCase($plugName);
1234
-        $plugin = $this->getObjectPlugin($class);
1235
-
1236
-        return call_user_func_array(array($plugin, 'process'), $params);
1237
-    }
1238
-
1239
-    /**
1240
-     * Calls a php function.
1241
-     *
1242
-     * @param string $callback the function to call
1243
-     * @param array  $params   an array of parameters to send to the function
1244
-     *
1245
-     * @return mixed the return value of the called function
1246
-     */
1247
-    public function arrayMap($callback, array $params)
1248
-    {
1249
-        if ($params[0] === $this) {
1250
-            $addThis = true;
1251
-            array_shift($params);
1252
-        }
1253
-        if ((is_array($params[0]) || ($params[0] instanceof Iterator && $params[0] instanceof ArrayAccess))) {
1254
-            if (empty($params[0])) {
1255
-                return $params[0];
1256
-            }
1257
-
1258
-            // array map
1259
-            $out = array();
1260
-            $cnt = count($params);
1261
-
1262
-            if (isset($addThis)) {
1263
-                array_unshift($params, $this);
1264
-                $items = $params[1];
1265
-                $keys  = array_keys($items);
1266
-
1267
-                if (is_string($callback) === false) {
1268
-                    while (($i = array_shift($keys)) !== null) {
1269
-                        $out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1270
-                    }
1271
-                } elseif ($cnt === 1) {
1272
-                    while (($i = array_shift($keys)) !== null) {
1273
-                        $out[] = $callback($this, $items[$i]);
1274
-                    }
1275
-                } elseif ($cnt === 2) {
1276
-                    while (($i = array_shift($keys)) !== null) {
1277
-                        $out[] = $callback($this, $items[$i], $params[2]);
1278
-                    }
1279
-                } elseif ($cnt === 3) {
1280
-                    while (($i = array_shift($keys)) !== null) {
1281
-                        $out[] = $callback($this, $items[$i], $params[2], $params[3]);
1282
-                    }
1283
-                } else {
1284
-                    while (($i = array_shift($keys)) !== null) {
1285
-                        $out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1286
-                    }
1287
-                }
1288
-            } else {
1289
-                $items = $params[0];
1290
-                $keys  = array_keys($items);
1291
-
1292
-                if (is_string($callback) === false) {
1293
-                    while (($i = array_shift($keys)) !== null) {
1294
-                        $out[] = call_user_func_array($callback, array($items[$i]) + $params);
1295
-                    }
1296
-                } elseif ($cnt === 1) {
1297
-                    while (($i = array_shift($keys)) !== null) {
1298
-                        $out[] = $callback($items[$i]);
1299
-                    }
1300
-                } elseif ($cnt === 2) {
1301
-                    while (($i = array_shift($keys)) !== null) {
1302
-                        $out[] = $callback($items[$i], $params[1]);
1303
-                    }
1304
-                } elseif ($cnt === 3) {
1305
-                    while (($i = array_shift($keys)) !== null) {
1306
-                        $out[] = $callback($items[$i], $params[1], $params[2]);
1307
-                    }
1308
-                } elseif ($cnt === 4) {
1309
-                    while (($i = array_shift($keys)) !== null) {
1310
-                        $out[] = $callback($items[$i], $params[1], $params[2], $params[3]);
1311
-                    }
1312
-                } else {
1313
-                    while (($i = array_shift($keys)) !== null) {
1314
-                        $out[] = call_user_func_array($callback, array($items[$i]) + $params);
1315
-                    }
1316
-                }
1317
-            }
1318
-
1319
-            return $out;
1320
-        } else {
1321
-            return $params[0];
1322
-        }
1323
-    }
1324
-
1325
-    /**
1326
-     * Reads a variable into the given data array.
1327
-     *
1328
-     * @param string $varstr   the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1329
-     * @param mixed  $data     the data array or object to read from
1330
-     * @param bool   $safeRead if true, the function will check whether the index exists to prevent any notices from
1331
-     *                         being output
1332
-     *
1333
-     * @return mixed
1334
-     */
1335
-    public function readVarInto($varstr, $data, $safeRead = false)
1336
-    {
1337
-        if ($data === null) {
1338
-            return null;
1339
-        }
1340
-
1341
-        if (is_array($varstr) === false) {
1342
-            preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1343
-        } else {
1344
-            $m = $varstr;
1345
-        }
1346
-        unset($varstr);
1347
-
1348
-        while (list($k, $sep) = each($m[1])) {
1349
-            if ($sep === '.' || $sep === '[' || $sep === '') {
1350
-                // strip enclosing quotes if present
1351
-                $m[2][$k] = preg_replace('#^(["\']?)(.*?)\1$#', '$2', $m[2][$k]);
1352
-
1353
-                if ((is_array($data) || $data instanceof ArrayAccess) && ($safeRead === false || isset($data[$m[2][$k]]))) {
1354
-                    $data = $data[$m[2][$k]];
1355
-                } else {
1356
-                    return null;
1357
-                }
1358
-            } else {
1359
-                if (is_object($data) && ($safeRead === false || isset($data->$m[2][$k]))) {
1360
-                    $data = $data->$m[2][$k];
1361
-                } else {
1362
-                    return null;
1363
-                }
1364
-            }
1365
-        }
1366
-
1367
-        return $data;
1368
-    }
1369
-
1370
-    /**
1371
-     * Reads a variable into the parent scope.
1372
-     *
1373
-     * @param int    $parentLevels the amount of parent levels to go from the current scope
1374
-     * @param string $varstr       the variable string, using dwoo variable syntax (i.e.
1375
-     *                             "var.subvar[subsubvar]->property")
1376
-     *
1377
-     * @return mixed
1378
-     */
1379
-    public function readParentVar($parentLevels, $varstr = null)
1380
-    {
1381
-        $tree = $this->scopeTree;
1382
-        $cur  = $this->data;
1383
-
1384
-        while ($parentLevels -- !== 0) {
1385
-            array_pop($tree);
1386
-        }
1387
-
1388
-        while (($i = array_shift($tree)) !== null) {
1389
-            if (is_object($cur)) {
1390
-                $cur = $cur->$i;
1391
-            } else {
1392
-                $cur = $cur[$i];
1393
-            }
1394
-        }
1395
-
1396
-        if ($varstr !== null) {
1397
-            return $this->readVarInto($varstr, $cur);
1398
-        } else {
1399
-            return $cur;
1400
-        }
1401
-    }
1402
-
1403
-    /**
1404
-     * Reads a variable into the current scope.
1405
-     *
1406
-     * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1407
-     *
1408
-     * @return mixed
1409
-     */
1410
-    public function readVar($varstr)
1411
-    {
1412
-        if (is_array($varstr) === true) {
1413
-            $m = $varstr;
1414
-            unset($varstr);
1415
-        } else {
1416
-            if (strstr($varstr, '.') === false && strstr($varstr, '[') === false && strstr($varstr, '->') === false) {
1417
-                if ($varstr === 'dwoo') {
1418
-                    return $this->globals;
1419
-                } elseif ($varstr === '__' || $varstr === '_root') {
1420
-                    return $this->data;
1421
-                } elseif ($varstr === '_' || $varstr === '_parent') {
1422
-                    $varstr = '.' . $varstr;
1423
-                    $tree   = $this->scopeTree;
1424
-                    $cur    = $this->data;
1425
-                    array_pop($tree);
1426
-
1427
-                    while (($i = array_shift($tree)) !== null) {
1428
-                        if (is_object($cur)) {
1429
-                            $cur = $cur->$i;
1430
-                        } else {
1431
-                            $cur = $cur[$i];
1432
-                        }
1433
-                    }
1434
-
1435
-                    return $cur;
1436
-                }
1437
-
1438
-                $cur = $this->scope;
1439
-
1440
-                if (isset($cur[$varstr])) {
1441
-                    return $cur[$varstr];
1442
-                } else {
1443
-                    return null;
1444
-                }
1445
-            }
1446
-
1447
-            if (substr($varstr, 0, 1) === '.') {
1448
-                $varstr = 'dwoo' . $varstr;
1449
-            }
1450
-
1451
-            preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1452
-        }
1453
-
1454
-        $i = $m[2][0];
1455
-        if ($i === 'dwoo') {
1456
-            $cur = $this->globals;
1457
-            array_shift($m[2]);
1458
-            array_shift($m[1]);
1459
-            switch ($m[2][0]) {
1460
-            case 'get':
1461
-                $cur = $_GET;
1462
-                break;
1463
-            case 'post':
1464
-                $cur = $_POST;
1465
-                break;
1466
-            case 'session':
1467
-                $cur = $_SESSION;
1468
-                break;
1469
-            case 'cookies':
1470
-            case 'cookie':
1471
-                $cur = $_COOKIE;
1472
-                break;
1473
-            case 'server':
1474
-                $cur = $_SERVER;
1475
-                break;
1476
-            case 'env':
1477
-                $cur = $_ENV;
1478
-                break;
1479
-            case 'request':
1480
-                $cur = $_REQUEST;
1481
-                break;
1482
-            case 'const':
1483
-                array_shift($m[2]);
1484
-                if (defined($m[2][0])) {
1485
-                    return constant($m[2][0]);
1486
-                } else {
1487
-                    return null;
1488
-                }
1489
-            }
1490
-            if ($cur !== $this->globals) {
1491
-                array_shift($m[2]);
1492
-                array_shift($m[1]);
1493
-            }
1494
-        } elseif ($i === '__' || $i === '_root') {
1495
-            $cur = $this->data;
1496
-            array_shift($m[2]);
1497
-            array_shift($m[1]);
1498
-        } elseif ($i === '_' || $i === '_parent') {
1499
-            $tree = $this->scopeTree;
1500
-            $cur  = $this->data;
1501
-
1502
-            while (true) {
1503
-                array_pop($tree);
1504
-                array_shift($m[2]);
1505
-                array_shift($m[1]);
1506
-                if (current($m[2]) === '_' || current($m[2]) === '_parent') {
1507
-                    continue;
1508
-                }
1509
-
1510
-                while (($i = array_shift($tree)) !== null) {
1511
-                    if (is_object($cur)) {
1512
-                        $cur = $cur->$i;
1513
-                    } else {
1514
-                        $cur = $cur[$i];
1515
-                    }
1516
-                }
1517
-                break;
1518
-            }
1519
-        } else {
1520
-            $cur = $this->scope;
1521
-        }
1522
-
1523
-        while (list($k, $sep) = each($m[1])) {
1524
-            if ($sep === '.' || $sep === '[' || $sep === '') {
1525
-                if ((is_array($cur) || $cur instanceof ArrayAccess) && isset($cur[$m[2][$k]])) {
1526
-                    $cur = $cur[$m[2][$k]];
1527
-                } else {
1528
-                    return null;
1529
-                }
1530
-            } elseif ($sep === '->') {
1531
-                if (is_object($cur)) {
1532
-                    $cur = $cur->$m[2][$k];
1533
-                } else {
1534
-                    return null;
1535
-                }
1536
-            } else {
1537
-                return null;
1538
-            }
1539
-        }
1540
-
1541
-        return $cur;
1542
-    }
1543
-
1544
-    /**
1545
-     * Assign the value to the given variable.
1546
-     *
1547
-     * @param mixed  $value the value to assign
1548
-     * @param string $scope the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1549
-     *
1550
-     * @return bool true if assigned correctly or false if a problem occured while parsing the var string
1551
-     */
1552
-    public function assignInScope($value, $scope)
1553
-    {
1554
-        if (!is_string($scope)) {
1555
-            $this->triggerError('Assignments must be done into strings, (' . gettype($scope) . ') ' . var_export($scope, true) . ' given', E_USER_ERROR);
1556
-        }
1557
-        if (strstr($scope, '.') === false && strstr($scope, '->') === false) {
1558
-            $this->scope[$scope] = $value;
1559
-        } else {
1560
-            // TODO handle _root/_parent scopes ?
1561
-            preg_match_all('#(\[|->|\.)?([^.[\]-]+)\]?#i', $scope, $m);
1562
-
1563
-            $cur  = &$this->scope;
1564
-            $last = array(
1565
-                array_pop($m[1]),
1566
-                array_pop($m[2])
1567
-            );
1568
-
1569
-            while (list($k, $sep) = each($m[1])) {
1570
-                if ($sep === '.' || $sep === '[' || $sep === '') {
1571
-                    if (is_array($cur) === false) {
1572
-                        $cur = array();
1573
-                    }
1574
-                    $cur = &$cur[$m[2][$k]];
1575
-                } elseif ($sep === '->') {
1576
-                    if (is_object($cur) === false) {
1577
-                        $cur = new stdClass();
1578
-                    }
1579
-                    $cur = &$cur->$m[2][$k];
1580
-                } else {
1581
-                    return false;
1582
-                }
1583
-            }
1584
-
1585
-            if ($last[0] === '.' || $last[0] === '[' || $last[0] === '') {
1586
-                if (is_array($cur) === false) {
1587
-                    $cur = array();
1588
-                }
1589
-                $cur[$last[1]] = $value;
1590
-            } elseif ($last[0] === '->') {
1591
-                if (is_object($cur) === false) {
1592
-                    $cur = new stdClass();
1593
-                }
1594
-                $cur->$last[1] = $value;
1595
-            } else {
1596
-                return false;
1597
-            }
1598
-        }
1599
-    }
1600
-
1601
-    /**
1602
-     * Sets the scope to the given scope string or array.
1603
-     *
1604
-     * @param mixed $scope    a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1605
-     * @param bool  $absolute if true, the scope is set from the top level scope and not from the current scope
1606
-     *
1607
-     * @return array the current scope tree
1608
-     */
1609
-    public function setScope($scope, $absolute = false)
1610
-    {
1611
-        $old = $this->scopeTree;
1612
-
1613
-        if (is_string($scope) === true) {
1614
-            $scope = explode('.', $scope);
1615
-        }
1616
-
1617
-        if ($absolute === true) {
1618
-            $this->scope     = &$this->data;
1619
-            $this->scopeTree = array();
1620
-        }
1621
-
1622
-        while (($bit = array_shift($scope)) !== null) {
1623
-            if ($bit === '_' || $bit === '_parent') {
1624
-                array_pop($this->scopeTree);
1625
-                $this->scope = &$this->data;
1626
-                $cnt         = count($this->scopeTree);
1627
-                for ($i = 0; $i < $cnt; ++ $i) {
1628
-                    $this->scope = &$this->scope[$this->scopeTree[$i]];
1629
-                }
1630
-            } elseif ($bit === '__' || $bit === '_root') {
1631
-                $this->scope     = &$this->data;
1632
-                $this->scopeTree = array();
1633
-            } elseif (isset($this->scope[$bit])) {
1634
-                if ($this->scope instanceof ArrayAccess) {
1635
-                    $tmp         = $this->scope[$bit];
1636
-                    $this->scope = &$tmp;
1637
-                } else {
1638
-                    $this->scope = &$this->scope[$bit];
1639
-                }
1640
-                $this->scopeTree[] = $bit;
1641
-            } else {
1642
-                unset($this->scope);
1643
-                $this->scope = null;
1644
-            }
1645
-        }
1646
-
1647
-        return $old;
1648
-    }
1649
-
1650
-    /**
1651
-     * Returns the entire data array.
1652
-     *
1653
-     * @return array
1654
-     */
1655
-    public function getData()
1656
-    {
1657
-        return $this->data;
1658
-    }
1659
-
1660
-    /**
1661
-     * Sets a return value for the currently running template.
1662
-     *
1663
-     * @param string $name  var name
1664
-     * @param mixed  $value var value
1665
-     *
1666
-     * @return void
1667
-     */
1668
-    public function setReturnValue($name, $value)
1669
-    {
1670
-        $this->returnData[$name] = $value;
1671
-    }
1672
-
1673
-    /**
1674
-     * Retrieves the return values set by the template.
1675
-     *
1676
-     * @return array
1677
-     */
1678
-    public function getReturnValues()
1679
-    {
1680
-        return $this->returnData;
1681
-    }
1682
-
1683
-    /**
1684
-     * Returns a reference to the current scope.
1685
-     *
1686
-     * @return mixed
1687
-     */
1688
-    public function &getScope()
1689
-    {
1690
-        return $this->scope;
1691
-    }
1692
-
1693
-    /**
1694
-     * Redirects all calls to unexisting to plugin proxy.
1695
-     *
1696
-     * @param string $method the method name
1697
-     * @param array  $args   array of arguments
1698
-     *
1699
-     * @return mixed
1700
-     * @throws Exception
1701
-     */
1702
-    public function __call($method, $args)
1703
-    {
1704
-        $proxy = $this->getPluginProxy();
1705
-        if (!$proxy) {
1706
-            throw new Exception('Call to undefined method ' . __CLASS__ . '::' . $method . '()');
1707
-        }
1708
-
1709
-        return call_user_func_array($proxy->getCallback($method), $args);
1710
-    }
1711
-
1712
-    /**
1713
-     * Convert plugin name from `auto_escape` to `AutoEscape`.
1714
-     * @param string $input
1715
-     * @param string $separator
1716
-     *
1717
-     * @return mixed
1718
-     */
1719
-    public static function toCamelCase($input, $separator = '_')
1720
-    {
1721
-        return join(array_map('ucfirst', explode($separator, $input)));
1722
-
1723
-        // TODO >= PHP5.4.32
1724
-        //return str_replace($separator, '', ucwords($input, $separator));
1725
-    }
577
+				);
578
+			}
579
+
580
+			$this->filters[] = $callback;
581
+		} else {
582
+			$this->filters[] = $callback;
583
+		}
584
+	}
585
+
586
+	/**
587
+	 * Removes a filter.
588
+	 *
589
+	 * @param mixed $callback callback or filter name if it was autoloaded
590
+	 *
591
+	 * @return void
592
+	 */
593
+	public function removeFilter($callback)
594
+	{
595
+		if (($index = array_search(self::NAMESPACE_PLUGINS_FILTERS. 'Filter' . self::toCamelCase($callback), $this->filters,
596
+				true)) !==
597
+			false) {
598
+			unset($this->filters[$index]);
599
+		} elseif (($index = array_search($callback, $this->filters, true)) !== false) {
600
+			unset($this->filters[$index]);
601
+		} else {
602
+			$class = self::NAMESPACE_PLUGINS_FILTERS . 'Filter' . $callback;
603
+			foreach ($this->filters as $index => $filter) {
604
+				if (is_array($filter) && $filter[0] instanceof $class) {
605
+					unset($this->filters[$index]);
606
+					break;
607
+				}
608
+			}
609
+		}
610
+	}
611
+
612
+	/**
613
+	 * Adds a resource or overrides a default one.
614
+	 *
615
+	 * @param string   $name            the resource name
616
+	 * @param string   $class           the resource class (which must implement ITemplate)
617
+	 * @param callback $compilerFactory the compiler factory callback, a function that must return a compiler instance
618
+	 *                                  used to compile this resource, if none is provided. by default it will produce
619
+	 *                                  a Compiler object
620
+	 *
621
+	 * @return void
622
+	 * @throws Exception
623
+	 */
624
+	public function addResource($name, $class, $compilerFactory = null)
625
+	{
626
+		if (strlen($name) < 2) {
627
+			throw new Exception('Resource names must be at least two-character long to avoid conflicts with Windows paths');
628
+		}
629
+
630
+		if (!class_exists($class)) {
631
+			throw new Exception('Resource class does not exist');
632
+		}
633
+
634
+		$interfaces = class_implements($class);
635
+		if (in_array('Dwoo\ITemplate', $interfaces) === false) {
636
+			throw new Exception('Resource class must implement ITemplate');
637
+		}
638
+
639
+		$this->resources[$name] = array(
640
+			'class'    => $class,
641
+			'compiler' => $compilerFactory
642
+		);
643
+	}
644
+
645
+	/**
646
+	 * Removes a custom resource.
647
+	 *
648
+	 * @param string $name the resource name
649
+	 *
650
+	 * @return void
651
+	 */
652
+	public function removeResource($name)
653
+	{
654
+		unset($this->resources[$name]);
655
+		if ($name === 'file') {
656
+			$this->resources['file'] = array(
657
+				'class'    => 'Dwoo\Template\File',
658
+				'compiler' => null
659
+			);
660
+		}
661
+	}
662
+
663
+	/**
664
+	 * Sets the loader object to use to load plugins.
665
+	 *
666
+	 * @param ILoader $loader loader
667
+	 *
668
+	 * @return void
669
+	 */
670
+	public function setLoader(ILoader $loader)
671
+	{
672
+		$this->loader = $loader;
673
+	}
674
+
675
+	/**
676
+	 * Returns the current loader object or a default one if none is currently found.
677
+	 *
678
+	 * @return ILoader|Loader
679
+	 */
680
+	public function getLoader()
681
+	{
682
+		if ($this->loader === null) {
683
+			$this->loader = new Loader($this->getCompileDir());
684
+		}
685
+
686
+		return $this->loader;
687
+	}
688
+
689
+	/**
690
+	 * Returns the custom plugins loaded.
691
+	 * Used by the ITemplate classes to pass the custom plugins to their ICompiler instance.
692
+	 *
693
+	 * @return array
694
+	 */
695
+	public function getCustomPlugins()
696
+	{
697
+		return $this->plugins;
698
+	}
699
+
700
+	/**
701
+	 * Return a specified custom plugin loaded by his name.
702
+	 * Used by the compiler, for executing a Closure.
703
+	 *
704
+	 * @param string $name
705
+	 *
706
+	 * @return mixed|null
707
+	 */
708
+	public function getCustomPlugin($name)
709
+	{
710
+		if (isset($this->plugins[$name])) {
711
+			return $this->plugins[$name]['callback'];
712
+		}
713
+
714
+		return null;
715
+	}
716
+
717
+	/**
718
+	 * Returns the cache directory with a trailing DIRECTORY_SEPARATOR.
719
+	 *
720
+	 * @return string
721
+	 */
722
+	public function getCacheDir()
723
+	{
724
+		if ($this->cacheDir === null) {
725
+			$this->setCacheDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR);
726
+		}
727
+
728
+		return $this->cacheDir;
729
+	}
730
+
731
+	/**
732
+	 * Sets the cache directory and automatically appends a DIRECTORY_SEPARATOR.
733
+	 *
734
+	 * @param string $dir the cache directory
735
+	 *
736
+	 * @return void
737
+	 * @throws Exception
738
+	 */
739
+	public function setCacheDir($dir)
740
+	{
741
+		$this->cacheDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
742
+		if (is_writable($this->cacheDir) === false) {
743
+			throw new Exception('The cache directory must be writable, chmod "' . $this->cacheDir . '" to make it writable');
744
+		}
745
+	}
746
+
747
+	/**
748
+	 * Returns the compile directory with a trailing DIRECTORY_SEPARATOR.
749
+	 *
750
+	 * @return string
751
+	 */
752
+	public function getCompileDir()
753
+	{
754
+		if ($this->compileDir === null) {
755
+			$this->setCompileDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'compiled' . DIRECTORY_SEPARATOR);
756
+		}
757
+
758
+		return $this->compileDir;
759
+	}
760
+
761
+	/**
762
+	 * Sets the compile directory and automatically appends a DIRECTORY_SEPARATOR.
763
+	 *
764
+	 * @param string $dir the compile directory
765
+	 *
766
+	 * @return void
767
+	 * @throws Exception
768
+	 */
769
+	public function setCompileDir($dir)
770
+	{
771
+		$this->compileDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
772
+		if (is_writable($this->compileDir) === false) {
773
+			throw new Exception('The compile directory must be writable, chmod "' . $this->compileDir . '" to make it writable');
774
+		}
775
+	}
776
+
777
+	/**
778
+	 * Returns the default cache time that is used with templates that do not have a cache time set.
779
+	 *
780
+	 * @return int the duration in seconds
781
+	 */
782
+	public function getCacheTime()
783
+	{
784
+		return $this->cacheTime;
785
+	}
786
+
787
+	/**
788
+	 * Sets the default cache time to use with templates that do not have a cache time set.
789
+	 *
790
+	 * @param int $seconds the duration in seconds
791
+	 *
792
+	 * @return void
793
+	 */
794
+	public function setCacheTime($seconds)
795
+	{
796
+		$this->cacheTime = (int)$seconds;
797
+	}
798
+
799
+	/**
800
+	 * Returns the character set used by the string manipulation plugins.
801
+	 * the charset is automatically lowercased
802
+	 *
803
+	 * @return string
804
+	 */
805
+	public function getCharset()
806
+	{
807
+		return $this->charset;
808
+	}
809
+
810
+	/**
811
+	 * Sets the character set used by the string manipulation plugins.
812
+	 * the charset will be automatically lowercased
813
+	 *
814
+	 * @param string $charset the character set
815
+	 *
816
+	 * @return void
817
+	 */
818
+	public function setCharset($charset)
819
+	{
820
+		$this->charset = strtolower((string)$charset);
821
+	}
822
+
823
+	/**
824
+	 * Returns the current template being rendered, when applicable, or null.
825
+	 *
826
+	 * @return ITemplate|null
827
+	 */
828
+	public function getTemplate()
829
+	{
830
+		return $this->template;
831
+	}
832
+
833
+	/**
834
+	 * Sets the current template being rendered.
835
+	 *
836
+	 * @param ITemplate $tpl template object
837
+	 *
838
+	 * @return void
839
+	 */
840
+	public function setTemplate(ITemplate $tpl)
841
+	{
842
+		$this->template = $tpl;
843
+	}
844
+
845
+	/**
846
+	 * Sets the default compiler factory function for the given resource name.
847
+	 * a compiler factory must return a ICompiler object pre-configured to fit your needs
848
+	 *
849
+	 * @param string   $resourceName    the resource name (i.e. file, string)
850
+	 * @param callback $compilerFactory the compiler factory callback
851
+	 *
852
+	 * @return void
853
+	 */
854
+	public function setDefaultCompilerFactory($resourceName, $compilerFactory)
855
+	{
856
+		$this->resources[$resourceName]['compiler'] = $compilerFactory;
857
+	}
858
+
859
+	/**
860
+	 * Returns the default compiler factory function for the given resource name.
861
+	 *
862
+	 * @param string $resourceName the resource name
863
+	 *
864
+	 * @return callback the compiler factory callback
865
+	 */
866
+	public function getDefaultCompilerFactory($resourceName)
867
+	{
868
+		return $this->resources[$resourceName]['compiler'];
869
+	}
870
+
871
+	/**
872
+	 * Sets the security policy object to enforce some php security settings.
873
+	 * use this if untrusted persons can modify templates
874
+	 *
875
+	 * @param SecurityPolicy $policy the security policy object
876
+	 *
877
+	 * @return void
878
+	 */
879
+	public function setSecurityPolicy(SecurityPolicy $policy = null)
880
+	{
881
+		$this->securityPolicy = $policy;
882
+	}
883
+
884
+	/**
885
+	 * Returns the current security policy object or null by default.
886
+	 *
887
+	 * @return SecurityPolicy|null the security policy object if any
888
+	 */
889
+	public function getSecurityPolicy()
890
+	{
891
+		return $this->securityPolicy;
892
+	}
893
+
894
+	/**
895
+	 * Sets the object that must be used as a plugin proxy when plugin can't be found
896
+	 * by dwoo's loader.
897
+	 *
898
+	 * @param IPluginProxy $pluginProxy the proxy object
899
+	 *
900
+	 * @return void
901
+	 */
902
+	public function setPluginProxy(IPluginProxy $pluginProxy)
903
+	{
904
+		$this->pluginProxy = $pluginProxy;
905
+	}
906
+
907
+	/**
908
+	 * Returns the current plugin proxy object or null by default.
909
+	 *
910
+	 * @return IPluginProxy
911
+	 */
912
+	public function getPluginProxy()
913
+	{
914
+		return $this->pluginProxy;
915
+	}
916
+
917
+	/**
918
+	 * Checks whether the given template is cached or not.
919
+	 *
920
+	 * @param ITemplate $tpl the template object
921
+	 *
922
+	 * @return bool
923
+	 */
924
+	public function isCached(ITemplate $tpl)
925
+	{
926
+		return is_string($tpl->getCachedTemplate($this));
927
+	}
928
+
929
+	/**
930
+	 * Clear templates inside the compiled directory.
931
+	 *
932
+	 * @return int
933
+	 */
934
+	public function clearCompiled()
935
+	{
936
+		$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getCompileDir()), \RecursiveIteratorIterator::SELF_FIRST);
937
+		$count    = 0;
938
+		foreach ($iterator as $file) {
939
+			if ($file->isFile()) {
940
+				$count += unlink($file->__toString()) ? 1 : 0;
941
+			}
942
+		}
943
+
944
+		return $count;
945
+	}
946
+
947
+	/**
948
+	 * Clears the cached templates if they are older than the given time.
949
+	 *
950
+	 * @param int $olderThan minimum time (in seconds) required for a cached template to be cleared
951
+	 *
952
+	 * @return int the amount of templates cleared
953
+	 */
954
+	public function clearCache($olderThan = - 1)
955
+	{
956
+		$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getCacheDir()), \RecursiveIteratorIterator::SELF_FIRST);
957
+		$expired  = time() - $olderThan;
958
+		$count    = 0;
959
+		foreach ($iterator as $file) {
960
+			if ($file->isFile() && $file->getCTime() < $expired) {
961
+				$count += unlink((string)$file) ? 1 : 0;
962
+			}
963
+		}
964
+
965
+		return $count;
966
+	}
967
+
968
+	/**
969
+	 * Fetches a template object of the given resource.
970
+	 *
971
+	 * @param string    $resourceName   the resource name (i.e. file, string)
972
+	 * @param string    $resourceId     the resource identifier (i.e. file path)
973
+	 * @param int       $cacheTime      the cache time setting for this resource
974
+	 * @param string    $cacheId        the unique cache identifier
975
+	 * @param string    $compileId      the unique compiler identifier
976
+	 * @param ITemplate $parentTemplate the parent template
977
+	 *
978
+	 * @return ITemplate
979
+	 * @throws Exception
980
+	 */
981
+	public function templateFactory($resourceName, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, ITemplate $parentTemplate = null)
982
+	{
983
+		if (isset($this->resources[$resourceName])) {
984
+			/**
985
+			 * Interface ITemplate
986
+			 *
987
+			 * @var ITemplate $class
988
+			 */
989
+			$class = $this->resources[$resourceName]['class'];
990
+
991
+			return $class::templateFactory($this, $resourceId, $cacheTime, $cacheId, $compileId, $parentTemplate);
992
+		}
993
+
994
+		throw new Exception('Unknown resource type : ' . $resourceName);
995
+	}
996
+
997
+	/**
998
+	 * Checks if the input is an array or arrayaccess object, optionally it can also check if it's
999
+	 * empty.
1000
+	 *
1001
+	 * @param mixed $value        the variable to check
1002
+	 * @param bool  $checkIsEmpty if true, the function will also check if the array|arrayaccess is empty,
1003
+	 *                            and return true only if it's not empty
1004
+	 *
1005
+	 * @return int|bool true if it's an array|arrayaccess (or the item count if $checkIsEmpty is true) or false if it's
1006
+	 *                  not an array|arrayaccess (or 0 if $checkIsEmpty is true)
1007
+	 */
1008
+	public function isArray($value, $checkIsEmpty = false)
1009
+	{
1010
+		if (is_array($value) === true || $value instanceof ArrayAccess) {
1011
+			if ($checkIsEmpty === false) {
1012
+				return true;
1013
+			}
1014
+
1015
+			return $this->count($value);
1016
+		}
1017
+
1018
+		return false;
1019
+	}
1020
+
1021
+	/**
1022
+	 * Checks if the input is an array or a traversable object, optionally it can also check if it's
1023
+	 * empty.
1024
+	 *
1025
+	 * @param mixed $value        the variable to check
1026
+	 * @param bool  $checkIsEmpty if true, the function will also check if the array|traversable is empty,
1027
+	 *                            and return true only if it's not empty
1028
+	 *
1029
+	 * @return int|bool true if it's an array|traversable (or the item count if $checkIsEmpty is true) or false if it's
1030
+	 *                  not an array|traversable (or 0 if $checkIsEmpty is true)
1031
+	 */
1032
+	public function isTraversable($value, $checkIsEmpty = false)
1033
+	{
1034
+		if (is_array($value) === true) {
1035
+			if ($checkIsEmpty === false) {
1036
+				return true;
1037
+			} else {
1038
+				return count($value) > 0;
1039
+			}
1040
+		} elseif ($value instanceof Traversable) {
1041
+			if ($checkIsEmpty === false) {
1042
+				return true;
1043
+			} else {
1044
+				return $this->count($value);
1045
+			}
1046
+		}
1047
+
1048
+		return false;
1049
+	}
1050
+
1051
+	/**
1052
+	 * Counts an array or arrayaccess/traversable object.
1053
+	 *
1054
+	 * @param mixed $value the value to count
1055
+	 *
1056
+	 * @return int|bool the count for arrays and objects that implement countable, true for other objects that don't,
1057
+	 *                  and 0 for empty elements
1058
+	 */
1059
+	public function count($value)
1060
+	{
1061
+		if (is_array($value) === true || $value instanceof Countable) {
1062
+			return count($value);
1063
+		} elseif ($value instanceof ArrayAccess) {
1064
+			if ($value->offsetExists(0)) {
1065
+				return true;
1066
+			}
1067
+		} elseif ($value instanceof Iterator) {
1068
+			$value->rewind();
1069
+			if ($value->valid()) {
1070
+				return true;
1071
+			}
1072
+		} elseif ($value instanceof Traversable) {
1073
+			foreach ($value as $dummy) {
1074
+				return true;
1075
+			}
1076
+		}
1077
+
1078
+		return 0;
1079
+	}
1080
+
1081
+	/**
1082
+	 * Triggers a dwoo error.
1083
+	 *
1084
+	 * @param string $message the error message
1085
+	 * @param int    $level   the error level, one of the PHP's E_* constants
1086
+	 *
1087
+	 * @return void
1088
+	 */
1089
+	public function triggerError($message, $level = E_USER_NOTICE)
1090
+	{
1091
+		if (!($tplIdentifier = $this->template->getResourceIdentifier())) {
1092
+			$tplIdentifier = $this->template->getResourceName();
1093
+		}
1094
+		trigger_error('Dwoo error (in ' . $tplIdentifier . ') : ' . $message, $level);
1095
+	}
1096
+
1097
+	/**
1098
+	 * Adds a block to the block stack.
1099
+	 *
1100
+	 * @param string $blockName the block name (without Dwoo_Plugin_ prefix)
1101
+	 * @param array  $args      the arguments to be passed to the block's init() function
1102
+	 *
1103
+	 * @return BlockPlugin the newly created block
1104
+	 */
1105
+	public function addStack($blockName, array $args = array())
1106
+	{
1107
+		if (isset($this->plugins[$blockName])) {
1108
+			$class = $this->plugins[$blockName]['class'];
1109
+		} else {
1110
+			$class = self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . self::toCamelCase($blockName);
1111
+		}
1112
+
1113
+		if ($this->curBlock !== null) {
1114
+			$this->curBlock->buffer(ob_get_contents());
1115
+			ob_clean();
1116
+		} else {
1117
+			$this->buffer .= ob_get_contents();
1118
+			ob_clean();
1119
+		}
1120
+
1121
+		$block = new $class($this);
1122
+
1123
+		call_user_func_array(array($block, 'init'), $args);
1124
+
1125
+		$this->stack[] = $this->curBlock = $block;
1126
+
1127
+		return $block;
1128
+	}
1129
+
1130
+	/**
1131
+	 * Removes the plugin at the top of the block stack.
1132
+	 * Calls the block buffer() function, followed by a call to end() and finally a call to process()
1133
+	 *
1134
+	 * @return void
1135
+	 */
1136
+	public function delStack()
1137
+	{
1138
+		$args = func_get_args();
1139
+
1140
+		$this->curBlock->buffer(ob_get_contents());
1141
+		ob_clean();
1142
+
1143
+		call_user_func_array(array($this->curBlock, 'end'), $args);
1144
+
1145
+		$tmp = array_pop($this->stack);
1146
+
1147
+		if (count($this->stack) > 0) {
1148
+			$this->curBlock = end($this->stack);
1149
+			$this->curBlock->buffer($tmp->process());
1150
+		} else {
1151
+			if ($this->buffer !== '') {
1152
+				echo $this->buffer;
1153
+				$this->buffer = '';
1154
+			}
1155
+			$this->curBlock = null;
1156
+			echo $tmp->process();
1157
+		}
1158
+
1159
+		unset($tmp);
1160
+	}
1161
+
1162
+	/**
1163
+	 * Returns the parent block of the given block.
1164
+	 *
1165
+	 * @param BlockPlugin $block the block class plugin
1166
+	 *
1167
+	 * @return BlockPlugin|false if the given block isn't in the stack
1168
+	 */
1169
+	public function getParentBlock(BlockPlugin $block)
1170
+	{
1171
+		$index = array_search($block, $this->stack, true);
1172
+		if ($index !== false && $index > 0) {
1173
+			return $this->stack[$index - 1];
1174
+		}
1175
+
1176
+		return false;
1177
+	}
1178
+
1179
+	/**
1180
+	 * Finds the closest block of the given type, starting at the top of the stack.
1181
+	 *
1182
+	 * @param string $type the type of plugin you want to find
1183
+	 *
1184
+	 * @return BlockPlugin|false if no plugin of such type is in the stack
1185
+	 */
1186
+	public function findBlock($type)
1187
+	{
1188
+		if (isset($this->plugins[$type])) {
1189
+			$type = $this->plugins[$type]['class'];
1190
+		} else {
1191
+			$type = self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin_' . str_replace(self::NAMESPACE_PLUGINS_BLOCKS.'Plugin',
1192
+					'', $type);
1193
+		}
1194
+
1195
+		$keys = array_keys($this->stack);
1196
+		while (($key = array_pop($keys)) !== false) {
1197
+			if ($this->stack[$key] instanceof $type) {
1198
+				return $this->stack[$key];
1199
+			}
1200
+		}
1201
+
1202
+		return false;
1203
+	}
1204
+
1205
+	/**
1206
+	 * Returns a Plugin of the given class.
1207
+	 * this is so a single instance of every class plugin is created at each template run,
1208
+	 * allowing class plugins to have "per-template-run" static variables
1209
+	 *
1210
+	 * @param string $class the class name
1211
+	 *
1212
+	 * @return mixed an object of the given class
1213
+	 */
1214
+	public function getObjectPlugin($class)
1215
+	{
1216
+		if (isset($this->runtimePlugins[$class])) {
1217
+			return $this->runtimePlugins[$class];
1218
+		}
1219
+
1220
+		return $this->runtimePlugins[$class] = new $class($this);
1221
+	}
1222
+
1223
+	/**
1224
+	 * Calls the process() method of the given class-plugin name.
1225
+	 *
1226
+	 * @param string $plugName the class plugin name (without Dwoo_Plugin_ prefix)
1227
+	 * @param array  $params   an array of parameters to send to the process() method
1228
+	 *
1229
+	 * @return string the process() return value
1230
+	 */
1231
+	public function classCall($plugName, array $params = array())
1232
+	{
1233
+		$class  = self::toCamelCase($plugName);
1234
+		$plugin = $this->getObjectPlugin($class);
1235
+
1236
+		return call_user_func_array(array($plugin, 'process'), $params);
1237
+	}
1238
+
1239
+	/**
1240
+	 * Calls a php function.
1241
+	 *
1242
+	 * @param string $callback the function to call
1243
+	 * @param array  $params   an array of parameters to send to the function
1244
+	 *
1245
+	 * @return mixed the return value of the called function
1246
+	 */
1247
+	public function arrayMap($callback, array $params)
1248
+	{
1249
+		if ($params[0] === $this) {
1250
+			$addThis = true;
1251
+			array_shift($params);
1252
+		}
1253
+		if ((is_array($params[0]) || ($params[0] instanceof Iterator && $params[0] instanceof ArrayAccess))) {
1254
+			if (empty($params[0])) {
1255
+				return $params[0];
1256
+			}
1257
+
1258
+			// array map
1259
+			$out = array();
1260
+			$cnt = count($params);
1261
+
1262
+			if (isset($addThis)) {
1263
+				array_unshift($params, $this);
1264
+				$items = $params[1];
1265
+				$keys  = array_keys($items);
1266
+
1267
+				if (is_string($callback) === false) {
1268
+					while (($i = array_shift($keys)) !== null) {
1269
+						$out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1270
+					}
1271
+				} elseif ($cnt === 1) {
1272
+					while (($i = array_shift($keys)) !== null) {
1273
+						$out[] = $callback($this, $items[$i]);
1274
+					}
1275
+				} elseif ($cnt === 2) {
1276
+					while (($i = array_shift($keys)) !== null) {
1277
+						$out[] = $callback($this, $items[$i], $params[2]);
1278
+					}
1279
+				} elseif ($cnt === 3) {
1280
+					while (($i = array_shift($keys)) !== null) {
1281
+						$out[] = $callback($this, $items[$i], $params[2], $params[3]);
1282
+					}
1283
+				} else {
1284
+					while (($i = array_shift($keys)) !== null) {
1285
+						$out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1286
+					}
1287
+				}
1288
+			} else {
1289
+				$items = $params[0];
1290
+				$keys  = array_keys($items);
1291
+
1292
+				if (is_string($callback) === false) {
1293
+					while (($i = array_shift($keys)) !== null) {
1294
+						$out[] = call_user_func_array($callback, array($items[$i]) + $params);
1295
+					}
1296
+				} elseif ($cnt === 1) {
1297
+					while (($i = array_shift($keys)) !== null) {
1298
+						$out[] = $callback($items[$i]);
1299
+					}
1300
+				} elseif ($cnt === 2) {
1301
+					while (($i = array_shift($keys)) !== null) {
1302
+						$out[] = $callback($items[$i], $params[1]);
1303
+					}
1304
+				} elseif ($cnt === 3) {
1305
+					while (($i = array_shift($keys)) !== null) {
1306
+						$out[] = $callback($items[$i], $params[1], $params[2]);
1307
+					}
1308
+				} elseif ($cnt === 4) {
1309
+					while (($i = array_shift($keys)) !== null) {
1310
+						$out[] = $callback($items[$i], $params[1], $params[2], $params[3]);
1311
+					}
1312
+				} else {
1313
+					while (($i = array_shift($keys)) !== null) {
1314
+						$out[] = call_user_func_array($callback, array($items[$i]) + $params);
1315
+					}
1316
+				}
1317
+			}
1318
+
1319
+			return $out;
1320
+		} else {
1321
+			return $params[0];
1322
+		}
1323
+	}
1324
+
1325
+	/**
1326
+	 * Reads a variable into the given data array.
1327
+	 *
1328
+	 * @param string $varstr   the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1329
+	 * @param mixed  $data     the data array or object to read from
1330
+	 * @param bool   $safeRead if true, the function will check whether the index exists to prevent any notices from
1331
+	 *                         being output
1332
+	 *
1333
+	 * @return mixed
1334
+	 */
1335
+	public function readVarInto($varstr, $data, $safeRead = false)
1336
+	{
1337
+		if ($data === null) {
1338
+			return null;
1339
+		}
1340
+
1341
+		if (is_array($varstr) === false) {
1342
+			preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1343
+		} else {
1344
+			$m = $varstr;
1345
+		}
1346
+		unset($varstr);
1347
+
1348
+		while (list($k, $sep) = each($m[1])) {
1349
+			if ($sep === '.' || $sep === '[' || $sep === '') {
1350
+				// strip enclosing quotes if present
1351
+				$m[2][$k] = preg_replace('#^(["\']?)(.*?)\1$#', '$2', $m[2][$k]);
1352
+
1353
+				if ((is_array($data) || $data instanceof ArrayAccess) && ($safeRead === false || isset($data[$m[2][$k]]))) {
1354
+					$data = $data[$m[2][$k]];
1355
+				} else {
1356
+					return null;
1357
+				}
1358
+			} else {
1359
+				if (is_object($data) && ($safeRead === false || isset($data->$m[2][$k]))) {
1360
+					$data = $data->$m[2][$k];
1361
+				} else {
1362
+					return null;
1363
+				}
1364
+			}
1365
+		}
1366
+
1367
+		return $data;
1368
+	}
1369
+
1370
+	/**
1371
+	 * Reads a variable into the parent scope.
1372
+	 *
1373
+	 * @param int    $parentLevels the amount of parent levels to go from the current scope
1374
+	 * @param string $varstr       the variable string, using dwoo variable syntax (i.e.
1375
+	 *                             "var.subvar[subsubvar]->property")
1376
+	 *
1377
+	 * @return mixed
1378
+	 */
1379
+	public function readParentVar($parentLevels, $varstr = null)
1380
+	{
1381
+		$tree = $this->scopeTree;
1382
+		$cur  = $this->data;
1383
+
1384
+		while ($parentLevels -- !== 0) {
1385
+			array_pop($tree);
1386
+		}
1387
+
1388
+		while (($i = array_shift($tree)) !== null) {
1389
+			if (is_object($cur)) {
1390
+				$cur = $cur->$i;
1391
+			} else {
1392
+				$cur = $cur[$i];
1393
+			}
1394
+		}
1395
+
1396
+		if ($varstr !== null) {
1397
+			return $this->readVarInto($varstr, $cur);
1398
+		} else {
1399
+			return $cur;
1400
+		}
1401
+	}
1402
+
1403
+	/**
1404
+	 * Reads a variable into the current scope.
1405
+	 *
1406
+	 * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1407
+	 *
1408
+	 * @return mixed
1409
+	 */
1410
+	public function readVar($varstr)
1411
+	{
1412
+		if (is_array($varstr) === true) {
1413
+			$m = $varstr;
1414
+			unset($varstr);
1415
+		} else {
1416
+			if (strstr($varstr, '.') === false && strstr($varstr, '[') === false && strstr($varstr, '->') === false) {
1417
+				if ($varstr === 'dwoo') {
1418
+					return $this->globals;
1419
+				} elseif ($varstr === '__' || $varstr === '_root') {
1420
+					return $this->data;
1421
+				} elseif ($varstr === '_' || $varstr === '_parent') {
1422
+					$varstr = '.' . $varstr;
1423
+					$tree   = $this->scopeTree;
1424
+					$cur    = $this->data;
1425
+					array_pop($tree);
1426
+
1427
+					while (($i = array_shift($tree)) !== null) {
1428
+						if (is_object($cur)) {
1429
+							$cur = $cur->$i;
1430
+						} else {
1431
+							$cur = $cur[$i];
1432
+						}
1433
+					}
1434
+
1435
+					return $cur;
1436
+				}
1437
+
1438
+				$cur = $this->scope;
1439
+
1440
+				if (isset($cur[$varstr])) {
1441
+					return $cur[$varstr];
1442
+				} else {
1443
+					return null;
1444
+				}
1445
+			}
1446
+
1447
+			if (substr($varstr, 0, 1) === '.') {
1448
+				$varstr = 'dwoo' . $varstr;
1449
+			}
1450
+
1451
+			preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1452
+		}
1453
+
1454
+		$i = $m[2][0];
1455
+		if ($i === 'dwoo') {
1456
+			$cur = $this->globals;
1457
+			array_shift($m[2]);
1458
+			array_shift($m[1]);
1459
+			switch ($m[2][0]) {
1460
+			case 'get':
1461
+				$cur = $_GET;
1462
+				break;
1463
+			case 'post':
1464
+				$cur = $_POST;
1465
+				break;
1466
+			case 'session':
1467
+				$cur = $_SESSION;
1468
+				break;
1469
+			case 'cookies':
1470
+			case 'cookie':
1471
+				$cur = $_COOKIE;
1472
+				break;
1473
+			case 'server':
1474
+				$cur = $_SERVER;
1475
+				break;
1476
+			case 'env':
1477
+				$cur = $_ENV;
1478
+				break;
1479
+			case 'request':
1480
+				$cur = $_REQUEST;
1481
+				break;
1482
+			case 'const':
1483
+				array_shift($m[2]);
1484
+				if (defined($m[2][0])) {
1485
+					return constant($m[2][0]);
1486
+				} else {
1487
+					return null;
1488
+				}
1489
+			}
1490
+			if ($cur !== $this->globals) {
1491
+				array_shift($m[2]);
1492
+				array_shift($m[1]);
1493
+			}
1494
+		} elseif ($i === '__' || $i === '_root') {
1495
+			$cur = $this->data;
1496
+			array_shift($m[2]);
1497
+			array_shift($m[1]);
1498
+		} elseif ($i === '_' || $i === '_parent') {
1499
+			$tree = $this->scopeTree;
1500
+			$cur  = $this->data;
1501
+
1502
+			while (true) {
1503
+				array_pop($tree);
1504
+				array_shift($m[2]);
1505
+				array_shift($m[1]);
1506
+				if (current($m[2]) === '_' || current($m[2]) === '_parent') {
1507
+					continue;
1508
+				}
1509
+
1510
+				while (($i = array_shift($tree)) !== null) {
1511
+					if (is_object($cur)) {
1512
+						$cur = $cur->$i;
1513
+					} else {
1514
+						$cur = $cur[$i];
1515
+					}
1516
+				}
1517
+				break;
1518
+			}
1519
+		} else {
1520
+			$cur = $this->scope;
1521
+		}
1522
+
1523
+		while (list($k, $sep) = each($m[1])) {
1524
+			if ($sep === '.' || $sep === '[' || $sep === '') {
1525
+				if ((is_array($cur) || $cur instanceof ArrayAccess) && isset($cur[$m[2][$k]])) {
1526
+					$cur = $cur[$m[2][$k]];
1527
+				} else {
1528
+					return null;
1529
+				}
1530
+			} elseif ($sep === '->') {
1531
+				if (is_object($cur)) {
1532
+					$cur = $cur->$m[2][$k];
1533
+				} else {
1534
+					return null;
1535
+				}
1536
+			} else {
1537
+				return null;
1538
+			}
1539
+		}
1540
+
1541
+		return $cur;
1542
+	}
1543
+
1544
+	/**
1545
+	 * Assign the value to the given variable.
1546
+	 *
1547
+	 * @param mixed  $value the value to assign
1548
+	 * @param string $scope the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1549
+	 *
1550
+	 * @return bool true if assigned correctly or false if a problem occured while parsing the var string
1551
+	 */
1552
+	public function assignInScope($value, $scope)
1553
+	{
1554
+		if (!is_string($scope)) {
1555
+			$this->triggerError('Assignments must be done into strings, (' . gettype($scope) . ') ' . var_export($scope, true) . ' given', E_USER_ERROR);
1556
+		}
1557
+		if (strstr($scope, '.') === false && strstr($scope, '->') === false) {
1558
+			$this->scope[$scope] = $value;
1559
+		} else {
1560
+			// TODO handle _root/_parent scopes ?
1561
+			preg_match_all('#(\[|->|\.)?([^.[\]-]+)\]?#i', $scope, $m);
1562
+
1563
+			$cur  = &$this->scope;
1564
+			$last = array(
1565
+				array_pop($m[1]),
1566
+				array_pop($m[2])
1567
+			);
1568
+
1569
+			while (list($k, $sep) = each($m[1])) {
1570
+				if ($sep === '.' || $sep === '[' || $sep === '') {
1571
+					if (is_array($cur) === false) {
1572
+						$cur = array();
1573
+					}
1574
+					$cur = &$cur[$m[2][$k]];
1575
+				} elseif ($sep === '->') {
1576
+					if (is_object($cur) === false) {
1577
+						$cur = new stdClass();
1578
+					}
1579
+					$cur = &$cur->$m[2][$k];
1580
+				} else {
1581
+					return false;
1582
+				}
1583
+			}
1584
+
1585
+			if ($last[0] === '.' || $last[0] === '[' || $last[0] === '') {
1586
+				if (is_array($cur) === false) {
1587
+					$cur = array();
1588
+				}
1589
+				$cur[$last[1]] = $value;
1590
+			} elseif ($last[0] === '->') {
1591
+				if (is_object($cur) === false) {
1592
+					$cur = new stdClass();
1593
+				}
1594
+				$cur->$last[1] = $value;
1595
+			} else {
1596
+				return false;
1597
+			}
1598
+		}
1599
+	}
1600
+
1601
+	/**
1602
+	 * Sets the scope to the given scope string or array.
1603
+	 *
1604
+	 * @param mixed $scope    a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1605
+	 * @param bool  $absolute if true, the scope is set from the top level scope and not from the current scope
1606
+	 *
1607
+	 * @return array the current scope tree
1608
+	 */
1609
+	public function setScope($scope, $absolute = false)
1610
+	{
1611
+		$old = $this->scopeTree;
1612
+
1613
+		if (is_string($scope) === true) {
1614
+			$scope = explode('.', $scope);
1615
+		}
1616
+
1617
+		if ($absolute === true) {
1618
+			$this->scope     = &$this->data;
1619
+			$this->scopeTree = array();
1620
+		}
1621
+
1622
+		while (($bit = array_shift($scope)) !== null) {
1623
+			if ($bit === '_' || $bit === '_parent') {
1624
+				array_pop($this->scopeTree);
1625
+				$this->scope = &$this->data;
1626
+				$cnt         = count($this->scopeTree);
1627
+				for ($i = 0; $i < $cnt; ++ $i) {
1628
+					$this->scope = &$this->scope[$this->scopeTree[$i]];
1629
+				}
1630
+			} elseif ($bit === '__' || $bit === '_root') {
1631
+				$this->scope     = &$this->data;
1632
+				$this->scopeTree = array();
1633
+			} elseif (isset($this->scope[$bit])) {
1634
+				if ($this->scope instanceof ArrayAccess) {
1635
+					$tmp         = $this->scope[$bit];
1636
+					$this->scope = &$tmp;
1637
+				} else {
1638
+					$this->scope = &$this->scope[$bit];
1639
+				}
1640
+				$this->scopeTree[] = $bit;
1641
+			} else {
1642
+				unset($this->scope);
1643
+				$this->scope = null;
1644
+			}
1645
+		}
1646
+
1647
+		return $old;
1648
+	}
1649
+
1650
+	/**
1651
+	 * Returns the entire data array.
1652
+	 *
1653
+	 * @return array
1654
+	 */
1655
+	public function getData()
1656
+	{
1657
+		return $this->data;
1658
+	}
1659
+
1660
+	/**
1661
+	 * Sets a return value for the currently running template.
1662
+	 *
1663
+	 * @param string $name  var name
1664
+	 * @param mixed  $value var value
1665
+	 *
1666
+	 * @return void
1667
+	 */
1668
+	public function setReturnValue($name, $value)
1669
+	{
1670
+		$this->returnData[$name] = $value;
1671
+	}
1672
+
1673
+	/**
1674
+	 * Retrieves the return values set by the template.
1675
+	 *
1676
+	 * @return array
1677
+	 */
1678
+	public function getReturnValues()
1679
+	{
1680
+		return $this->returnData;
1681
+	}
1682
+
1683
+	/**
1684
+	 * Returns a reference to the current scope.
1685
+	 *
1686
+	 * @return mixed
1687
+	 */
1688
+	public function &getScope()
1689
+	{
1690
+		return $this->scope;
1691
+	}
1692
+
1693
+	/**
1694
+	 * Redirects all calls to unexisting to plugin proxy.
1695
+	 *
1696
+	 * @param string $method the method name
1697
+	 * @param array  $args   array of arguments
1698
+	 *
1699
+	 * @return mixed
1700
+	 * @throws Exception
1701
+	 */
1702
+	public function __call($method, $args)
1703
+	{
1704
+		$proxy = $this->getPluginProxy();
1705
+		if (!$proxy) {
1706
+			throw new Exception('Call to undefined method ' . __CLASS__ . '::' . $method . '()');
1707
+		}
1708
+
1709
+		return call_user_func_array($proxy->getCallback($method), $args);
1710
+	}
1711
+
1712
+	/**
1713
+	 * Convert plugin name from `auto_escape` to `AutoEscape`.
1714
+	 * @param string $input
1715
+	 * @param string $separator
1716
+	 *
1717
+	 * @return mixed
1718
+	 */
1719
+	public static function toCamelCase($input, $separator = '_')
1720
+	{
1721
+		return join(array_map('ucfirst', explode($separator, $input)));
1722
+
1723
+		// TODO >= PHP5.4.32
1724
+		//return str_replace($separator, '', ucwords($input, $separator));
1725
+	}
1726 1726
 }
Please login to merge, or discard this patch.
lib/Dwoo/Filter.php 1 patch
Indentation   +24 added lines, -24 removed lines patch added patch discarded remove patch
@@ -23,30 +23,30 @@
 block discarded – undo
23 23
  */
24 24
 abstract class Filter
25 25
 {
26
-    /**
27
-     * The dwoo instance that runs this filter.
28
-     *
29
-     * @var Core
30
-     */
31
-    protected $dwoo;
26
+	/**
27
+	 * The dwoo instance that runs this filter.
28
+	 *
29
+	 * @var Core
30
+	 */
31
+	protected $dwoo;
32 32
 
33
-    /**
34
-     * Constructor, if you override it, call parent::__construct($dwoo); or assign
35
-     * the dwoo instance yourself if you need it.
36
-     *
37
-     * @param Core $dwoo the dwoo instance that runs this plugin
38
-     */
39
-    public function __construct(Core $dwoo)
40
-    {
41
-        $this->dwoo = $dwoo;
42
-    }
33
+	/**
34
+	 * Constructor, if you override it, call parent::__construct($dwoo); or assign
35
+	 * the dwoo instance yourself if you need it.
36
+	 *
37
+	 * @param Core $dwoo the dwoo instance that runs this plugin
38
+	 */
39
+	public function __construct(Core $dwoo)
40
+	{
41
+		$this->dwoo = $dwoo;
42
+	}
43 43
 
44
-    /**
45
-     * Processes the input and returns it filtered.
46
-     *
47
-     * @param string $input the template to process
48
-     *
49
-     * @return string
50
-     */
51
-    abstract public function process($input);
44
+	/**
45
+	 * Processes the input and returns it filtered.
46
+	 *
47
+	 * @param string $input the template to process
48
+	 *
49
+	 * @return string
50
+	 */
51
+	abstract public function process($input);
52 52
 }
Please login to merge, or discard this patch.
lib/Dwoo/ILoader.php 1 patch
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -23,15 +23,15 @@
 block discarded – undo
23 23
  */
24 24
 interface ILoader
25 25
 {
26
-    /**
27
-     * Loads a plugin file.
28
-     * the second parameter is used to avoid permanent rehashing when using php functions,
29
-     * however this means that if you have add a plugin that overrides a php function you have
30
-     * to delete the classpath.cache file(s) by hand to force a rehash of the plugins
31
-     *
32
-     * @param string $class       the plugin name, without the `Plugin` prefix
33
-     * @param bool   $forceRehash if true, the class path caches will be rebuilt if the plugin is not found, in case it
34
-     *                            has just been added, defaults to true
35
-     */
36
-    public function loadPlugin($class, $forceRehash = true);
26
+	/**
27
+	 * Loads a plugin file.
28
+	 * the second parameter is used to avoid permanent rehashing when using php functions,
29
+	 * however this means that if you have add a plugin that overrides a php function you have
30
+	 * to delete the classpath.cache file(s) by hand to force a rehash of the plugins
31
+	 *
32
+	 * @param string $class       the plugin name, without the `Plugin` prefix
33
+	 * @param bool   $forceRehash if true, the class path caches will be rebuilt if the plugin is not found, in case it
34
+	 *                            has just been added, defaults to true
35
+	 */
36
+	public function loadPlugin($class, $forceRehash = true);
37 37
 }
Please login to merge, or discard this patch.
lib/Dwoo/ICompilable.php 1 patch
Indentation   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -26,6 +26,6 @@
 block discarded – undo
26 26
  */
27 27
 interface ICompilable
28 28
 {
29
-    // this replaces the process function
30
-    //public static function compile(Compiler $compiler, $arg, $arg, ...);
29
+	// this replaces the process function
30
+	//public static function compile(Compiler $compiler, $arg, $arg, ...);
31 31
 }
Please login to merge, or discard this patch.