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