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