Completed
Push — master ( a400a4...020752 )
by David
07:41 queued 04:43
created
lib/Dwoo/Core.php 1 patch
Indentation   +1734 added lines, -1734 removed lines patch added patch discarded remove patch
@@ -44,1744 +44,1744 @@
 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.4';
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 = 134;
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
-    protected $globals = array();
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
-     * Directory where the template files are stored
135
-     *
136
-     * @var array
137
-     */
138
-    protected $templateDir = array();
139
-
140
-    /**
141
-     * Defines how long (in seconds) the cached files must remain valid.
142
-     * can be overridden on a per-template basis
143
-     * -1 = never delete
144
-     * 0 = disabled
145
-     * >0 = duration in seconds
146
-     *
147
-     * @var int
148
-     */
149
-    protected $cacheTime = 0;
150
-
151
-    /**
152
-     * Security policy object.
153
-     *
154
-     * @var SecurityPolicy
155
-     */
156
-    protected $securityPolicy = null;
157
-
158
-    /**
159
-     * Stores the custom plugins callbacks.
160
-     *
161
-     * @see addPlugin
162
-     * @see removePlugin
163
-     * @var array
164
-     */
165
-    protected $plugins = array();
166
-
167
-    /**
168
-     * Stores the filter callbacks.
169
-     *
170
-     * @see addFilter
171
-     * @see removeFilter
172
-     * @var array
173
-     */
174
-    protected $filters = array();
175
-
176
-    /**
177
-     * Stores the resource types and associated
178
-     * classes / compiler classes.
179
-     *
180
-     * @var array
181
-     */
182
-    protected $resources = array(
183
-        'file'   => array(
184
-            'class'    => 'Dwoo\Template\File',
185
-            'compiler' => null,
186
-        ),
187
-        'string' => array(
188
-            'class'    => 'Dwoo\Template\Str',
189
-            'compiler' => null,
190
-        ),
191
-    );
192
-
193
-    /**
194
-     * The dwoo loader object used to load plugins by this dwoo instance.
195
-     *
196
-     * @var ILoader
197
-     */
198
-    protected $loader = null;
199
-
200
-    /**
201
-     * Currently rendered template, set to null when not-rendering.
202
-     *
203
-     * @var ITemplate
204
-     */
205
-    protected $template = null;
206
-
207
-    /**
208
-     * Stores the instances of the class plugins during template runtime.
209
-     *
210
-     * @var array
211
-     */
212
-    protected $runtimePlugins = array();
213
-
214
-    /**
215
-     * Stores the returned values during template runtime.
216
-     *
217
-     * @var array
218
-     */
219
-    protected $returnData = array();
220
-
221
-    /**
222
-     * Stores the data during template runtime.
223
-     *
224
-     * @var array
225
-     */
226
-    protected $data = array();
227
-
228
-    /**
229
-     * Stores the current scope during template runtime.
230
-     * this should ideally not be accessed directly from outside template code
231
-     *
232
-     * @var mixed
233
-     */
234
-    public $scope;
235
-
236
-    /**
237
-     * Stores the scope tree during template runtime.
238
-     *
239
-     * @var array
240
-     */
241
-    protected $scopeTree = array();
242
-
243
-    /**
244
-     * Stores the block plugins stack during template runtime.
245
-     *
246
-     * @var array
247
-     */
248
-    protected $stack = array();
249
-
250
-    /**
251
-     * Stores the current block plugin at the top of the stack during template runtime.
252
-     *
253
-     * @var BlockPlugin
254
-     */
255
-    protected $curBlock;
256
-
257
-    /**
258
-     * Stores the output buffer during template runtime.
259
-     *
260
-     * @var string
261
-     */
262
-    protected $buffer;
263
-
264
-    /**
265
-     * Stores plugin proxy.
266
-     *
267
-     * @var IPluginProxy
268
-     */
269
-    protected $pluginProxy;
270
-
271
-    /**
272
-     * Constructor, sets the cache and compile dir to the default values if not provided.
273
-     *
274
-     * @param string $compileDir path to the compiled directory, defaults to lib/compiled
275
-     * @param string $cacheDir   path to the cache directory, defaults to lib/cache
276
-     */
277
-    public function __construct($compileDir = null, $cacheDir = null)
278
-    {
279
-        if ($compileDir !== null) {
280
-            $this->setCompileDir($compileDir);
281
-        }
282
-        if ($cacheDir !== null) {
283
-            $this->setCacheDir($cacheDir);
284
-        }
285
-        $this->initGlobals();
286
-    }
287
-
288
-    /**
289
-     * Resets some runtime variables to allow a cloned object to be used to render sub-templates.
290
-     *
291
-     * @return void
292
-     */
293
-    public function __clone()
294
-    {
295
-        $this->template = null;
296
-        unset($this->data);
297
-        unset($this->returnData);
298
-    }
299
-
300
-    /**
301
-     * Returns the given template rendered using the provided data and optional compiler.
302
-     *
303
-     * @param mixed     $_tpl      template, can either be a ITemplate object (i.e. TemplateFile), a
304
-     *                             valid path to a template, or a template as a string it is recommended to
305
-     *                             provide a ITemplate as it will probably make things faster, especially if
306
-     *                             you render a template multiple times
307
-     * @param mixed     $data      the data to use, can either be a IDataProvider object (i.e. Data) or
308
-     *                             an associative array. if you're rendering the template from cache, it can be
309
-     *                             left null
310
-     * @param ICompiler $_compiler the compiler that must be used to compile the template, if left empty a default
311
-     *                             Compiler will be used
312
-     *
313
-     * @return string|void or the template output if $output is false
314
-     * @throws Exception
315
-     */
316
-    public function get($_tpl, $data = array(), $_compiler = null)
317
-    {
318
-        // a render call came from within a template, so we need a new dwoo instance in order to avoid breaking this one
319
-        if ($this->template instanceof ITemplate) {
320
-            $clone = clone $this;
321
-
322
-            return $clone->get($_tpl, $data, $_compiler);
323
-        }
324
-
325
-        // auto-create template if required
326
-        if ($_tpl instanceof ITemplate) {
327
-            // valid, skip
328
-        } elseif (is_string($_tpl)) {
329
-            $_tpl = new TemplateFile($_tpl);
330
-            $_tpl->setIncludePath($this->getTemplateDir());
331
-        } else {
332
-            throw new Exception('Dwoo->get\'s first argument must be a ITemplate (i.e. TemplateFile) or a valid path to a template file', E_USER_NOTICE);
333
-        }
334
-
335
-        // save the current template, enters render mode at the same time
336
-        // if another rendering is requested it will be proxied to a new Core(instance
337
-        $this->template = $_tpl;
338
-
339
-        // load data
340
-        if ($data instanceof IDataProvider) {
341
-            $this->data = $data->getData();
342
-        } elseif (is_array($data)) {
343
-            $this->data = $data;
344
-        } elseif ($data instanceof ArrayAccess) {
345
-            $this->data = $data;
346
-        } else {
347
-            throw new Exception('Dwoo->get/Dwoo->output\'s data argument must be a IDataProvider object (i.e. Data) or an associative array', E_USER_NOTICE);
348
-        }
349
-
350
-        $this->addGlobal('template', $_tpl->getName());
351
-        $this->initRuntimeVars($_tpl);
352
-
353
-        // try to get cached template
354
-        $file        = $_tpl->getCachedTemplate($this);
355
-        $doCache     = $file === true;
356
-        $cacheLoaded = is_string($file);
357
-
358
-        if ($cacheLoaded === true) {
359
-            // cache is present, run it
360
-            ob_start();
361
-            include $file;
362
-            $this->template = null;
363
-
364
-            return ob_get_clean();
365
-        } else {
366
-            $dynamicId = uniqid();
367
-
368
-            // render template
369
-            $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
370
-            $out              = include $compiledTemplate;
371
-
372
-            // template returned false so it needs to be recompiled
373
-            if ($out === false) {
374
-                $_tpl->forceCompilation();
375
-                $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
376
-                $out              = include $compiledTemplate;
377
-            }
378
-
379
-            if ($doCache === true) {
380
-                $out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php /*' . $dynamicId . '*/ echo \'$1\'; ?>', $out);
381
-                if (!class_exists(self::NAMESPACE_PLUGINS_BLOCKS . 'PluginDynamic')) {
382
-                    $this->getLoader()->loadPlugin('PluginDynamic');
383
-                }
384
-                $out = PluginDynamic::unescape($out, $dynamicId, $compiledTemplate);
385
-            }
386
-
387
-            // process filters
388
-            foreach ($this->filters as $filter) {
389
-                if (is_array($filter) && $filter[0] instanceof Filter) {
390
-                    $out = call_user_func($filter, $out);
391
-                } else {
392
-                    $out = call_user_func($filter, $this, $out);
393
-                }
394
-            }
395
-
396
-            if ($doCache === true) {
397
-                // building cache
398
-                $file = $_tpl->cache($this, $out);
399
-
400
-                // run it from the cache to be sure dynamics are rendered
401
-                ob_start();
402
-                include $file;
403
-                // exit render mode
404
-                $this->template = null;
405
-
406
-                return ob_get_clean();
407
-            } else {
408
-                // no need to build cache
409
-                // exit render mode
410
-                $this->template = null;
411
-
412
-                return $out;
413
-            }
414
-        }
415
-    }
416
-
417
-    /**
418
-     * Registers a Global.
419
-     * New globals can be added before compiling or rendering a template
420
-     * but after, you can only update existing globals.
421
-     *
422
-     * @param string $name
423
-     * @param mixed  $value
424
-     *
425
-     * @return $this
426
-     * @throws Exception
427
-     */
428
-    public function addGlobal($name, $value)
429
-    {
430
-        if (null === $this->globals) {
431
-            $this->initGlobals();
432
-        }
433
-
434
-        $this->globals[$name] = $value;
435
-
436
-        return $this;
437
-    }
438
-
439
-    /**
440
-     * Gets the registered Globals.
441
-     *
442
-     * @return array
443
-     */
444
-    public function getGlobals()
445
-    {
446
-        return $this->globals;
447
-    }
448
-
449
-    /**
450
-     * Re-initializes the globals array before each template run.
451
-     * this method is only callede once when the Dwoo object is created
452
-     *
453
-     * @return void
454
-     */
455
-    protected function initGlobals()
456
-    {
457
-        $this->globals = array(
458
-            'version' => self::VERSION,
459
-            'ad'      => '<a href="http://dwoo.org/">Powered by Dwoo</a>',
460
-            'now'     => $_SERVER['REQUEST_TIME'],
461
-            'charset' => $this->getCharset(),
462
-        );
463
-    }
464
-
465
-    /**
466
-     * Re-initializes the runtime variables before each template run.
467
-     * override this method to inject data in the globals array if needed, this
468
-     * method is called before each template execution
469
-     *
470
-     * @param ITemplate $tpl the template that is going to be rendered
471
-     *
472
-     * @return void
473
-     */
474
-    protected function initRuntimeVars(ITemplate $tpl)
475
-    {
476
-        $this->runtimePlugins = array();
477
-        $this->scope          = &$this->data;
478
-        $this->scopeTree      = array();
479
-        $this->stack          = array();
480
-        $this->curBlock       = null;
481
-        $this->buffer         = '';
482
-        $this->returnData     = array();
483
-    }
484
-
485
-    /**
486
-     * Adds a custom plugin that is not in one of the plugin directories.
487
-     *
488
-     * @param string   $name       the plugin name to be used in the templates
489
-     * @param callback $callback   the plugin callback, either a function name,
490
-     *                             a class name or an array containing an object
491
-     *                             or class name and a method name
492
-     * @param bool     $compilable if set to true, the plugin is assumed to be compilable
493
-     *
494
-     * @return void
495
-     * @throws Exception
496
-     */
497
-    public function addPlugin($name, $callback, $compilable = false)
498
-    {
499
-        $compilable = $compilable ? self::COMPILABLE_PLUGIN : 0;
500
-        if (is_array($callback)) {
501
-            if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo\Block\Plugin')) {
502
-                $this->plugins[$name] = array(
503
-                    'type'     => self::BLOCK_PLUGIN | $compilable,
504
-                    'callback' => $callback,
505
-                    'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0])
506
-                );
507
-            } else {
508
-                $this->plugins[$name] = array(
509
-                    'type'     => self::CLASS_PLUGIN | $compilable,
510
-                    'callback' => $callback,
511
-                    'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0]),
512
-                    'function' => $callback[1]
513
-                );
514
-            }
515
-        } elseif (is_string($callback)) {
516
-            if (class_exists($callback)) {
517
-                if (is_subclass_of($callback, 'Dwoo\Block\Plugin')) {
518
-                    $this->plugins[$name] = array(
519
-                        'type'     => self::BLOCK_PLUGIN | $compilable,
520
-                        'callback' => $callback,
521
-                        'class'    => $callback
522
-                    );
523
-                } else {
524
-                    $this->plugins[$name] = array(
525
-                        'type'     => self::CLASS_PLUGIN | $compilable,
526
-                        'callback' => $callback,
527
-                        'class'    => $callback,
528
-                        'function' => ($compilable ? 'compile' : 'process')
529
-                    );
530
-                }
531
-            } elseif (function_exists($callback)) {
532
-                $this->plugins[$name] = array(
533
-                    'type'     => self::FUNC_PLUGIN | $compilable,
534
-                    'callback' => $callback
535
-                );
536
-            } else {
537
-                throw new Exception(
538
-                    'Callback could not be processed correctly, please check that the function/class 
47
+	/**
48
+	 * Current version number.
49
+	 *
50
+	 * @var string
51
+	 */
52
+	const VERSION = '1.3.4';
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 = 134;
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
+	protected $globals = array();
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
+	 * Directory where the template files are stored
135
+	 *
136
+	 * @var array
137
+	 */
138
+	protected $templateDir = array();
139
+
140
+	/**
141
+	 * Defines how long (in seconds) the cached files must remain valid.
142
+	 * can be overridden on a per-template basis
143
+	 * -1 = never delete
144
+	 * 0 = disabled
145
+	 * >0 = duration in seconds
146
+	 *
147
+	 * @var int
148
+	 */
149
+	protected $cacheTime = 0;
150
+
151
+	/**
152
+	 * Security policy object.
153
+	 *
154
+	 * @var SecurityPolicy
155
+	 */
156
+	protected $securityPolicy = null;
157
+
158
+	/**
159
+	 * Stores the custom plugins callbacks.
160
+	 *
161
+	 * @see addPlugin
162
+	 * @see removePlugin
163
+	 * @var array
164
+	 */
165
+	protected $plugins = array();
166
+
167
+	/**
168
+	 * Stores the filter callbacks.
169
+	 *
170
+	 * @see addFilter
171
+	 * @see removeFilter
172
+	 * @var array
173
+	 */
174
+	protected $filters = array();
175
+
176
+	/**
177
+	 * Stores the resource types and associated
178
+	 * classes / compiler classes.
179
+	 *
180
+	 * @var array
181
+	 */
182
+	protected $resources = array(
183
+		'file'   => array(
184
+			'class'    => 'Dwoo\Template\File',
185
+			'compiler' => null,
186
+		),
187
+		'string' => array(
188
+			'class'    => 'Dwoo\Template\Str',
189
+			'compiler' => null,
190
+		),
191
+	);
192
+
193
+	/**
194
+	 * The dwoo loader object used to load plugins by this dwoo instance.
195
+	 *
196
+	 * @var ILoader
197
+	 */
198
+	protected $loader = null;
199
+
200
+	/**
201
+	 * Currently rendered template, set to null when not-rendering.
202
+	 *
203
+	 * @var ITemplate
204
+	 */
205
+	protected $template = null;
206
+
207
+	/**
208
+	 * Stores the instances of the class plugins during template runtime.
209
+	 *
210
+	 * @var array
211
+	 */
212
+	protected $runtimePlugins = array();
213
+
214
+	/**
215
+	 * Stores the returned values during template runtime.
216
+	 *
217
+	 * @var array
218
+	 */
219
+	protected $returnData = array();
220
+
221
+	/**
222
+	 * Stores the data during template runtime.
223
+	 *
224
+	 * @var array
225
+	 */
226
+	protected $data = array();
227
+
228
+	/**
229
+	 * Stores the current scope during template runtime.
230
+	 * this should ideally not be accessed directly from outside template code
231
+	 *
232
+	 * @var mixed
233
+	 */
234
+	public $scope;
235
+
236
+	/**
237
+	 * Stores the scope tree during template runtime.
238
+	 *
239
+	 * @var array
240
+	 */
241
+	protected $scopeTree = array();
242
+
243
+	/**
244
+	 * Stores the block plugins stack during template runtime.
245
+	 *
246
+	 * @var array
247
+	 */
248
+	protected $stack = array();
249
+
250
+	/**
251
+	 * Stores the current block plugin at the top of the stack during template runtime.
252
+	 *
253
+	 * @var BlockPlugin
254
+	 */
255
+	protected $curBlock;
256
+
257
+	/**
258
+	 * Stores the output buffer during template runtime.
259
+	 *
260
+	 * @var string
261
+	 */
262
+	protected $buffer;
263
+
264
+	/**
265
+	 * Stores plugin proxy.
266
+	 *
267
+	 * @var IPluginProxy
268
+	 */
269
+	protected $pluginProxy;
270
+
271
+	/**
272
+	 * Constructor, sets the cache and compile dir to the default values if not provided.
273
+	 *
274
+	 * @param string $compileDir path to the compiled directory, defaults to lib/compiled
275
+	 * @param string $cacheDir   path to the cache directory, defaults to lib/cache
276
+	 */
277
+	public function __construct($compileDir = null, $cacheDir = null)
278
+	{
279
+		if ($compileDir !== null) {
280
+			$this->setCompileDir($compileDir);
281
+		}
282
+		if ($cacheDir !== null) {
283
+			$this->setCacheDir($cacheDir);
284
+		}
285
+		$this->initGlobals();
286
+	}
287
+
288
+	/**
289
+	 * Resets some runtime variables to allow a cloned object to be used to render sub-templates.
290
+	 *
291
+	 * @return void
292
+	 */
293
+	public function __clone()
294
+	{
295
+		$this->template = null;
296
+		unset($this->data);
297
+		unset($this->returnData);
298
+	}
299
+
300
+	/**
301
+	 * Returns the given template rendered using the provided data and optional compiler.
302
+	 *
303
+	 * @param mixed     $_tpl      template, can either be a ITemplate object (i.e. TemplateFile), a
304
+	 *                             valid path to a template, or a template as a string it is recommended to
305
+	 *                             provide a ITemplate as it will probably make things faster, especially if
306
+	 *                             you render a template multiple times
307
+	 * @param mixed     $data      the data to use, can either be a IDataProvider object (i.e. Data) or
308
+	 *                             an associative array. if you're rendering the template from cache, it can be
309
+	 *                             left null
310
+	 * @param ICompiler $_compiler the compiler that must be used to compile the template, if left empty a default
311
+	 *                             Compiler will be used
312
+	 *
313
+	 * @return string|void or the template output if $output is false
314
+	 * @throws Exception
315
+	 */
316
+	public function get($_tpl, $data = array(), $_compiler = null)
317
+	{
318
+		// a render call came from within a template, so we need a new dwoo instance in order to avoid breaking this one
319
+		if ($this->template instanceof ITemplate) {
320
+			$clone = clone $this;
321
+
322
+			return $clone->get($_tpl, $data, $_compiler);
323
+		}
324
+
325
+		// auto-create template if required
326
+		if ($_tpl instanceof ITemplate) {
327
+			// valid, skip
328
+		} elseif (is_string($_tpl)) {
329
+			$_tpl = new TemplateFile($_tpl);
330
+			$_tpl->setIncludePath($this->getTemplateDir());
331
+		} else {
332
+			throw new Exception('Dwoo->get\'s first argument must be a ITemplate (i.e. TemplateFile) or a valid path to a template file', E_USER_NOTICE);
333
+		}
334
+
335
+		// save the current template, enters render mode at the same time
336
+		// if another rendering is requested it will be proxied to a new Core(instance
337
+		$this->template = $_tpl;
338
+
339
+		// load data
340
+		if ($data instanceof IDataProvider) {
341
+			$this->data = $data->getData();
342
+		} elseif (is_array($data)) {
343
+			$this->data = $data;
344
+		} elseif ($data instanceof ArrayAccess) {
345
+			$this->data = $data;
346
+		} else {
347
+			throw new Exception('Dwoo->get/Dwoo->output\'s data argument must be a IDataProvider object (i.e. Data) or an associative array', E_USER_NOTICE);
348
+		}
349
+
350
+		$this->addGlobal('template', $_tpl->getName());
351
+		$this->initRuntimeVars($_tpl);
352
+
353
+		// try to get cached template
354
+		$file        = $_tpl->getCachedTemplate($this);
355
+		$doCache     = $file === true;
356
+		$cacheLoaded = is_string($file);
357
+
358
+		if ($cacheLoaded === true) {
359
+			// cache is present, run it
360
+			ob_start();
361
+			include $file;
362
+			$this->template = null;
363
+
364
+			return ob_get_clean();
365
+		} else {
366
+			$dynamicId = uniqid();
367
+
368
+			// render template
369
+			$compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
370
+			$out              = include $compiledTemplate;
371
+
372
+			// template returned false so it needs to be recompiled
373
+			if ($out === false) {
374
+				$_tpl->forceCompilation();
375
+				$compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
376
+				$out              = include $compiledTemplate;
377
+			}
378
+
379
+			if ($doCache === true) {
380
+				$out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php /*' . $dynamicId . '*/ echo \'$1\'; ?>', $out);
381
+				if (!class_exists(self::NAMESPACE_PLUGINS_BLOCKS . 'PluginDynamic')) {
382
+					$this->getLoader()->loadPlugin('PluginDynamic');
383
+				}
384
+				$out = PluginDynamic::unescape($out, $dynamicId, $compiledTemplate);
385
+			}
386
+
387
+			// process filters
388
+			foreach ($this->filters as $filter) {
389
+				if (is_array($filter) && $filter[0] instanceof Filter) {
390
+					$out = call_user_func($filter, $out);
391
+				} else {
392
+					$out = call_user_func($filter, $this, $out);
393
+				}
394
+			}
395
+
396
+			if ($doCache === true) {
397
+				// building cache
398
+				$file = $_tpl->cache($this, $out);
399
+
400
+				// run it from the cache to be sure dynamics are rendered
401
+				ob_start();
402
+				include $file;
403
+				// exit render mode
404
+				$this->template = null;
405
+
406
+				return ob_get_clean();
407
+			} else {
408
+				// no need to build cache
409
+				// exit render mode
410
+				$this->template = null;
411
+
412
+				return $out;
413
+			}
414
+		}
415
+	}
416
+
417
+	/**
418
+	 * Registers a Global.
419
+	 * New globals can be added before compiling or rendering a template
420
+	 * but after, you can only update existing globals.
421
+	 *
422
+	 * @param string $name
423
+	 * @param mixed  $value
424
+	 *
425
+	 * @return $this
426
+	 * @throws Exception
427
+	 */
428
+	public function addGlobal($name, $value)
429
+	{
430
+		if (null === $this->globals) {
431
+			$this->initGlobals();
432
+		}
433
+
434
+		$this->globals[$name] = $value;
435
+
436
+		return $this;
437
+	}
438
+
439
+	/**
440
+	 * Gets the registered Globals.
441
+	 *
442
+	 * @return array
443
+	 */
444
+	public function getGlobals()
445
+	{
446
+		return $this->globals;
447
+	}
448
+
449
+	/**
450
+	 * Re-initializes the globals array before each template run.
451
+	 * this method is only callede once when the Dwoo object is created
452
+	 *
453
+	 * @return void
454
+	 */
455
+	protected function initGlobals()
456
+	{
457
+		$this->globals = array(
458
+			'version' => self::VERSION,
459
+			'ad'      => '<a href="http://dwoo.org/">Powered by Dwoo</a>',
460
+			'now'     => $_SERVER['REQUEST_TIME'],
461
+			'charset' => $this->getCharset(),
462
+		);
463
+	}
464
+
465
+	/**
466
+	 * Re-initializes the runtime variables before each template run.
467
+	 * override this method to inject data in the globals array if needed, this
468
+	 * method is called before each template execution
469
+	 *
470
+	 * @param ITemplate $tpl the template that is going to be rendered
471
+	 *
472
+	 * @return void
473
+	 */
474
+	protected function initRuntimeVars(ITemplate $tpl)
475
+	{
476
+		$this->runtimePlugins = array();
477
+		$this->scope          = &$this->data;
478
+		$this->scopeTree      = array();
479
+		$this->stack          = array();
480
+		$this->curBlock       = null;
481
+		$this->buffer         = '';
482
+		$this->returnData     = array();
483
+	}
484
+
485
+	/**
486
+	 * Adds a custom plugin that is not in one of the plugin directories.
487
+	 *
488
+	 * @param string   $name       the plugin name to be used in the templates
489
+	 * @param callback $callback   the plugin callback, either a function name,
490
+	 *                             a class name or an array containing an object
491
+	 *                             or class name and a method name
492
+	 * @param bool     $compilable if set to true, the plugin is assumed to be compilable
493
+	 *
494
+	 * @return void
495
+	 * @throws Exception
496
+	 */
497
+	public function addPlugin($name, $callback, $compilable = false)
498
+	{
499
+		$compilable = $compilable ? self::COMPILABLE_PLUGIN : 0;
500
+		if (is_array($callback)) {
501
+			if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo\Block\Plugin')) {
502
+				$this->plugins[$name] = array(
503
+					'type'     => self::BLOCK_PLUGIN | $compilable,
504
+					'callback' => $callback,
505
+					'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0])
506
+				);
507
+			} else {