Completed
Push — master ( 67fff9...3dcfcd )
by David
08:00 queued 03:38
created
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 overridden 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 overridden 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