Passed
Push — master ( 32c874...a28393 )
by David
57s
created
lib/Dwoo/Template/File.php 3 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -18,7 +18,6 @@
 block discarded – undo
18 18
 
19 19
 use Dwoo\Exception as DwooException;
20 20
 use Dwoo\Core as Core;
21
-use Dwoo\ICompiler;
22 21
 use Dwoo\ITemplate as ITemplate;
23 22
 use Dwoo\Security\Exception as SecurityException;
24 23
 use Dwoo\Template\File as TemplateFile;
Please login to merge, or discard this patch.
Indentation   +237 added lines, -237 removed lines patch added patch discarded remove patch
@@ -30,264 +30,264 @@
 block discarded – undo
30 30
  */
31 31
 class File extends Str
32 32
 {
33
-    /**
34
-     * Template filename.
35
-     *
36
-     * @var string
37
-     */
38
-    protected $file;
33
+	/**
34
+	 * Template filename.
35
+	 *
36
+	 * @var string
37
+	 */
38
+	protected $file;
39 39
 
40
-    /**
41
-     * Include path(s) to look into to find this template.
42
-     *
43
-     * @var array
44
-     */
45
-    protected $includePath = array();
40
+	/**
41
+	 * Include path(s) to look into to find this template.
42
+	 *
43
+	 * @var array
44
+	 */
45
+	protected $includePath = array();
46 46
 
47
-    /**
48
-     * Resolved path cache when looking for a file in multiple include paths.
49
-     * this is reset when the include path is changed
50
-     *
51
-     * @var string
52
-     */
53
-    protected $resolvedPath = null;
47
+	/**
48
+	 * Resolved path cache when looking for a file in multiple include paths.
49
+	 * this is reset when the include path is changed
50
+	 *
51
+	 * @var string
52
+	 */
53
+	protected $resolvedPath = null;
54 54
 
55
-    /**
56
-     * Creates a template from a file.
57
-     *
58
-     * @param string $file        the path to the template file, make sure it exists
59
-     * @param int    $cacheTime   duration of the cache validity for this template,
60
-     *                            if null it defaults to the Dwoo instance that will
61
-     *                            render this template
62
-     * @param string $cacheId     the unique cache identifier of this page or anything else that
63
-     *                            makes this template's content unique, if null it defaults
64
-     *                            to the current url
65
-     * @param string $compileId   the unique compiled identifier, which is used to distinguish this
66
-     *                            template from others, if null it defaults to the filename+bits of the path
67
-     * @param mixed  $includePath a string for a single path to look into for the given file, or an array of paths
68
-     */
69
-    public function __construct($file, $cacheTime = null, $cacheId = null, $compileId = null, $includePath = array())
70
-    {
71
-        parent::__construct($file, $cacheTime, $cacheId, $compileId);
72
-        $this->template = null;
73
-        $this->file     = $file;
74
-        $this->name     = basename($file);
75
-        $this->setIncludePath($includePath);
76
-    }
55
+	/**
56
+	 * Creates a template from a file.
57
+	 *
58
+	 * @param string $file        the path to the template file, make sure it exists
59
+	 * @param int    $cacheTime   duration of the cache validity for this template,
60
+	 *                            if null it defaults to the Dwoo instance that will
61
+	 *                            render this template
62
+	 * @param string $cacheId     the unique cache identifier of this page or anything else that
63
+	 *                            makes this template's content unique, if null it defaults
64
+	 *                            to the current url
65
+	 * @param string $compileId   the unique compiled identifier, which is used to distinguish this
66
+	 *                            template from others, if null it defaults to the filename+bits of the path
67
+	 * @param mixed  $includePath a string for a single path to look into for the given file, or an array of paths
68
+	 */
69
+	public function __construct($file, $cacheTime = null, $cacheId = null, $compileId = null, $includePath = array())
70
+	{
71
+		parent::__construct($file, $cacheTime, $cacheId, $compileId);
72
+		$this->template = null;
73
+		$this->file     = $file;
74
+		$this->name     = basename($file);
75
+		$this->setIncludePath($includePath);
76
+	}
77 77
 
78
-    /**
79
-     * Sets the include path(s) to where the given template filename must be looked up.
80
-     *
81
-     * @param mixed $paths the path to look into, can be string for a single path or an array of paths
82
-     */
83
-    public function setIncludePath($paths)
84
-    {
85
-        if (is_array($paths) === false) {
86
-            $paths = array($paths);
87
-        }
78
+	/**
79
+	 * Sets the include path(s) to where the given template filename must be looked up.
80
+	 *
81
+	 * @param mixed $paths the path to look into, can be string for a single path or an array of paths
82
+	 */
83
+	public function setIncludePath($paths)
84
+	{
85
+		if (is_array($paths) === false) {
86
+			$paths = array($paths);
87
+		}
88 88
 
89
-        $this->includePath  = $paths;
90
-        $this->resolvedPath = null;
91
-    }
89
+		$this->includePath  = $paths;
90
+		$this->resolvedPath = null;
91
+	}
92 92
 
93
-    /**
94
-     * Return the current include path(s).
95
-     *
96
-     * @return array
97
-     */
98
-    public function getIncludePath()
99
-    {
100
-        return $this->includePath;
101
-    }
93
+	/**
94
+	 * Return the current include path(s).
95
+	 *
96
+	 * @return array
97
+	 */
98
+	public function getIncludePath()
99
+	{
100
+		return $this->includePath;
101
+	}
102 102
 
103
-    /**
104
-     * Checks if compiled file is valid (exists and it's the modification is greater or
105
-     * equal to the modification time of the template file).
106
-     *
107
-     * @param string file
108
-     *
109
-     * @return bool True cache file existance and it's modification time
110
-     */
111
-    protected function isValidCompiledFile($file)
112
-    {
113
-        return parent::isValidCompiledFile($file) && (int)$this->getUid() <= filemtime($file);
114
-    }
103
+	/**
104
+	 * Checks if compiled file is valid (exists and it's the modification is greater or
105
+	 * equal to the modification time of the template file).
106
+	 *
107
+	 * @param string file
108
+	 *
109
+	 * @return bool True cache file existance and it's modification time
110
+	 */
111
+	protected function isValidCompiledFile($file)
112
+	{
113
+		return parent::isValidCompiledFile($file) && (int)$this->getUid() <= filemtime($file);
114
+	}
115 115
 
116
-    /**
117
-     * Returns the template source of this template.
118
-     *
119
-     * @return string
120
-     */
121
-    public function getSource()
122
-    {
123
-        return file_get_contents($this->getResourceIdentifier());
124
-    }
116
+	/**
117
+	 * Returns the template source of this template.
118
+	 *
119
+	 * @return string
120
+	 */
121
+	public function getSource()
122
+	{
123
+		return file_get_contents($this->getResourceIdentifier());
124
+	}
125 125
 
126
-    /**
127
-     * Returns the resource name for this template class.
128
-     *
129
-     * @return string
130
-     */
131
-    public function getResourceName()
132
-    {
133
-        return 'file';
134
-    }
126
+	/**
127
+	 * Returns the resource name for this template class.
128
+	 *
129
+	 * @return string
130
+	 */
131
+	public function getResourceName()
132
+	{
133
+		return 'file';
134
+	}
135 135
 
136
-    /**
137
-     * Returns this template's source filename.
138
-     *
139
-     * @return string
140
-     * @throws DwooException
141
-     */
142
-    public function getResourceIdentifier()
143
-    {
144
-        if ($this->resolvedPath !== null) {
145
-            return $this->resolvedPath;
146
-        } elseif (array_filter($this->getIncludePath()) == array()) {
147
-            return $this->file;
148
-        } else {
149
-            foreach ($this->getIncludePath() as $path) {
150
-                $path = rtrim($path, DIRECTORY_SEPARATOR);
151
-                if (file_exists($path . DIRECTORY_SEPARATOR . $this->file) === true) {
152
-                    return $this->resolvedPath = $path . DIRECTORY_SEPARATOR . $this->file;
153
-                }
154
-            }
136
+	/**
137
+	 * Returns this template's source filename.
138
+	 *
139
+	 * @return string
140
+	 * @throws DwooException
141
+	 */
142
+	public function getResourceIdentifier()
143
+	{
144
+		if ($this->resolvedPath !== null) {
145
+			return $this->resolvedPath;
146
+		} elseif (array_filter($this->getIncludePath()) == array()) {
147
+			return $this->file;
148
+		} else {
149
+			foreach ($this->getIncludePath() as $path) {
150
+				$path = rtrim($path, DIRECTORY_SEPARATOR);
151
+				if (file_exists($path . DIRECTORY_SEPARATOR . $this->file) === true) {
152
+					return $this->resolvedPath = $path . DIRECTORY_SEPARATOR . $this->file;
153
+				}
154
+			}
155 155
 
156
-            throw new DwooException('Template "' . $this->file . '" could not be found in any of your include path(s)');
157
-        }
158
-    }
156
+			throw new DwooException('Template "' . $this->file . '" could not be found in any of your include path(s)');
157
+		}
158
+	}
159 159
 
160
-    /**
161
-     * Returns an unique value identifying the current version of this template,
162
-     * in this case it's the unix timestamp of the last modification.
163
-     *
164
-     * @return string
165
-     */
166
-    public function getUid()
167
-    {
168
-        return (string)filemtime($this->getResourceIdentifier());
169
-    }
160
+	/**
161
+	 * Returns an unique value identifying the current version of this template,
162
+	 * in this case it's the unix timestamp of the last modification.
163
+	 *
164
+	 * @return string
165
+	 */
166
+	public function getUid()
167
+	{
168
+		return (string)filemtime($this->getResourceIdentifier());
169
+	}
170 170
 
171
-    /**
172
-     * Returns a new template object from the given include name, null if no include is
173
-     * possible (resource not found), or false if include is not permitted by this resource type.
174
-     *
175
-     * @param Core      $core           the dwoo instance requiring it
176
-     * @param mixed     $resourceId     the filename (relative to this template's dir) of the template to
177
-     *                                  include
178
-     * @param int       $cacheTime      duration of the cache validity for this template, if null it defaults
179
-     *                                  to the Dwoo instance that will render this template if null it
180
-     *                                  defaults to the Dwoo instance that will render this template if null
181
-     *                                  it defaults to the Dwoo instance that will render this template
182
-     * @param string    $cacheId        the unique cache identifier of this page or anything else that makes
183
-     *                                  this template's content unique, if null it defaults to the current
184
-     *                                  url makes this template's content unique, if null it defaults to the
185
-     *                                  current url makes this template's content unique, if null it defaults
186
-     *                                  to the current url
187
-     * @param string    $compileId      the unique compiled identifier, which is used to distinguish this
188
-     *                                  template from others, if null it defaults to the filename+bits of the
189
-     *                                  path template from others, if null it defaults to the filename+bits
190
-     *                                  of the path template from others, if null it defaults to the
191
-     *                                  filename+bits of the path
192
-     * @param ITemplate $parentTemplate the template that is requesting a new template object (through an
193
-     *                                  include, extends or any other plugin) an include, extends or any
194
-     *                                  other plugin) an include, extends or any other plugin)
195
-     *
196
-     * @return TemplateFile|null
197
-     * @throws DwooException
198
-     * @throws SecurityException
199
-     */
200
-    public static function templateFactory(Core $core, $resourceId, $cacheTime = null, $cacheId = null,
201
-                                           $compileId = null, ITemplate $parentTemplate = null)
202
-    {
203
-        if (DIRECTORY_SEPARATOR === '\\') {
204
-            $resourceId = str_replace(array("\t", "\n", "\r", "\f", "\v"), array(
205
-                '\\t',
206
-                '\\n',
207
-                '\\r',
208
-                '\\f',
209
-                '\\v'
210
-            ), $resourceId);
211
-        }
212
-        $resourceId = strtr($resourceId, '\\', '/');
171
+	/**
172
+	 * Returns a new template object from the given include name, null if no include is
173
+	 * possible (resource not found), or false if include is not permitted by this resource type.
174
+	 *
175
+	 * @param Core      $core           the dwoo instance requiring it
176
+	 * @param mixed     $resourceId     the filename (relative to this template's dir) of the template to
177
+	 *                                  include
178
+	 * @param int       $cacheTime      duration of the cache validity for this template, if null it defaults
179
+	 *                                  to the Dwoo instance that will render this template if null it
180
+	 *                                  defaults to the Dwoo instance that will render this template if null
181
+	 *                                  it defaults to the Dwoo instance that will render this template
182
+	 * @param string    $cacheId        the unique cache identifier of this page or anything else that makes
183
+	 *                                  this template's content unique, if null it defaults to the current
184
+	 *                                  url makes this template's content unique, if null it defaults to the
185
+	 *                                  current url makes this template's content unique, if null it defaults
186
+	 *                                  to the current url
187
+	 * @param string    $compileId      the unique compiled identifier, which is used to distinguish this
188
+	 *                                  template from others, if null it defaults to the filename+bits of the
189
+	 *                                  path template from others, if null it defaults to the filename+bits
190
+	 *                                  of the path template from others, if null it defaults to the
191
+	 *                                  filename+bits of the path
192
+	 * @param ITemplate $parentTemplate the template that is requesting a new template object (through an
193
+	 *                                  include, extends or any other plugin) an include, extends or any
194
+	 *                                  other plugin) an include, extends or any other plugin)
195
+	 *
196
+	 * @return TemplateFile|null
197
+	 * @throws DwooException
198
+	 * @throws SecurityException
199
+	 */
200
+	public static function templateFactory(Core $core, $resourceId, $cacheTime = null, $cacheId = null,
201
+										   $compileId = null, ITemplate $parentTemplate = null)
202
+	{
203
+		if (DIRECTORY_SEPARATOR === '\\') {
204
+			$resourceId = str_replace(array("\t", "\n", "\r", "\f", "\v"), array(
205
+				'\\t',
206
+				'\\n',
207
+				'\\r',
208
+				'\\f',
209
+				'\\v'
210
+			), $resourceId);
211
+		}
212
+		$resourceId = strtr($resourceId, '\\', '/');
213 213
 
214
-        $includePath = null;
214
+		$includePath = null;
215 215
 
216
-        if (file_exists($resourceId) === false) {
217
-            if ($parentTemplate === null) {
218
-                $parentTemplate = $core->getTemplate();
219
-            }
220
-            if ($parentTemplate instanceof self) {
221
-                if ($includePath = $parentTemplate->getIncludePath()) {
222
-                    if (strstr($resourceId, '../')) {
223
-                        throw new DwooException('When using an include path you can not reference a template into a parent directory (using ../)');
224
-                    }
225
-                } else {
226
-                    $resourceId = dirname($parentTemplate->getResourceIdentifier()) . DIRECTORY_SEPARATOR . $resourceId;
227
-                    if (file_exists($resourceId) === false) {
228
-                        return null;
229
-                    }
230
-                }
231
-            } else {
232
-                return null;
233
-            }
234
-        }
216
+		if (file_exists($resourceId) === false) {
217
+			if ($parentTemplate === null) {
218
+				$parentTemplate = $core->getTemplate();
219
+			}
220
+			if ($parentTemplate instanceof self) {
221
+				if ($includePath = $parentTemplate->getIncludePath()) {
222
+					if (strstr($resourceId, '../')) {
223
+						throw new DwooException('When using an include path you can not reference a template into a parent directory (using ../)');
224
+					}
225
+				} else {
226
+					$resourceId = dirname($parentTemplate->getResourceIdentifier()) . DIRECTORY_SEPARATOR . $resourceId;
227
+					if (file_exists($resourceId) === false) {
228
+						return null;
229
+					}
230
+				}
231
+			} else {
232
+				return null;
233
+			}
234
+		}
235 235
 
236
-        if ($policy = $core->getSecurityPolicy()) {
237
-            while (true) {
238
-                if (preg_match('{^([a-z]+?)://}i', $resourceId)) {
239
-                    throw new SecurityException('The security policy prevents you to read files from external sources : <em>' . $resourceId . '</em>.');
240
-                }
236
+		if ($policy = $core->getSecurityPolicy()) {
237
+			while (true) {
238
+				if (preg_match('{^([a-z]+?)://}i', $resourceId)) {
239
+					throw new SecurityException('The security policy prevents you to read files from external sources : <em>' . $resourceId . '</em>.');
240
+				}
241 241
 
242
-                if ($includePath) {
243
-                    break;
244
-                }
242
+				if ($includePath) {
243
+					break;
244
+				}
245 245
 
246
-                $resourceId = realpath($resourceId);
247
-                $dirs       = $policy->getAllowedDirectories();
248
-                foreach ($dirs as $dir => $dummy) {
249
-                    if (strpos($resourceId, $dir) === 0) {
250
-                        break 2;
251
-                    }
252
-                }
253
-                throw new SecurityException('The security policy prevents you to read <em>' . $resourceId . '</em>');
254
-            }
255
-        }
246
+				$resourceId = realpath($resourceId);
247
+				$dirs       = $policy->getAllowedDirectories();
248
+				foreach ($dirs as $dir => $dummy) {
249
+					if (strpos($resourceId, $dir) === 0) {
250
+						break 2;
251
+					}
252
+				}
253
+				throw new SecurityException('The security policy prevents you to read <em>' . $resourceId . '</em>');
254
+			}
255
+		}
256 256
 
257
-        $class = 'Dwoo\Template\File';
258
-        if ($parentTemplate) {
259
-            $class = get_class($parentTemplate);
260
-        }
257
+		$class = 'Dwoo\Template\File';
258
+		if ($parentTemplate) {
259
+			$class = get_class($parentTemplate);
260
+		}
261 261
 
262
-        return new $class($resourceId, $cacheTime, $cacheId, $compileId, $includePath);
263
-    }
262
+		return new $class($resourceId, $cacheTime, $cacheId, $compileId, $includePath);
263
+	}
264 264
 
265
-    /**
266
-     * Returns the full compiled file name and assigns a default value to it if
267
-     * required.
268
-     *
269
-     * @param Core $core the Core instance that requests the file name
270
-     *
271
-     * @return string the full path to the compiled file
272
-     */
273
-    protected function getCompiledFilename(Core $core)
274
-    {
275
-        // no compile id was provided, set default
276
-        if ($this->compileId === null) {
277
-            $this->compileId = $this->getResourceIdentifier();
278
-        }
265
+	/**
266
+	 * Returns the full compiled file name and assigns a default value to it if
267
+	 * required.
268
+	 *
269
+	 * @param Core $core the Core instance that requests the file name
270
+	 *
271
+	 * @return string the full path to the compiled file
272
+	 */
273
+	protected function getCompiledFilename(Core $core)
274
+	{
275
+		// no compile id was provided, set default
276
+		if ($this->compileId === null) {
277
+			$this->compileId = $this->getResourceIdentifier();
278
+		}
279 279
 
280
-        return $this->compileId . '.d' . Core::RELEASE_TAG . '.php';
281
-    }
280
+		return $this->compileId . '.d' . Core::RELEASE_TAG . '.php';
281
+	}
282 282
 
283
-    /**
284
-     * Returns some php code that will check if this template has been modified or not.
285
-     * if the function returns null, the template will be instanciated and then the Uid checked
286
-     *
287
-     * @return string
288
-     */
289
-    public function getIsModifiedCode()
290
-    {
291
-        return '"' . $this->getUid() . '" == filemtime(' . var_export($this->getResourceIdentifier(), true) . ')';
292
-    }
283
+	/**
284
+	 * Returns some php code that will check if this template has been modified or not.
285
+	 * if the function returns null, the template will be instanciated and then the Uid checked
286
+	 *
287
+	 * @return string
288
+	 */
289
+	public function getIsModifiedCode()
290
+	{
291
+		return '"' . $this->getUid() . '" == filemtime(' . var_export($this->getResourceIdentifier(), true) . ')';
292
+	}
293 293
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -110,7 +110,7 @@  discard block
 block discarded – undo
110 110
      */
111 111
     protected function isValidCompiledFile($file)
112 112
     {
113
-        return parent::isValidCompiledFile($file) && (int)$this->getUid() <= filemtime($file);
113
+        return parent::isValidCompiledFile($file) && (int) $this->getUid() <= filemtime($file);
114 114
     }
115 115
 
116 116
     /**
@@ -148,12 +148,12 @@  discard block
 block discarded – undo
148 148
         } else {
149 149
             foreach ($this->getIncludePath() as $path) {
150 150
                 $path = rtrim($path, DIRECTORY_SEPARATOR);
151
-                if (file_exists($path . DIRECTORY_SEPARATOR . $this->file) === true) {
152
-                    return $this->resolvedPath = $path . DIRECTORY_SEPARATOR . $this->file;
151
+                if (file_exists($path.DIRECTORY_SEPARATOR.$this->file) === true) {
152
+                    return $this->resolvedPath = $path.DIRECTORY_SEPARATOR.$this->file;
153 153
                 }
154 154
             }
155 155
 
156
-            throw new DwooException('Template "' . $this->file . '" could not be found in any of your include path(s)');
156
+            throw new DwooException('Template "'.$this->file.'" could not be found in any of your include path(s)');
157 157
         }
158 158
     }
159 159
 
@@ -165,7 +165,7 @@  discard block
 block discarded – undo
165 165
      */
166 166
     public function getUid()
167 167
     {
168
-        return (string)filemtime($this->getResourceIdentifier());
168
+        return (string) filemtime($this->getResourceIdentifier());
169 169
     }
170 170
 
171 171
     /**
@@ -223,7 +223,7 @@  discard block
 block discarded – undo
223 223
                         throw new DwooException('When using an include path you can not reference a template into a parent directory (using ../)');
224 224
                     }
225 225
                 } else {
226
-                    $resourceId = dirname($parentTemplate->getResourceIdentifier()) . DIRECTORY_SEPARATOR . $resourceId;
226
+                    $resourceId = dirname($parentTemplate->getResourceIdentifier()).DIRECTORY_SEPARATOR.$resourceId;
227 227
                     if (file_exists($resourceId) === false) {
228 228
                         return null;
229 229
                     }
@@ -236,7 +236,7 @@  discard block
 block discarded – undo
236 236
         if ($policy = $core->getSecurityPolicy()) {
237 237
             while (true) {
238 238
                 if (preg_match('{^([a-z]+?)://}i', $resourceId)) {
239
-                    throw new SecurityException('The security policy prevents you to read files from external sources : <em>' . $resourceId . '</em>.');
239
+                    throw new SecurityException('The security policy prevents you to read files from external sources : <em>'.$resourceId.'</em>.');
240 240
                 }
241 241
 
242 242
                 if ($includePath) {
@@ -250,7 +250,7 @@  discard block
 block discarded – undo
250 250
                         break 2;
251 251
                     }
252 252
                 }
253
-                throw new SecurityException('The security policy prevents you to read <em>' . $resourceId . '</em>');
253
+                throw new SecurityException('The security policy prevents you to read <em>'.$resourceId.'</em>');
254 254
             }
255 255
         }
256 256
 
@@ -277,7 +277,7 @@  discard block
 block discarded – undo
277 277
             $this->compileId = $this->getResourceIdentifier();
278 278
         }
279 279
 
280
-        return $this->compileId . '.d' . Core::RELEASE_TAG . '.php';
280
+        return $this->compileId.'.d'.Core::RELEASE_TAG.'.php';
281 281
     }
282 282
 
283 283
     /**
@@ -288,6 +288,6 @@  discard block
 block discarded – undo
288 288
      */
289 289
     public function getIsModifiedCode()
290 290
     {
291
-        return '"' . $this->getUid() . '" == filemtime(' . var_export($this->getResourceIdentifier(), true) . ')';
291
+        return '"'.$this->getUid().'" == filemtime('.var_export($this->getResourceIdentifier(), true).')';
292 292
     }
293 293
 }
Please login to merge, or discard this patch.
lib/Dwoo/Data.php 2 patches
Indentation   +219 added lines, -219 removed lines patch added patch discarded remove patch
@@ -24,241 +24,241 @@
 block discarded – undo
24 24
  */
25 25
 class Data implements IDataProvider
26 26
 {
27
-    /**
28
-     * Data array.
29
-     *
30
-     * @var array
31
-     */
32
-    protected $data = array();
27
+	/**
28
+	 * Data array.
29
+	 *
30
+	 * @var array
31
+	 */
32
+	protected $data = array();
33 33
 
34
-    /**
35
-     * Returns the data array.
36
-     *
37
-     * @return array
38
-     */
39
-    public function getData()
40
-    {
41
-        return $this->data;
42
-    }
34
+	/**
35
+	 * Returns the data array.
36
+	 *
37
+	 * @return array
38
+	 */
39
+	public function getData()
40
+	{
41
+		return $this->data;
42
+	}
43 43
 
44
-    /**
45
-     * Clears a the entire data or only the given key.
46
-     *
47
-     * @param array|string $name clears only one value if you give a name, multiple values if
48
-     *                           you give an array of names, or the entire data if left null
49
-     */
50
-    public function clear($name = null)
51
-    {
52
-        if ($name === null) {
53
-            $this->data = array();
54
-        } elseif (is_array($name)) {
55
-            foreach ($name as $index) {
56
-                unset($this->data[$index]);
57
-            }
58
-        } else {
59
-            unset($this->data[$name]);
60
-        }
61
-    }
44
+	/**
45
+	 * Clears a the entire data or only the given key.
46
+	 *
47
+	 * @param array|string $name clears only one value if you give a name, multiple values if
48
+	 *                           you give an array of names, or the entire data if left null
49
+	 */
50
+	public function clear($name = null)
51
+	{
52
+		if ($name === null) {
53
+			$this->data = array();
54
+		} elseif (is_array($name)) {
55
+			foreach ($name as $index) {
56
+				unset($this->data[$index]);
57
+			}
58
+		} else {
59
+			unset($this->data[$name]);
60
+		}
61
+	}
62 62
 
63
-    /**
64
-     * Overwrites the entire data with the given array.
65
-     *
66
-     * @param array $data the new data array to use
67
-     */
68
-    public function setData(array $data)
69
-    {
70
-        $this->data = $data;
71
-    }
63
+	/**
64
+	 * Overwrites the entire data with the given array.
65
+	 *
66
+	 * @param array $data the new data array to use
67
+	 */
68
+	public function setData(array $data)
69
+	{
70
+		$this->data = $data;
71
+	}
72 72
 
73
-    /**
74
-     * merges the given array(s) with the current data with array_merge.
75
-     *
76
-     * @param array $data  the array to merge
77
-     */
78
-    public function mergeData(array $data)
79
-    {
80
-        $args = func_get_args();
81
-        foreach ($args as $key => $v) {
82
-            if (is_array($v)) {
83
-                $this->data = array_merge($this->data, $v);
84
-            }
85
-        }
86
-    }
73
+	/**
74
+	 * merges the given array(s) with the current data with array_merge.
75
+	 *
76
+	 * @param array $data  the array to merge
77
+	 */
78
+	public function mergeData(array $data)
79
+	{
80
+		$args = func_get_args();
81
+		foreach ($args as $key => $v) {
82
+			if (is_array($v)) {
83
+				$this->data = array_merge($this->data, $v);
84
+			}
85
+		}
86
+	}
87 87
 
88
-    /**
89
-     * Assigns a value or an array of values to the data object.
90
-     *
91
-     * @param array|string $name an associative array of multiple (index=>value) or a string
92
-     *                           that is the index to use, i.e. a value assigned to "foo" will be
93
-     *                           accessible in the template through {$foo}
94
-     * @param mixed        $val  the value to assign, or null if $name was an array
95
-     */
96
-    public function assign($name, $val = null)
97
-    {
98
-        if (is_array($name)) {
99
-            reset($name);
100
-            foreach ($name as $k => $v){
101
-                $this->data[$k] = $v;
102
-            }
103
-        } else {
104
-            $this->data[$name] = $val;
105
-        }
106
-    }
88
+	/**
89
+	 * Assigns a value or an array of values to the data object.
90
+	 *
91
+	 * @param array|string $name an associative array of multiple (index=>value) or a string
92
+	 *                           that is the index to use, i.e. a value assigned to "foo" will be
93
+	 *                           accessible in the template through {$foo}
94
+	 * @param mixed        $val  the value to assign, or null if $name was an array
95
+	 */
96
+	public function assign($name, $val = null)
97
+	{
98
+		if (is_array($name)) {
99
+			reset($name);
100
+			foreach ($name as $k => $v){
101
+				$this->data[$k] = $v;
102
+			}
103
+		} else {
104
+			$this->data[$name] = $val;
105
+		}
106
+	}
107 107
 
108
-    /**
109
-     * Allows to assign variables using the object syntax.
110
-     *
111
-     * @param string $name  the variable name
112
-     * @param string $value the value to assign to it
113
-     */
114
-    public function __set($name, $value)
115
-    {
116
-        $this->assign($name, $value);
117
-    }
108
+	/**
109
+	 * Allows to assign variables using the object syntax.
110
+	 *
111
+	 * @param string $name  the variable name
112
+	 * @param string $value the value to assign to it
113
+	 */
114
+	public function __set($name, $value)
115
+	{
116
+		$this->assign($name, $value);
117
+	}
118 118
 
119
-    /**
120
-     * Assigns a value by reference to the data object.
121
-     *
122
-     * @param string $name the index to use, i.e. a value assigned to "foo" will be
123
-     *                     accessible in the template through {$foo}
124
-     * @param mixed  $val  the value to assign by reference
125
-     */
126
-    public function assignByRef($name, &$val)
127
-    {
128
-        $this->data[$name] = &$val;
129
-    }
119
+	/**
120
+	 * Assigns a value by reference to the data object.
121
+	 *
122
+	 * @param string $name the index to use, i.e. a value assigned to "foo" will be
123
+	 *                     accessible in the template through {$foo}
124
+	 * @param mixed  $val  the value to assign by reference
125
+	 */
126
+	public function assignByRef($name, &$val)
127
+	{
128
+		$this->data[$name] = &$val;
129
+	}
130 130
 
131
-    /**
132
-     * Appends values or an array of values to the data object.
133
-     *
134
-     * @param array|string $name  an associative array of multiple (index=>value) or a string
135
-     *                            that is the index to use, i.e. a value assigned to "foo" will be
136
-     *                            accessible in the template through {$foo}
137
-     * @param mixed        $val   the value to assign, or null if $name was an array
138
-     * @param bool         $merge true to merge data or false to append, defaults to false
139
-     */
140
-    public function append($name, $val = null, $merge = false)
141
-    {
142
-        if (is_array($name)) {
143
-            foreach ($name as $key => $val) {
144
-                if (isset($this->data[$key]) && !is_array($this->data[$key])) {
145
-                    settype($this->data[$key], 'array');
146
-                }
131
+	/**
132
+	 * Appends values or an array of values to the data object.
133
+	 *
134
+	 * @param array|string $name  an associative array of multiple (index=>value) or a string
135
+	 *                            that is the index to use, i.e. a value assigned to "foo" will be
136
+	 *                            accessible in the template through {$foo}
137
+	 * @param mixed        $val   the value to assign, or null if $name was an array
138
+	 * @param bool         $merge true to merge data or false to append, defaults to false
139
+	 */
140
+	public function append($name, $val = null, $merge = false)
141
+	{
142
+		if (is_array($name)) {
143
+			foreach ($name as $key => $val) {
144
+				if (isset($this->data[$key]) && !is_array($this->data[$key])) {
145
+					settype($this->data[$key], 'array');
146
+				}
147 147
 
148
-                if ($merge === true && is_array($val)) {
149
-                    $this->data[$key] = $val + $this->data[$key];
150
-                } else {
151
-                    $this->data[$key][] = $val;
152
-                }
153
-            }
154
-        } elseif ($val !== null) {
155
-            if (isset($this->data[$name]) && !is_array($this->data[$name])) {
156
-                settype($this->data[$name], 'array');
157
-            } elseif (!isset($this->data[$name])) {
158
-                $this->data[$name] = array();
159
-            }
148
+				if ($merge === true && is_array($val)) {
149
+					$this->data[$key] = $val + $this->data[$key];
150
+				} else {
151
+					$this->data[$key][] = $val;
152
+				}
153
+			}
154
+		} elseif ($val !== null) {
155
+			if (isset($this->data[$name]) && !is_array($this->data[$name])) {
156
+				settype($this->data[$name], 'array');
157
+			} elseif (!isset($this->data[$name])) {
158
+				$this->data[$name] = array();
159
+			}
160 160
 
161
-            if ($merge === true && is_array($val)) {
162
-                $this->data[$name] = $val + $this->data[$name];
163
-            } else {
164
-                $this->data[$name][] = $val;
165
-            }
166
-        }
167
-    }
161
+			if ($merge === true && is_array($val)) {
162
+				$this->data[$name] = $val + $this->data[$name];
163
+			} else {
164
+				$this->data[$name][] = $val;
165
+			}
166
+		}
167
+	}
168 168
 
169
-    /**
170
-     * Appends a value by reference to the data object.
171
-     *
172
-     * @param string $name  the index to use, i.e. a value assigned to "foo" will be
173
-     *                      accessible in the template through {$foo}
174
-     * @param mixed  $val   the value to append by reference
175
-     * @param bool   $merge true to merge data or false to append, defaults to false
176
-     */
177
-    public function appendByRef($name, &$val, $merge = false)
178
-    {
179
-        if (isset($this->data[$name]) && !is_array($this->data[$name])) {
180
-            settype($this->data[$name], 'array');
181
-        }
169
+	/**
170
+	 * Appends a value by reference to the data object.
171
+	 *
172
+	 * @param string $name  the index to use, i.e. a value assigned to "foo" will be
173
+	 *                      accessible in the template through {$foo}
174
+	 * @param mixed  $val   the value to append by reference
175
+	 * @param bool   $merge true to merge data or false to append, defaults to false
176
+	 */
177
+	public function appendByRef($name, &$val, $merge = false)
178
+	{
179
+		if (isset($this->data[$name]) && !is_array($this->data[$name])) {
180
+			settype($this->data[$name], 'array');
181
+		}
182 182
 
183
-        if ($merge === true && is_array($val)) {
184
-            foreach ($val as $key => &$value) {
185
-                $this->data[$name][$key] = &$value;
186
-            }
187
-        } else {
188
-            $this->data[$name][] = &$val;
189
-        }
190
-    }
183
+		if ($merge === true && is_array($val)) {
184
+			foreach ($val as $key => &$value) {
185
+				$this->data[$name][$key] = &$value;
186
+			}
187
+		} else {
188
+			$this->data[$name][] = &$val;
189
+		}
190
+	}
191 191
 
192
-    /**
193
-     * Returns true if the variable has been assigned already, false otherwise.
194
-     *
195
-     * @param string $name the variable name
196
-     *
197
-     * @return bool
198
-     */
199
-    public function isAssigned($name)
200
-    {
201
-        return isset($this->data[$name]);
202
-    }
192
+	/**
193
+	 * Returns true if the variable has been assigned already, false otherwise.
194
+	 *
195
+	 * @param string $name the variable name
196
+	 *
197
+	 * @return bool
198
+	 */
199
+	public function isAssigned($name)
200
+	{
201
+		return isset($this->data[$name]);
202
+	}
203 203
 
204
-    /**
205
-     * Supports calls to isset($dwoo->var).
206
-     *
207
-     * @param string $name the variable name
208
-     *
209
-     * @return bool
210
-     */
211
-    public function __isset($name)
212
-    {
213
-        return isset($this->data[$name]);
214
-    }
204
+	/**
205
+	 * Supports calls to isset($dwoo->var).
206
+	 *
207
+	 * @param string $name the variable name
208
+	 *
209
+	 * @return bool
210
+	 */
211
+	public function __isset($name)
212
+	{
213
+		return isset($this->data[$name]);
214
+	}
215 215
 
216
-    /**
217
-     * Unassigns/removes a variable.
218
-     *
219
-     * @param string $name the variable name
220
-     */
221
-    public function unassign($name)
222
-    {
223
-        unset($this->data[$name]);
224
-    }
216
+	/**
217
+	 * Unassigns/removes a variable.
218
+	 *
219
+	 * @param string $name the variable name
220
+	 */
221
+	public function unassign($name)
222
+	{
223
+		unset($this->data[$name]);
224
+	}
225 225
 
226
-    /**
227
-     * Supports unsetting variables using the object syntax.
228
-     *
229
-     * @param string $name the variable name
230
-     */
231
-    public function __unset($name)
232
-    {
233
-        unset($this->data[$name]);
234
-    }
226
+	/**
227
+	 * Supports unsetting variables using the object syntax.
228
+	 *
229
+	 * @param string $name the variable name
230
+	 */
231
+	public function __unset($name)
232
+	{
233
+		unset($this->data[$name]);
234
+	}
235 235
 
236
-    /**
237
-     * Returns a variable if it was assigned.
238
-     *
239
-     * @param string $name the variable name
240
-     *
241
-     * @return mixed
242
-     */
243
-    public function get($name)
244
-    {
245
-        return $this->__get($name);
246
-    }
236
+	/**
237
+	 * Returns a variable if it was assigned.
238
+	 *
239
+	 * @param string $name the variable name
240
+	 *
241
+	 * @return mixed
242
+	 */
243
+	public function get($name)
244
+	{
245
+		return $this->__get($name);
246
+	}
247 247
 
248
-    /**
249
-     * Allows to read variables using the object syntax.
250
-     *
251
-     * @param string $name the variable name
252
-     *
253
-     * @return mixed
254
-     * @throws Exception
255
-     */
256
-    public function __get($name)
257
-    {
258
-        if (isset($this->data[$name])) {
259
-            return $this->data[$name];
260
-        } else {
261
-            throw new Exception('Tried to read a value that was not assigned yet : "' . $name . '"');
262
-        }
263
-    }
248
+	/**
249
+	 * Allows to read variables using the object syntax.
250
+	 *
251
+	 * @param string $name the variable name
252
+	 *
253
+	 * @return mixed
254
+	 * @throws Exception
255
+	 */
256
+	public function __get($name)
257
+	{
258
+		if (isset($this->data[$name])) {
259
+			return $this->data[$name];
260
+		} else {
261
+			throw new Exception('Tried to read a value that was not assigned yet : "' . $name . '"');
262
+		}
263
+	}
264 264
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -97,7 +97,7 @@  discard block
 block discarded – undo
97 97
     {
98 98
         if (is_array($name)) {
99 99
             reset($name);
100
-            foreach ($name as $k => $v){
100
+            foreach ($name as $k => $v) {
101 101
                 $this->data[$k] = $v;
102 102
             }
103 103
         } else {
@@ -146,7 +146,7 @@  discard block
 block discarded – undo
146 146
                 }
147 147
 
148 148
                 if ($merge === true && is_array($val)) {
149
-                    $this->data[$key] = $val + $this->data[$key];
149
+                    $this->data[$key] = $val+$this->data[$key];
150 150
                 } else {
151 151
                     $this->data[$key][] = $val;
152 152
                 }
@@ -159,7 +159,7 @@  discard block
 block discarded – undo
159 159
             }
160 160
 
161 161
             if ($merge === true && is_array($val)) {
162
-                $this->data[$name] = $val + $this->data[$name];
162
+                $this->data[$name] = $val+$this->data[$name];
163 163
             } else {
164 164
                 $this->data[$name][] = $val;
165 165
             }
@@ -258,7 +258,7 @@  discard block
 block discarded – undo
258 258
         if (isset($this->data[$name])) {
259 259
             return $this->data[$name];
260 260
         } else {
261
-            throw new Exception('Tried to read a value that was not assigned yet : "' . $name . '"');
261
+            throw new Exception('Tried to read a value that was not assigned yet : "'.$name.'"');
262 262
         }
263 263
     }
264 264
 }
Please login to merge, or discard this patch.
lib/Dwoo/Template/Str.php 2 patches
Indentation   +506 added lines, -506 removed lines patch added patch discarded remove patch
@@ -29,510 +29,510 @@
 block discarded – undo
29 29
  */
30 30
 class Str implements ITemplate
31 31
 {
32
-    /**
33
-     * Template name.
34
-     *
35
-     * @var string
36
-     */
37
-    protected $name;
38
-
39
-    /**
40
-     * Template compilation id.
41
-     *
42
-     * @var string
43
-     */
44
-    protected $compileId;
45
-
46
-    /**
47
-     * Template cache id, if not provided in the constructor, it is set to
48
-     * the md4 hash of the request_uri. it is however highly recommended to
49
-     * provide one that will fit your needs.
50
-     * in all cases, the compilation id is prepended to the cache id to separate
51
-     * templates with similar cache ids from one another
52
-     *
53
-     * @var string
54
-     */
55
-    protected $cacheId;
56
-
57
-    /**
58
-     * Validity duration of the generated cache file (in seconds).
59
-     * set to -1 for infinite cache, 0 to disable and null to inherit the Dwoo instance's cache time
60
-     *
61
-     * @var int
62
-     */
63
-    protected $cacheTime;
64
-
65
-    /**
66
-     * Boolean flag that defines whether the compilation should be enforced (once) or
67
-     * not use this if you have issues with the compiled templates not being updated
68
-     * but if you do need this it's most likely that you should file a bug report.
69
-     *
70
-     * @var bool
71
-     */
72
-    protected $compilationEnforced;
73
-
74
-    /**
75
-     * Caches the results of the file checks to save some time when the same
76
-     * templates is rendered several times.
77
-     *
78
-     * @var array
79
-     */
80
-    protected static $cache = array(
81
-        'cached'   => array(),
82
-        'compiled' => array()
83
-    );
84
-
85
-    /**
86
-     * Holds the compiler that built this template.
87
-     *
88
-     * @var ICompiler
89
-     */
90
-    protected $compiler;
91
-
92
-    /**
93
-     * Chmod value for all files written (cached or compiled ones).
94
-     * set to null if you don't want any chmod operation to happen
95
-     *
96
-     * @var int
97
-     */
98
-    protected $chmod = 0777;
99
-
100
-    /**
101
-     * Containing template string.
102
-     *
103
-     * @var string
104
-     */
105
-    protected $template;
106
-
107
-    /**
108
-     * Creates a template from a string.
109
-     *
110
-     * @param string $templateString the template to use
111
-     * @param int    $cacheTime      duration of the cache validity for this template,
112
-     *                               if null it defaults to the Dwoo instance that will
113
-     *                               render this template, set to -1 for infinite cache or 0 to disable
114
-     * @param string $cacheId        the unique cache identifier of this page or anything else that
115
-     *                               makes this template's content unique, if null it defaults
116
-     *                               to the current url
117
-     * @param string $compileId      the unique compiled identifier, which is used to distinguish this
118
-     *                               template from others, if null it defaults to the md4 hash of the template
119
-     */
120
-    public function __construct($templateString, $cacheTime = null, $cacheId = null, $compileId = null)
121
-    {
122
-        $this->template  = $templateString;
123
-        $this->name      = hash('md4', $templateString);
124
-        $this->cacheTime = $cacheTime;
125
-
126
-        if ($compileId !== null) {
127
-            $this->compileId = str_replace('../', '__', strtr($compileId, '\\%?=!:;' . PATH_SEPARATOR, '/-------'));
128
-        }
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
-        $cacheLength = $core->getCacheTime();
264
-        if ($this->cacheTime !== null) {
265
-            $cacheLength = $this->cacheTime;
266
-        }
267
-
268
-        // file is not cacheable
269
-        if ($cacheLength == 0) {
270
-            return false;
271
-        }
272
-
273
-        $cachedFile = $this->getCacheFilename($core);
274
-
275
-        if (isset(self::$cache['cached'][$this->cacheId]) === true && file_exists($cachedFile)) {
276
-            // already checked, return cache file
277
-            return $cachedFile;
278
-        } elseif ($this->compilationEnforced !== true && file_exists($cachedFile) && ($cacheLength === - 1 || filemtime($cachedFile) > ($_SERVER['REQUEST_TIME'] - $cacheLength)) && $this->isValidCompiledFile($this->getCompiledFilename($core))) {
279
-            // cache is still valid and can be loaded
280
-            self::$cache['cached'][$this->cacheId] = true;
281
-
282
-            return $cachedFile;
283
-        }
284
-
285
-        // file is cacheable
286
-        return true;
287
-    }
288
-
289
-    /**
290
-     * Caches the provided output into the cache file.
291
-     *
292
-     * @param Core   $core   the dwoo instance that requests it
293
-     * @param string $output the template output
294
-     *
295
-     * @return mixed full path of the cached file or false upon failure
296
-     */
297
-    public function cache(Core $core, $output)
298
-    {
299
-        $cacheDir   = $core->getCacheDir();
300
-        $cachedFile = $this->getCacheFilename($core);
301
-
302
-        // the code below is courtesy of Rasmus Schultz,
303
-        // thanks for his help on avoiding concurency issues
304
-        $temp = tempnam($cacheDir, 'temp');
305
-        if (!($file = @fopen($temp, 'wb'))) {
306
-            $temp = $cacheDir . uniqid('temp');
307
-            if (!($file = @fopen($temp, 'wb'))) {
308
-                trigger_error('Error writing temporary file \'' . $temp . '\'', E_USER_WARNING);
309
-
310
-                return false;
311
-            }
312
-        }
313
-
314
-        fwrite($file, $output);
315
-        fclose($file);
316
-
317
-        $this->makeDirectory(dirname($cachedFile), $cacheDir);
318
-        if (!@rename($temp, $cachedFile)) {
319
-            @unlink($cachedFile);
320
-            @rename($temp, $cachedFile);
321
-        }
322
-
323
-        if ($this->chmod !== null) {
324
-            chmod($cachedFile, $this->chmod);
325
-        }
326
-
327
-        self::$cache['cached'][$this->cacheId] = true;
328
-
329
-        return $cachedFile;
330
-    }
331
-
332
-    /**
333
-     * Clears the cached template if it's older than the given time.
334
-     *
335
-     * @param Core $core      the dwoo instance that was used to cache that template
336
-     * @param int  $olderThan minimum time (in seconds) required for the cache to be cleared
337
-     *
338
-     * @return bool true if the cache was not present or if it was deleted, false if it remains there
339
-     */
340
-    public function clearCache(Core $core, $olderThan = - 1)
341
-    {
342
-        $cachedFile = $this->getCacheFilename($core);
343
-
344
-        return !file_exists($cachedFile) || (filectime($cachedFile) < (time() - $olderThan) && unlink($cachedFile));
345
-    }
346
-
347
-    /**
348
-     * Returns the compiled template file name.
349
-     *
350
-     * @param Core      $core     the dwoo instance that requests it
351
-     * @param ICompiler $compiler the compiler that must be used
352
-     *
353
-     * @return string
354
-     */
355
-    public function getCompiledTemplate(Core $core, ICompiler $compiler = null)
356
-    {
357
-        $compiledFile = $this->getCompiledFilename($core);
358
-
359
-        if ($this->compilationEnforced !== true && isset(self::$cache['compiled'][$this->compileId]) === true) {
360
-            // already checked, return compiled file
361
-        } elseif ($this->compilationEnforced !== true && $this->isValidCompiledFile($compiledFile)) {
362
-            // template is compiled
363
-            self::$cache['compiled'][$this->compileId] = true;
364
-        } else {
365
-            // compiles the template
366
-            $this->compilationEnforced = false;
367
-
368
-            if ($compiler === null) {
369
-                $compiler = $core->getDefaultCompilerFactory($this->getResourceName());
370
-
371
-                if ($compiler === null || $compiler === array('Dwoo\Compiler', 'compilerFactory')) {
372
-                    $compiler = Compiler::compilerFactory();
373
-                } else {
374
-                    $compiler = call_user_func($compiler);
375
-                }
376
-            }
377
-
378
-            $this->compiler = $compiler;
379
-
380
-            $compiler->setCustomPlugins($core->getCustomPlugins());
381
-            $compiler->setSecurityPolicy($core->getSecurityPolicy());
382
-            $this->makeDirectory(dirname($compiledFile), $core->getCompileDir());
383
-            file_put_contents($compiledFile, $compiler->compile($core, $this));
384
-            if ($this->chmod !== null) {
385
-                chmod($compiledFile, $this->chmod);
386
-            }
387
-
388
-            if (extension_loaded('Zend OPcache')) {
389
-                opcache_invalidate($compiledFile);
390
-            } elseif (extension_loaded('apc') && ini_get('apc.enabled')) {
391
-                apc_delete_file($compiledFile);
392
-            }
393
-
394
-            self::$cache['compiled'][$this->compileId] = true;
395
-        }
396
-
397
-        return $compiledFile;
398
-    }
399
-
400
-    /**
401
-     * Checks if compiled file is valid (it exists).
402
-     *
403
-     * @param string $file
404
-     *
405
-     * @return bool True cache file existence
406
-     */
407
-    protected function isValidCompiledFile($file)
408
-    {
409
-        return file_exists($file);
410
-    }
411
-
412
-    /**
413
-     * Returns a new template string object with the resource id being the template source code.
414
-     *
415
-     * @param Core      $core           the dwoo instance requiring it
416
-     * @param mixed     $resourceId     the filename (relative to this template's dir) of the template to include
417
-     * @param int       $cacheTime      duration of the cache validity for this template, if null it defaults to the
418
-     *                                  Dwoo instance that will render this template if null it defaults to the Dwoo
419
-     *                                  instance that will render this template
420
-     * @param string    $cacheId        the unique cache identifier of this page or anything else that makes this
421
-     *                                  template's content unique, if null it defaults to the current url makes this
422
-     *                                  template's content unique, if null it defaults to the current url
423
-     * @param string    $compileId      the unique compiled identifier, which is used to distinguish this template from
424
-     *                                  others, if null it defaults to the filename+bits of the path template from
425
-     *                                  others, if null it defaults to the filename+bits of the path
426
-     * @param ITemplate $parentTemplate the template that is requesting a new template object (through an include,
427
-     *                                  extends or any other plugin) an include, extends or any other plugin)
428
-     *
429
-     * @return $this
430
-     */
431
-    public static function templateFactory(Core $core, $resourceId, $cacheTime = null, $cacheId = null,
432
-                                           $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 Core 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('../', '__',
478
-                $this->compileId . strtr($cacheId, '\\%?=!:;' . PATH_SEPARATOR, '/-------'));
479
-        }
480
-
481
-        return $core->getCacheDir() . $this->cacheId . '.html';
482
-    }
483
-
484
-    /**
485
-     * Returns some php code that will check if this template has been modified or not.
486
-     * if the function returns null, the template will be instanciated and then the Uid checked
487
-     *
488
-     * @return string
489
-     */
490
-    public function getIsModifiedCode()
491
-    {
492
-        return null;
493
-    }
494
-
495
-    /**
496
-     * Ensures the given path exists.
497
-     *
498
-     * @param string $path    any path
499
-     * @param string $baseDir the base directory where the directory is created
500
-     *                        ($path must still contain the full path, $baseDir
501
-     *                        is only used for unix permissions)
502
-     *
503
-     * @throws Exception
504
-     */
505
-    protected function makeDirectory($path, $baseDir = null)
506
-    {
507
-        if (is_dir($path) === true) {
508
-            return;
509
-        }
510
-
511
-        if ($this->chmod === null) {
512
-            $chmod = 0777;
513
-        } else {
514
-            $chmod = $this->chmod;
515
-        }
516
-
517
-        $retries = 3;
518
-        while ($retries --) {
519
-            @mkdir($path, $chmod, true);
520
-            if (is_dir($path)) {
521
-                break;
522
-            }
523
-            usleep(20);
524
-        }
525
-
526
-        // enforce the correct mode for all directories created
527
-        if (strpos(PHP_OS, 'WIN') !== 0 && $baseDir !== null) {
528
-            $path    = strtr(str_replace($baseDir, '', $path), '\\', '/');
529
-            $folders = explode('/', trim($path, '/'));
530
-            foreach ($folders as $folder) {
531
-                $baseDir .= $folder . DIRECTORY_SEPARATOR;
532
-                if (!chmod($baseDir, $chmod)) {
533
-                    throw new Exception('Unable to chmod ' . "$baseDir to $chmod: " . print_r(error_get_last(), true));
534
-                }
535
-            }
536
-        }
537
-    }
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
+		$cacheLength = $core->getCacheTime();
264
+		if ($this->cacheTime !== null) {
265
+			$cacheLength = $this->cacheTime;
266
+		}
267
+
268
+		// file is not cacheable
269
+		if ($cacheLength == 0) {
270
+			return false;
271
+		}
272
+
273
+		$cachedFile = $this->getCacheFilename($core);
274
+
275
+		if (isset(self::$cache['cached'][$this->cacheId]) === true && file_exists($cachedFile)) {
276
+			// already checked, return cache file
277
+			return $cachedFile;
278
+		} elseif ($this->compilationEnforced !== true && file_exists($cachedFile) && ($cacheLength === - 1 || filemtime($cachedFile) > ($_SERVER['REQUEST_TIME'] - $cacheLength)) && $this->isValidCompiledFile($this->getCompiledFilename($core))) {
279
+			// cache is still valid and can be loaded
280
+			self::$cache['cached'][$this->cacheId] = true;
281
+
282
+			return $cachedFile;
283
+		}
284
+
285
+		// file is cacheable
286
+		return true;
287
+	}
288
+
289
+	/**
290
+	 * Caches the provided output into the cache file.
291
+	 *
292
+	 * @param Core   $core   the dwoo instance that requests it
293
+	 * @param string $output the template output
294
+	 *
295
+	 * @return mixed full path of the cached file or false upon failure
296
+	 */
297
+	public function cache(Core $core, $output)
298
+	{
299
+		$cacheDir   = $core->getCacheDir();
300
+		$cachedFile = $this->getCacheFilename($core);
301
+
302
+		// the code below is courtesy of Rasmus Schultz,
303
+		// thanks for his help on avoiding concurency issues
304
+		$temp = tempnam($cacheDir, 'temp');
305
+		if (!($file = @fopen($temp, 'wb'))) {
306
+			$temp = $cacheDir . uniqid('temp');
307
+			if (!($file = @fopen($temp, 'wb'))) {
308
+				trigger_error('Error writing temporary file \'' . $temp . '\'', E_USER_WARNING);
309
+
310
+				return false;
311
+			}
312
+		}
313
+
314
+		fwrite($file, $output);
315
+		fclose($file);
316
+
317
+		$this->makeDirectory(dirname($cachedFile), $cacheDir);
318
+		if (!@rename($temp, $cachedFile)) {
319
+			@unlink($cachedFile);
320
+			@rename($temp, $cachedFile);
321
+		}
322
+
323
+		if ($this->chmod !== null) {
324
+			chmod($cachedFile, $this->chmod);
325
+		}
326
+
327
+		self::$cache['cached'][$this->cacheId] = true;
328
+
329
+		return $cachedFile;
330
+	}
331
+
332
+	/**
333
+	 * Clears the cached template if it's older than the given time.
334
+	 *
335
+	 * @param Core $core      the dwoo instance that was used to cache that template
336
+	 * @param int  $olderThan minimum time (in seconds) required for the cache to be cleared
337
+	 *
338
+	 * @return bool true if the cache was not present or if it was deleted, false if it remains there
339
+	 */
340
+	public function clearCache(Core $core, $olderThan = - 1)
341
+	{
342
+		$cachedFile = $this->getCacheFilename($core);
343
+
344
+		return !file_exists($cachedFile) || (filectime($cachedFile) < (time() - $olderThan) && unlink($cachedFile));
345
+	}
346
+
347
+	/**
348
+	 * Returns the compiled template file name.
349
+	 *
350
+	 * @param Core      $core     the dwoo instance that requests it
351
+	 * @param ICompiler $compiler the compiler that must be used
352
+	 *
353
+	 * @return string
354
+	 */
355
+	public function getCompiledTemplate(Core $core, ICompiler $compiler = null)
356
+	{
357
+		$compiledFile = $this->getCompiledFilename($core);
358
+
359
+		if ($this->compilationEnforced !== true && isset(self::$cache['compiled'][$this->compileId]) === true) {
360
+			// already checked, return compiled file
361
+		} elseif ($this->compilationEnforced !== true && $this->isValidCompiledFile($compiledFile)) {
362
+			// template is compiled
363
+			self::$cache['compiled'][$this->compileId] = true;
364
+		} else {
365
+			// compiles the template
366
+			$this->compilationEnforced = false;
367
+
368
+			if ($compiler === null) {
369
+				$compiler = $core->getDefaultCompilerFactory($this->getResourceName());
370
+
371
+				if ($compiler === null || $compiler === array('Dwoo\Compiler', 'compilerFactory')) {
372
+					$compiler = Compiler::compilerFactory();
373
+				} else {
374
+					$compiler = call_user_func($compiler);
375
+				}
376
+			}
377
+
378
+			$this->compiler = $compiler;
379
+
380
+			$compiler->setCustomPlugins($core->getCustomPlugins());
381
+			$compiler->setSecurityPolicy($core->getSecurityPolicy());
382
+			$this->makeDirectory(dirname($compiledFile), $core->getCompileDir());
383
+			file_put_contents($compiledFile, $compiler->compile($core, $this));
384
+			if ($this->chmod !== null) {
385
+				chmod($compiledFile, $this->chmod);
386
+			}
387
+
388
+			if (extension_loaded('Zend OPcache')) {
389
+				opcache_invalidate($compiledFile);
390
+			} elseif (extension_loaded('apc') && ini_get('apc.enabled')) {
391
+				apc_delete_file($compiledFile);
392
+			}
393
+
394
+			self::$cache['compiled'][$this->compileId] = true;
395
+		}
396
+
397
+		return $compiledFile;
398
+	}
399
+
400
+	/**
401
+	 * Checks if compiled file is valid (it exists).
402
+	 *
403
+	 * @param string $file
404
+	 *
405
+	 * @return bool True cache file existence
406
+	 */
407
+	protected function isValidCompiledFile($file)
408
+	{
409
+		return file_exists($file);
410
+	}
411
+
412
+	/**
413
+	 * Returns a new template string object with the resource id being the template source code.
414
+	 *
415
+	 * @param Core      $core           the dwoo instance requiring it
416
+	 * @param mixed     $resourceId     the filename (relative to this template's dir) of the template to include
417
+	 * @param int       $cacheTime      duration of the cache validity for this template, if null it defaults to the
418
+	 *                                  Dwoo instance that will render this template if null it defaults to the Dwoo
419
+	 *                                  instance that will render this template
420
+	 * @param string    $cacheId        the unique cache identifier of this page or anything else that makes this
421
+	 *                                  template's content unique, if null it defaults to the current url makes this
422
+	 *                                  template's content unique, if null it defaults to the current url
423
+	 * @param string    $compileId      the unique compiled identifier, which is used to distinguish this template from
424
+	 *                                  others, if null it defaults to the filename+bits of the path template from
425
+	 *                                  others, if null it defaults to the filename+bits of the path
426
+	 * @param ITemplate $parentTemplate the template that is requesting a new template object (through an include,
427
+	 *                                  extends or any other plugin) an include, extends or any other plugin)
428
+	 *
429
+	 * @return $this
430
+	 */
431
+	public static function templateFactory(Core $core, $resourceId, $cacheTime = null, $cacheId = null,
432
+										   $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 Core 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('../', '__',
478
+				$this->compileId . strtr($cacheId, '\\%?=!:;' . PATH_SEPARATOR, '/-------'));
479
+		}
480
+
481
+		return $core->getCacheDir() . $this->cacheId . '.html';
482
+	}
483
+
484
+	/**
485
+	 * Returns some php code that will check if this template has been modified or not.
486
+	 * if the function returns null, the template will be instanciated and then the Uid checked
487
+	 *
488
+	 * @return string
489
+	 */
490
+	public function getIsModifiedCode()
491
+	{
492
+		return null;
493
+	}
494
+
495
+	/**
496
+	 * Ensures the given path exists.
497
+	 *
498
+	 * @param string $path    any path
499
+	 * @param string $baseDir the base directory where the directory is created
500
+	 *                        ($path must still contain the full path, $baseDir
501
+	 *                        is only used for unix permissions)
502
+	 *
503
+	 * @throws Exception
504
+	 */
505
+	protected function makeDirectory($path, $baseDir = null)
506
+	{
507
+		if (is_dir($path) === true) {
508
+			return;
509
+		}
510
+
511
+		if ($this->chmod === null) {
512
+			$chmod = 0777;
513
+		} else {
514
+			$chmod = $this->chmod;
515
+		}
516
+
517
+		$retries = 3;
518
+		while ($retries --) {
519
+			@mkdir($path, $chmod, true);
520
+			if (is_dir($path)) {
521
+				break;
522
+			}
523
+			usleep(20);
524
+		}
525
+
526
+		// enforce the correct mode for all directories created
527
+		if (strpos(PHP_OS, 'WIN') !== 0 && $baseDir !== null) {
528
+			$path    = strtr(str_replace($baseDir, '', $path), '\\', '/');
529
+			$folders = explode('/', trim($path, '/'));
530
+			foreach ($folders as $folder) {
531
+				$baseDir .= $folder . DIRECTORY_SEPARATOR;
532
+				if (!chmod($baseDir, $chmod)) {
533
+					throw new Exception('Unable to chmod ' . "$baseDir to $chmod: " . print_r(error_get_last(), true));
534
+				}
535
+			}
536
+		}
537
+	}
538 538
 }
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -124,11 +124,11 @@  discard block
 block discarded – undo
124 124
         $this->cacheTime = $cacheTime;
125 125
 
126 126
         if ($compileId !== null) {
127
-            $this->compileId = str_replace('../', '__', strtr($compileId, '\\%?=!:;' . PATH_SEPARATOR, '/-------'));
127
+            $this->compileId = str_replace('../', '__', strtr($compileId, '\\%?=!:;'.PATH_SEPARATOR, '/-------'));
128 128
         }
129 129
 
130 130
         if ($cacheId !== null) {
131
-            $this->cacheId = str_replace('../', '__', strtr($cacheId, '\\%?=!:;' . PATH_SEPARATOR, '/-------'));
131
+            $this->cacheId = str_replace('../', '__', strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------'));
132 132
         }
133 133
     }
134 134
 
@@ -275,7 +275,7 @@  discard block
 block discarded – undo
275 275
         if (isset(self::$cache['cached'][$this->cacheId]) === true && file_exists($cachedFile)) {
276 276
             // already checked, return cache file
277 277
             return $cachedFile;
278
-        } elseif ($this->compilationEnforced !== true && file_exists($cachedFile) && ($cacheLength === - 1 || filemtime($cachedFile) > ($_SERVER['REQUEST_TIME'] - $cacheLength)) && $this->isValidCompiledFile($this->getCompiledFilename($core))) {
278
+        } elseif ($this->compilationEnforced !== true && file_exists($cachedFile) && ($cacheLength === - 1 || filemtime($cachedFile) > ($_SERVER['REQUEST_TIME']-$cacheLength)) && $this->isValidCompiledFile($this->getCompiledFilename($core))) {
279 279
             // cache is still valid and can be loaded
280 280
             self::$cache['cached'][$this->cacheId] = true;
281 281
 
@@ -303,9 +303,9 @@  discard block
 block discarded – undo
303 303
         // thanks for his help on avoiding concurency issues
304 304
         $temp = tempnam($cacheDir, 'temp');
305 305
         if (!($file = @fopen($temp, 'wb'))) {
306
-            $temp = $cacheDir . uniqid('temp');
306
+            $temp = $cacheDir.uniqid('temp');
307 307
             if (!($file = @fopen($temp, 'wb'))) {
308
-                trigger_error('Error writing temporary file \'' . $temp . '\'', E_USER_WARNING);
308
+                trigger_error('Error writing temporary file \''.$temp.'\'', E_USER_WARNING);
309 309
 
310 310
                 return false;
311 311
             }
@@ -341,7 +341,7 @@  discard block
 block discarded – undo
341 341
     {
342 342
         $cachedFile = $this->getCacheFilename($core);
343 343
 
344
-        return !file_exists($cachedFile) || (filectime($cachedFile) < (time() - $olderThan) && unlink($cachedFile));
344
+        return !file_exists($cachedFile) || (filectime($cachedFile) < (time()-$olderThan) && unlink($cachedFile));
345 345
     }
346 346
 
347 347
     /**
@@ -449,7 +449,7 @@  discard block
 block discarded – undo
449 449
             $this->compileId = $this->name;
450 450
         }
451 451
 
452
-        return $core->getCompileDir() . $this->compileId . '.d' . Core::RELEASE_TAG . '.php';
452
+        return $core->getCompileDir().$this->compileId.'.d'.Core::RELEASE_TAG.'.php';
453 453
     }
454 454
 
455 455
     /**
@@ -467,7 +467,7 @@  discard block
 block discarded – undo
467 467
             if (isset($_SERVER['REQUEST_URI']) === true) {
468 468
                 $cacheId = $_SERVER['REQUEST_URI'];
469 469
             } elseif (isset($_SERVER['SCRIPT_FILENAME']) && isset($_SERVER['argv'])) {
470
-                $cacheId = $_SERVER['SCRIPT_FILENAME'] . '-' . implode('-', $_SERVER['argv']);
470
+                $cacheId = $_SERVER['SCRIPT_FILENAME'].'-'.implode('-', $_SERVER['argv']);
471 471
             } else {
472 472
                 $cacheId = '';
473 473
             }
@@ -475,10 +475,10 @@  discard block
 block discarded – undo
475 475
             $this->getCompiledFilename($core);
476 476
 
477 477
             $this->cacheId = str_replace('../', '__',
478
-                $this->compileId . strtr($cacheId, '\\%?=!:;' . PATH_SEPARATOR, '/-------'));
478
+                $this->compileId.strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------'));
479 479
         }
480 480
 
481
-        return $core->getCacheDir() . $this->cacheId . '.html';
481
+        return $core->getCacheDir().$this->cacheId.'.html';
482 482
     }
483 483
 
484 484
     /**
@@ -515,7 +515,7 @@  discard block
 block discarded – undo
515 515
         }
516 516
 
517 517
         $retries = 3;
518
-        while ($retries --) {
518
+        while ($retries--) {
519 519
             @mkdir($path, $chmod, true);
520 520
             if (is_dir($path)) {
521 521
                 break;
@@ -528,9 +528,9 @@  discard block
 block discarded – undo
528 528
             $path    = strtr(str_replace($baseDir, '', $path), '\\', '/');
529 529
             $folders = explode('/', trim($path, '/'));
530 530
             foreach ($folders as $folder) {
531
-                $baseDir .= $folder . DIRECTORY_SEPARATOR;
531
+                $baseDir .= $folder.DIRECTORY_SEPARATOR;
532 532
                 if (!chmod($baseDir, $chmod)) {
533
-                    throw new Exception('Unable to chmod ' . "$baseDir to $chmod: " . print_r(error_get_last(), true));
533
+                    throw new Exception('Unable to chmod '."$baseDir to $chmod: ".print_r(error_get_last(), true));
534 534
                 }
535 535
             }
536 536
         }
Please login to merge, or discard this patch.
lib/Dwoo/Core.php 2 patches
Indentation   +1738 added lines, -1738 removed lines patch added patch discarded remove patch
@@ -44,1750 +44,1750 @@
 block discarded – undo
44 44
  */
45 45
 class Core
46 46
 {
47
-    /**
48
-     * Current version number.
49
-     *
50
-     * @var string
51
-     */
52
-    const VERSION = '1.3.4';
53
-
54
-    /**
55
-     * Unique number of this dwoo release, based on version number.
56
-     * this can be used by templates classes to check whether the compiled template
57
-     * has been compiled before this release or not, so that old templates are
58
-     * recompiled automatically when Dwoo is updated
59
-     */
60
-    const RELEASE_TAG = 134;
61
-
62
-    /**
63
-     * Constants that represents all plugin types
64
-     * these are bitwise-operation-safe values to allow multiple types
65
-     * on a single plugin
66
-     *
67
-     * @var int
68
-     */
69
-    const CLASS_PLUGIN      = 1;
70
-    const FUNC_PLUGIN       = 2;
71
-    const NATIVE_PLUGIN     = 4;
72
-    const BLOCK_PLUGIN      = 8;
73
-    const COMPILABLE_PLUGIN = 16;
74
-    const CUSTOM_PLUGIN     = 32;
75
-    const SMARTY_MODIFIER   = 64;
76
-    const SMARTY_BLOCK      = 128;
77
-    const SMARTY_FUNCTION   = 256;
78
-    const PROXY_PLUGIN      = 512;
79
-    const TEMPLATE_PLUGIN   = 1024;
80
-
81
-    /**
82
-     * Constant to default namespaces of builtin plugins
83
-     *
84
-     * @var string
85
-     */
86
-    const NAMESPACE_PLUGINS_BLOCKS     = 'Dwoo\Plugins\Blocks\\';
87
-    const NAMESPACE_PLUGINS_FILTERS    = 'Dwoo\Plugins\Filters\\';
88
-    const NAMESPACE_PLUGINS_FUNCTIONS  = 'Dwoo\Plugins\Functions\\';
89
-    const NAMESPACE_PLUGINS_HELPERS    = 'Dwoo\Plugins\Helpers\\';
90
-    const NAMESPACE_PLUGINS_PROCESSORS = 'Dwoo\Plugins\Processors\\';
91
-
92
-    /**
93
-     * Character set of the template, used by string manipulation plugins.
94
-     * it must be lowercase, but setCharset() will take care of that
95
-     *
96
-     * @see setCharset
97
-     * @see getCharset
98
-     * @var string
99
-     */
100
-    protected $charset = 'UTF-8';
101
-
102
-    /**
103
-     * Global variables that are accessible through $dwoo.* in the templates.
104
-     * default values include:
105
-     * $dwoo.version - current version number
106
-     * $dwoo.ad - a Powered by Dwoo link pointing to dwoo.org
107
-     * $dwoo.now - the current time
108
-     * $dwoo.template - the current template filename
109
-     * $dwoo.charset - the character set used by the template
110
-     * on top of that, foreach and other plugins can store special values in there,
111
-     * see their documentation for more details.
112
-     *
113
-     * @var array
114
-     */
115
-    protected $globals = array();
116
-
117
-    /**
118
-     * Directory where the compiled templates are stored.
119
-     * defaults to DWOO_COMPILEDIR (= dwoo_dir/compiled by default)
120
-     *
121
-     * @var string
122
-     */
123
-    protected $compileDir;
124
-
125
-    /**
126
-     * Directory where the cached templates are stored.
127
-     * defaults to DWOO_CACHEDIR (= dwoo_dir/cache by default)
128
-     *
129
-     * @var string
130
-     */
131
-    protected $cacheDir;
132
-
133
-    /**
134
-     * Directory where the template files are stored
135
-     *
136
-     * @var array
137
-     */
138
-    protected $templateDir = array();
139
-
140
-    /**
141
-     * Defines how long (in seconds) the cached files must remain valid.
142
-     * can be overridden on a per-template basis
143
-     * -1 = never delete
144
-     * 0 = disabled
145
-     * >0 = duration in seconds
146
-     *
147
-     * @var int
148
-     */
149
-    protected $cacheTime = 0;
150
-
151
-    /**
152
-     * Security policy object.
153
-     *
154
-     * @var SecurityPolicy
155
-     */
156
-    protected $securityPolicy = null;
157
-
158
-    /**
159
-     * Stores the custom plugins callbacks.
160
-     *
161
-     * @see addPlugin
162
-     * @see removePlugin
163
-     * @var array
164
-     */
165
-    protected $plugins = array();
166
-
167
-    /**
168
-     * Stores the filter callbacks.
169
-     *
170
-     * @see addFilter
171
-     * @see removeFilter
172
-     * @var array
173
-     */
174
-    protected $filters = array();
175
-
176
-    /**
177
-     * Stores the resource types and associated
178
-     * classes / compiler classes.
179
-     *
180
-     * @var array
181
-     */
182
-    protected $resources = array(
183
-        'file'   => array(
184
-            'class'    => 'Dwoo\Template\File',
185
-            'compiler' => null,
186
-        ),
187
-        'string' => array(
188
-            'class'    => 'Dwoo\Template\Str',
189
-            'compiler' => null,
190
-        ),
191
-    );
192
-
193
-    /**
194
-     * The dwoo loader object used to load plugins by this dwoo instance.
195
-     *
196
-     * @var ILoader
197
-     */
198
-    protected $loader = null;
199
-
200
-    /**
201
-     * Currently rendered template, set to null when not-rendering.
202
-     *
203
-     * @var ITemplate
204
-     */
205
-    protected $template = null;
206
-
207
-    /**
208
-     * Stores the instances of the class plugins during template runtime.
209
-     *
210
-     * @var array
211
-     */
212
-    protected $runtimePlugins = array();
213
-
214
-    /**
215
-     * Stores the returned values during template runtime.
216
-     *
217
-     * @var array
218
-     */
219
-    protected $returnData = array();
220
-
221
-    /**
222
-     * Stores the data during template runtime.
223
-     *
224
-     * @var array
225
-     */
226
-    protected $data = array();
227
-
228
-    /**
229
-     * Stores the current scope during template runtime.
230
-     * this should ideally not be accessed directly from outside template code
231
-     *
232
-     * @var mixed
233
-     */
234
-    public $scope;
235
-
236
-    /**
237
-     * Stores the scope tree during template runtime.
238
-     *
239
-     * @var array
240
-     */
241
-    protected $scopeTree = array();
242
-
243
-    /**
244
-     * Stores the block plugins stack during template runtime.
245
-     *
246
-     * @var array
247
-     */
248
-    protected $stack = array();
249
-
250
-    /**
251
-     * Stores the current block plugin at the top of the stack during template runtime.
252
-     *
253
-     * @var BlockPlugin
254
-     */
255
-    protected $curBlock;
256
-
257
-    /**
258
-     * Stores the output buffer during template runtime.
259
-     *
260
-     * @var string
261
-     */
262
-    protected $buffer;
263
-
264
-    /**
265
-     * Stores plugin proxy.
266
-     *
267
-     * @var IPluginProxy
268
-     */
269
-    protected $pluginProxy;
270
-
271
-    /**
272
-     * Constructor, sets the cache and compile dir to the default values if not provided.
273
-     *
274
-     * @param string $compileDir path to the compiled directory, defaults to lib/compiled
275
-     * @param string $cacheDir   path to the cache directory, defaults to lib/cache
276
-     */
277
-    public function __construct($compileDir = null, $cacheDir = null)
278
-    {
279
-        if ($compileDir !== null) {
280
-            $this->setCompileDir($compileDir);
281
-        }
282
-        if ($cacheDir !== null) {
283
-            $this->setCacheDir($cacheDir);
284
-        }
285
-        $this->initGlobals();
286
-    }
287
-
288
-    /**
289
-     * Resets some runtime variables to allow a cloned object to be used to render sub-templates.
290
-     *
291
-     * @return void
292
-     */
293
-    public function __clone()
294
-    {
295
-        $this->template = null;
296
-        unset($this->data);
297
-        unset($this->returnData);
298
-    }
299
-
300
-    /**
301
-     * Returns the given template rendered using the provided data and optional compiler.
302
-     *
303
-     * @param mixed     $_tpl      template, can either be a ITemplate object (i.e. TemplateFile), a
304
-     *                             valid path to a template, or a template as a string it is recommended to
305
-     *                             provide a ITemplate as it will probably make things faster, especially if
306
-     *                             you render a template multiple times
307
-     * @param mixed     $data      the data to use, can either be a IDataProvider object (i.e. Data) or
308
-     *                             an associative array. if you're rendering the template from cache, it can be
309
-     *                             left null
310
-     * @param ICompiler $_compiler the compiler that must be used to compile the template, if left empty a default
311
-     *                             Compiler will be used
312
-     *
313
-     * @return string|void or the template output if $output is false
314
-     * @throws Exception
315
-     */
316
-    public function get($_tpl, $data = array(), $_compiler = null)
317
-    {
318
-        // a render call came from within a template, so we need a new dwoo instance in order to avoid breaking this one
319
-        if ($this->template instanceof ITemplate) {
320
-            $clone = clone $this;
321
-
322
-            return $clone->get($_tpl, $data, $_compiler);
323
-        }
324
-
325
-        // auto-create template if required
326
-        if ($_tpl instanceof ITemplate) {
327
-            // valid, skip
328
-        } elseif (is_string($_tpl)) {
329
-            $_tpl = new TemplateFile($_tpl);
330
-            $_tpl->setIncludePath($this->getTemplateDir());
331
-        } else {
332
-            throw new Exception(
333
-                '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.4';
53
+
54
+	/**
55
+	 * Unique number of this dwoo release, based on version number.
56
+	 * this can be used by templates classes to check whether the compiled template
57
+	 * has been compiled before this release or not, so that old templates are
58
+	 * recompiled automatically when Dwoo is updated
59
+	 */
60
+	const RELEASE_TAG = 134;
61
+
62
+	/**
63
+	 * Constants that represents all plugin types
64
+	 * these are bitwise-operation-safe values to allow multiple types
65
+	 * on a single plugin
66
+	 *
67
+	 * @var int
68
+	 */
69
+	const CLASS_PLUGIN      = 1;
70
+	const FUNC_PLUGIN       = 2;
71
+	const NATIVE_PLUGIN     = 4;
72
+	const BLOCK_PLUGIN      = 8;
73
+	const COMPILABLE_PLUGIN = 16;
74
+	const CUSTOM_PLUGIN     = 32;
75
+	const SMARTY_MODIFIER   = 64;
76
+	const SMARTY_BLOCK      = 128;
77
+	const SMARTY_FUNCTION   = 256;
78
+	const PROXY_PLUGIN      = 512;
79
+	const TEMPLATE_PLUGIN   = 1024;
80
+
81
+	/**
82
+	 * Constant to default namespaces of builtin plugins
83
+	 *
84
+	 * @var string
85
+	 */
86
+	const NAMESPACE_PLUGINS_BLOCKS     = 'Dwoo\Plugins\Blocks\\';
87
+	const NAMESPACE_PLUGINS_FILTERS    = 'Dwoo\Plugins\Filters\\';
88
+	const NAMESPACE_PLUGINS_FUNCTIONS  = 'Dwoo\Plugins\Functions\\';
89
+	const NAMESPACE_PLUGINS_HELPERS    = 'Dwoo\Plugins\Helpers\\';
90
+	const NAMESPACE_PLUGINS_PROCESSORS = 'Dwoo\Plugins\Processors\\';
91
+
92
+	/**
93
+	 * Character set of the template, used by string manipulation plugins.
94
+	 * it must be lowercase, but setCharset() will take care of that
95
+	 *
96
+	 * @see setCharset
97
+	 * @see getCharset
98
+	 * @var string
99
+	 */
100
+	protected $charset = 'UTF-8';
101
+
102
+	/**
103
+	 * Global variables that are accessible through $dwoo.* in the templates.
104
+	 * default values include:
105
+	 * $dwoo.version - current version number
106
+	 * $dwoo.ad - a Powered by Dwoo link pointing to dwoo.org
107
+	 * $dwoo.now - the current time
108
+	 * $dwoo.template - the current template filename
109
+	 * $dwoo.charset - the character set used by the template
110
+	 * on top of that, foreach and other plugins can store special values in there,
111
+	 * see their documentation for more details.
112
+	 *
113
+	 * @var array
114
+	 */
115
+	protected $globals = array();
116
+
117
+	/**
118
+	 * Directory where the compiled templates are stored.
119
+	 * defaults to DWOO_COMPILEDIR (= dwoo_dir/compiled by default)
120
+	 *
121
+	 * @var string
122
+	 */
123
+	protected $compileDir;
124
+
125
+	/**
126
+	 * Directory where the cached templates are stored.
127
+	 * defaults to DWOO_CACHEDIR (= dwoo_dir/cache by default)
128
+	 *
129
+	 * @var string
130
+	 */
131
+	protected $cacheDir;
132
+
133
+	/**
134
+	 * Directory where the template files are stored
135
+	 *
136
+	 * @var array
137
+	 */
138
+	protected $templateDir = array();
139
+
140
+	/**
141
+	 * Defines how long (in seconds) the cached files must remain valid.
142
+	 * can be overridden on a per-template basis
143
+	 * -1 = never delete
144
+	 * 0 = disabled
145
+	 * >0 = duration in seconds
146
+	 *
147
+	 * @var int
148
+	 */
149
+	protected $cacheTime = 0;
150
+
151
+	/**
152
+	 * Security policy object.
153
+	 *
154
+	 * @var SecurityPolicy
155
+	 */
156
+	protected $securityPolicy = null;
157
+
158
+	/**
159
+	 * Stores the custom plugins callbacks.
160
+	 *
161
+	 * @see addPlugin
162
+	 * @see removePlugin
163
+	 * @var array
164
+	 */
165
+	protected $plugins = array();
166
+
167
+	/**
168
+	 * Stores the filter callbacks.
169
+	 *
170
+	 * @see addFilter
171
+	 * @see removeFilter
172
+	 * @var array
173
+	 */
174
+	protected $filters = array();
175
+
176
+	/**
177
+	 * Stores the resource types and associated
178
+	 * classes / compiler classes.
179
+	 *
180
+	 * @var array
181
+	 */
182
+	protected $resources = array(
183
+		'file'   => array(
184
+			'class'    => 'Dwoo\Template\File',
185
+			'compiler' => null,
186
+		),
187
+		'string' => array(
188
+			'class'    => 'Dwoo\Template\Str',
189
+			'compiler' => null,
190
+		),
191
+	);
192
+
193
+	/**
194
+	 * The dwoo loader object used to load plugins by this dwoo instance.
195
+	 *
196
+	 * @var ILoader
197
+	 */
198
+	protected $loader = null;
199
+
200
+	/**
201
+	 * Currently rendered template, set to null when not-rendering.
202
+	 *
203
+	 * @var ITemplate
204
+	 */
205
+	protected $template = null;
206
+
207
+	/**
208
+	 * Stores the instances of the class plugins during template runtime.
209
+	 *
210
+	 * @var array
211
+	 */
212
+	protected $runtimePlugins = array();
213
+
214
+	/**
215
+	 * Stores the returned values during template runtime.
216
+	 *
217
+	 * @var array
218
+	 */
219
+	protected $returnData = array();
220
+
221
+	/**
222
+	 * Stores the data during template runtime.
223
+	 *
224
+	 * @var array
225
+	 */
226
+	protected $data = array();
227
+
228
+	/**
229
+	 * Stores the current scope during template runtime.
230
+	 * this should ideally not be accessed directly from outside template code
231
+	 *
232
+	 * @var mixed
233
+	 */
234
+	public $scope;
235
+
236
+	/**
237
+	 * Stores the scope tree during template runtime.
238
+	 *
239
+	 * @var array
240
+	 */
241
+	protected $scopeTree = array();
242
+
243
+	/**
244
+	 * Stores the block plugins stack during template runtime.
245
+	 *
246
+	 * @var array
247
+	 */
248
+	protected $stack = array();
249
+
250
+	/**
251
+	 * Stores the current block plugin at the top of the stack during template runtime.
252
+	 *
253
+	 * @var BlockPlugin
254
+	 */
255
+	protected $curBlock;
256
+
257
+	/**
258
+	 * Stores the output buffer during template runtime.
259
+	 *
260
+	 * @var string
261
+	 */
262
+	protected $buffer;
263
+
264
+	/**
265
+	 * Stores plugin proxy.
266
+	 *
267
+	 * @var IPluginProxy
268
+	 */
269
+	protected $pluginProxy;
270
+
271
+	/**
272
+	 * Constructor, sets the cache and compile dir to the default values if not provided.
273
+	 *
274
+	 * @param string $compileDir path to the compiled directory, defaults to lib/compiled
275
+	 * @param string $cacheDir   path to the cache directory, defaults to lib/cache
276
+	 */
277
+	public function __construct($compileDir = null, $cacheDir = null)
278
+	{
279
+		if ($compileDir !== null) {
280
+			$this->setCompileDir($compileDir);
281
+		}
282
+		if ($cacheDir !== null) {
283
+			$this->setCacheDir($cacheDir);
284
+		}
285
+		$this->initGlobals();
286
+	}
287
+
288
+	/**
289
+	 * Resets some runtime variables to allow a cloned object to be used to render sub-templates.
290
+	 *
291
+	 * @return void
292
+	 */
293
+	public function __clone()
294
+	{
295
+		$this->template = null;
296
+		unset($this->data);
297
+		unset($this->returnData);
298
+	}
299
+
300
+	/**
301
+	 * Returns the given template rendered using the provided data and optional compiler.
302
+	 *
303
+	 * @param mixed     $_tpl      template, can either be a ITemplate object (i.e. TemplateFile), a
304
+	 *                             valid path to a template, or a template as a string it is recommended to
305
+	 *                             provide a ITemplate as it will probably make things faster, especially if
306
+	 *                             you render a template multiple times
307
+	 * @param mixed     $data      the data to use, can either be a IDataProvider object (i.e. Data) or
308
+	 *                             an associative array. if you're rendering the template from cache, it can be
309
+	 *                             left null
310
+	 * @param ICompiler $_compiler the compiler that must be used to compile the template, if left empty a default
311
+	 *                             Compiler will be used
312
+	 *
313
+	 * @return string|void or the template output if $output is false
314
+	 * @throws Exception
315
+	 */
316
+	public function get($_tpl, $data = array(), $_compiler = null)
317
+	{
318
+		// a render call came from within a template, so we need a new dwoo instance in order to avoid breaking this one
319
+		if ($this->template instanceof ITemplate) {
320
+			$clone = clone $this;
321
+
322
+			return $clone->get($_tpl, $data, $_compiler);
323
+		}
324
+
325
+		// auto-create template if required
326
+		if ($_tpl instanceof ITemplate) {
327
+			// valid, skip
328
+		} elseif (is_string($_tpl)) {
329
+			$_tpl = new TemplateFile($_tpl);
330
+			$_tpl->setIncludePath($this->getTemplateDir());
331
+		} else {
332
+			throw new Exception(
333
+				'Dwoo->get\'s first argument must be a ITemplate (i.e. TemplateFile) or 
334 334
             a valid path to a template file', E_USER_NOTICE
335
-            );
336
-        }
337
-
338
-        // save the current template, enters render mode at the same time
339
-        // if another rendering is requested it will be proxied to a new Core(instance
340
-        $this->template = $_tpl;
341
-
342
-        // load data
343
-        if ($data instanceof IDataProvider) {
344
-            $this->data = $data->getData();
345
-        } elseif (is_array($data)) {
346
-            $this->data = $data;
347
-        } elseif ($data instanceof ArrayAccess) {
348
-            $this->data = $data;
349
-        } else {
350
-            throw new Exception(
351
-                'Dwoo->get/Dwoo->output\'s data argument must be a IDataProvider object (i.e. Data) or
335
+			);
336
+		}
337
+
338
+		// save the current template, enters render mode at the same time
339
+		// if another rendering is requested it will be proxied to a new Core(instance
340
+		$this->template = $_tpl;
341
+
342
+		// load data
343
+		if ($data instanceof IDataProvider) {
344
+			$this->data = $data->getData();
345
+		} elseif (is_array($data)) {
346
+			$this->data = $data;
347
+		} elseif ($data instanceof ArrayAccess) {
348
+			$this->data = $data;
349
+		} else {
350
+			throw new Exception(
351
+				'Dwoo->get/Dwoo->output\'s data argument must be a IDataProvider object (i.e. Data) or
352 352
             an associative array', E_USER_NOTICE
353
-            );
354
-        }
355
-
356
-        $this->addGlobal('template', $_tpl->getName());
357
-        $this->initRuntimeVars($_tpl);
358
-
359
-        // try to get cached template
360
-        $file        = $_tpl->getCachedTemplate($this);
361
-        $doCache     = $file === true;
362
-        $cacheLoaded = is_string($file);
363
-
364
-        if ($cacheLoaded === true) {
365
-            // cache is present, run it
366
-            ob_start();
367
-            include $file;
368
-            $this->template = null;
369
-
370
-            return ob_get_clean();
371
-        } else {
372
-            $dynamicId = uniqid();
373
-
374
-            // render template
375
-            $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
376
-            $out              = include $compiledTemplate;
377
-
378
-            // template returned false so it needs to be recompiled
379
-            if ($out === false) {
380
-                $_tpl->forceCompilation();
381
-                $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
382
-                $out              = include $compiledTemplate;
383
-            }
384
-
385
-            if ($doCache === true) {
386
-                $out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php /*' . $dynamicId . '*/ echo \'$1\'; ?>', $out);
387
-                if (!class_exists(self::NAMESPACE_PLUGINS_BLOCKS . 'PluginDynamic')) {
388
-                    $this->getLoader()->loadPlugin('PluginDynamic');
389
-                }
390
-                $out = PluginDynamic::unescape($out, $dynamicId, $compiledTemplate);
391
-            }
392
-
393
-            // process filters
394
-            foreach ($this->filters as $filter) {
395
-                if (is_array($filter) && $filter[0] instanceof Filter) {
396
-                    $out = call_user_func($filter, $out);
397
-                } else {
398
-                    $out = call_user_func($filter, $this, $out);
399
-                }
400
-            }
401
-
402
-            if ($doCache === true) {
403
-                // building cache
404
-                $file = $_tpl->cache($this, $out);
405
-
406
-                // run it from the cache to be sure dynamics are rendered
407
-                ob_start();
408
-                include $file;
409
-                // exit render mode
410
-                $this->template = null;
411
-
412
-                return ob_get_clean();
413
-            } else {
414
-                // no need to build cache
415
-                // exit render mode
416
-                $this->template = null;
417
-
418
-                return $out;
419
-            }
420
-        }
421
-    }
422
-
423
-    /**
424
-     * Registers a Global.
425
-     * New globals can be added before compiling or rendering a template
426
-     * but after, you can only update existing globals.
427
-     *
428
-     * @param string $name
429
-     * @param mixed  $value
430
-     *
431
-     * @return $this
432
-     * @throws Exception
433
-     */
434
-    public function addGlobal($name, $value)
435
-    {
436
-        if (null === $this->globals) {
437
-            $this->initGlobals();
438
-        }
439
-
440
-        $this->globals[$name] = $value;
441
-
442
-        return $this;
443
-    }
444
-
445
-    /**
446
-     * Gets the registered Globals.
447
-     *
448
-     * @return array
449
-     */
450
-    public function getGlobals()
451
-    {
452
-        return $this->globals;
453
-    }
454
-
455
-    /**
456
-     * Re-initializes the globals array before each template run.
457
-     * this method is only callede once when the Dwoo object is created
458
-     *
459
-     * @return void
460
-     */
461
-    protected function initGlobals()
462
-    {
463
-        $this->globals = array(
464
-            'version' => self::VERSION,
465
-            'ad'      => '<a href="http://dwoo.org/">Powered by Dwoo</a>',
466
-            'now'     => $_SERVER['REQUEST_TIME'],
467
-            'charset' => $this->getCharset(),
468
-        );
469
-    }
470
-
471
-    /**
472
-     * Re-initializes the runtime variables before each template run.
473
-     * override this method to inject data in the globals array if needed, this
474
-     * method is called before each template execution
475
-     *
476
-     * @param ITemplate $tpl the template that is going to be rendered
477
-     *
478
-     * @return void
479
-     */
480
-    protected function initRuntimeVars(ITemplate $tpl)
481
-    {
482
-        $this->runtimePlugins = array();
483
-        $this->scope          = &$this->data;
484
-        $this->scopeTree      = array();
485
-        $this->stack          = array();
486
-        $this->curBlock       = null;
487
-        $this->buffer         = '';
488
-        $this->returnData     = array();
489
-    }
490
-
491
-    /**
492
-     * Adds a custom plugin that is not in one of the plugin directories.
493
-     *
494
-     * @param string   $name       the plugin name to be used in the templates
495
-     * @param callback $callback   the plugin callback, either a function name,
496
-     *                             a class name or an array containing an object
497
-     *                             or class name and a method name
498
-     * @param bool     $compilable if set to true, the plugin is assumed to be compilable
499
-     *
500
-     * @return void
501
-     * @throws Exception
502
-     */
503
-    public function addPlugin($name, $callback, $compilable = false)
504
-    {
505
-        $compilable = $compilable ? self::COMPILABLE_PLUGIN : 0;
506
-        if (is_array($callback)) {
507
-            if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo\Block\Plugin')) {
508
-                $this->plugins[$name] = array(
509
-                    'type'     => self::BLOCK_PLUGIN | $compilable,
510
-                    'callback' => $callback,
511
-                    'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0])
512
-                );
513
-            } else {
514
-                $this->plugins[$name] = array(
515
-                    'type'     => self::CLASS_PLUGIN | $compilable,
516
-                    'callback' => $callback,
517
-                    'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0]),
518
-                    'function' => $callback[1]
519
-                );
520
-            }
521
-        } elseif (is_string($callback)) {
522
-            if (class_exists($callback)) {
523
-                if (is_subclass_of($callback, 'Dwoo\Block\Plugin')) {
524
-                    $this->plugins[$name] = array(
525
-                        'type'     => self::BLOCK_PLUGIN | $compilable,
526
-                        'callback' => $callback,
527
-                        'class'    => $callback
528
-                    );
529
-                } else {
530
-                    $this->plugins[$name] = array(
531
-                        'type'     => self::CLASS_PLUGIN | $compilable,
532
-                        'callback' => $callback,
533
-                        'class'    => $callback,
534
-                        'function' => ($compilable ? 'compile' : 'process')
535
-                    );
536
-                }
537
-            } elseif (function_exists($callback)) {
538
-                $this->plugins[$name] = array(
539
-                    'type'     => self::FUNC_PLUGIN | $compilable,
540
-                    'callback' => $callback
541
-                );
542
-            } else {
543
-                throw new Exception(
544
-                    'Callback could not be processed correctly, please check that the function/class 
353
+			);
354
+		}
355
+
356
+		$this->addGlobal('template', $_tpl->getName());
357
+		$this->initRuntimeVars($_tpl);
358
+
359
+		// try to get cached template
360
+		$file        = $_tpl->getCachedTemplate($this);
361
+		$doCache     = $file === true;
362
+		$cacheLoaded = is_string($file);
363
+
364
+		if ($cacheLoaded === true) {
365
+			// cache is present, run it
366
+			ob_start();
367
+			include $file;
368
+			$this->template = null;
369
+
370
+			return ob_get_clean();
371
+		} else {
372
+			$dynamicId = uniqid();
373
+
374
+			// render template
375
+			$compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
376
+			$out              = include $compiledTemplate;
377
+
378
+			// template returned false so it needs to be recompiled
379
+			if ($out === false) {
380
+				$_tpl->forceCompilation();
381
+				$compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
382
+				$out              = include $compiledTemplate;
383
+			}
384
+
385
+			if ($doCache === true) {
386
+				$out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php /*' . $dynamicId . '*/ echo \'$1\'; ?>', $out);
387
+				if (!class_exists(self::NAMESPACE_PLUGINS_BLOCKS . 'PluginDynamic')) {
388
+					$this->getLoader()->loadPlugin('PluginDynamic');
389
+				}
390
+				$out = PluginDynamic::unescape($out, $dynamicId, $compiledTemplate);
391
+			}
392
+
393
+			// process filters
394
+			foreach ($this->filters as $filter) {
395
+				if (is_array($filter) && $filter[0] instanceof Filter) {
396
+					$out = call_user_func($filter, $out);
397
+				} else {
398
+					$out = call_user_func($filter, $this, $out);
399
+				}
400
+			}
401
+
402
+			if ($doCache === true) {
403
+				// building cache
404
+				$file = $_tpl->cache($this, $out);
405
+
406
+				// run it from the cache to be sure dynamics are rendered
407
+				ob_start();
408
+				include $file;
409
+				// exit render mode
410
+				$this->template = null;
411
+
412
+				return ob_get_clean();
413
+			} else {
414
+				// no need to build cache
415
+				// exit render mode
416
+				$this->template = null;
417
+
418
+				return $out;
419
+			}
420
+		}
421
+	}
422
+
423
+	/**
424
+	 * Registers a Global.
425
+	 * New globals can be added before compiling or rendering a template
426
+	 * but after, you can only update existing globals.
427
+	 *
428
+	 * @param string $name
429
+	 * @param mixed  $value
430
+	 *
431
+	 * @return $this
432
+	 * @throws Exception
433
+	 */
434
+	public function addGlobal($name, $value)
435
+	{
436
+		if (null === $this->globals) {
437
+			$this->initGlobals();
438
+		}
439
+
440
+		$this->globals[$name] = $value;
441
+
442
+		return $this;
443
+	}
444
+
445
+	/**
446
+	 * Gets the registered Globals.
447
+	 *
448
+	 * @return array
449
+	 */
450
+	public function getGlobals()
451
+	{
452
+		return $this->globals;
453
+	}
454
+
455
+	/**
456
+	 * Re-initializes the globals array before each template run.
457
+	 * this method is only callede once when the Dwoo object is created
458
+	 *
459
+	 * @return void
460
+	 */
461
+	protected function initGlobals()
462
+	{
463
+		$this->globals = array(
464
+			'version' => self::VERSION,
465
+			'ad'      => '<a href="http://dwoo.org/">Powered by Dwoo</a>',
466
+			'now'     => $_SERVER['REQUEST_TIME'],
467
+			'charset' => $this->getCharset(),
468
+		);
469
+	}
470
+
471
+	/**
472
+	 * Re-initializes the runtime variables before each template run.
473
+	 * override this method to inject data in the globals array if needed, this
474
+	 * method is called before each template execution
475
+	 *
476
+	 * @param ITemplate $tpl the template that is going to be rendered
477
+	 *
478
+	 * @return void
479
+	 */
480
+	protected function initRuntimeVars(ITemplate $tpl)
481
+	{
482
+		$this->runtimePlugins = array();
483
+		$this->scope          = &$this->data;
484
+		$this->scopeTree      = array();
485
+		$this->stack          = array();
486
+		$this->curBlock       = null;
487
+		$this->buffer         = '';
488
+		$this->returnData     = array();
489
+	}
490
+
491
+	/**
492
+	 * Adds a custom plugin that is not in one of the plugin directories.
493
+	 *
494
+	 * @param string   $name       the plugin name to be used in the templates
495
+	 * @param callback $callback   the plugin callback, either a function name,
496
+	 *                             a class name or an array containing an object
497
+	 *                             or class name and a method name
498
+	 * @param bool     $compilable if set to true, the plugin is assumed to be compilable
499
+	 *
500
+	 * @return void
501
+	 * @throws Exception
502
+	 */
503
+	public function addPlugin($name, $callback, $compilable = false)
504
+	{
505
+		$compilable = $compilable ? self::COMPILABLE_PLUGIN : 0;
506
+		if (is_array($callback)) {
507
+			if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo\Block\Plugin')) {
508
+				$this->plugins[$name] = array(
509
+					'type'     => self::BLOCK_PLUGIN | $compilable,
510
+					'callback' => $callback,
511
+					'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0])
512
+				);
513
+			} else {
514
+				$this->plugins[$name] = array(
515
+					'type'     => self::CLASS_PLUGIN | $compilable,
516
+					'callback' => $callback,
517
+					'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0]),
518
+					'function' => $callback[1]
519
+				);
520
+			}
521
+		} elseif (is_string($callback)) {
522
+			if (class_exists($callback)) {
523
+				if (is_subclass_of($callback, 'Dwoo\Block\Plugin')) {
524
+					$this->plugins[$name] = array(
525
+						'type'     => self::BLOCK_PLUGIN | $compilable,
526
+						'callback' => $callback,
527
+						'class'    => $callback
528
+					);
529
+				} else {
530
+					$this->plugins[$name] = array(
531
+						'type'     => self::CLASS_PLUGIN | $compilable,
532
+						'callback' => $callback,
533
+						'class'    => $callback,
534
+						'function' => ($compilable ? 'compile' : 'process')
535
+					);
536
+				}
537
+			} elseif (function_exists($callback)) {
538
+				$this->plugins[$name] = array(
539
+					'type'     => self::FUNC_PLUGIN | $compilable,
540
+					'callback' => $callback
541
+				);
542
+			} else {
543
+				throw new Exception(
544
+					'Callback could not be processed correctly, please check that the function/class 
545 545
                 you used exists'
546
-                );
547
-            }
548
-        } elseif ($callback instanceof Closure) {
549
-            $this->plugins[$name] = array(
550
-                'type'     => self::FUNC_PLUGIN | $compilable,
551
-                'callback' => $callback
552
-            );
553
-        } else {
554
-            throw new Exception(
555
-                'Callback could not be processed correctly, please check that the function/class you 
546
+				);
547
+			}
548
+		} elseif ($callback instanceof Closure) {
549
+			$this->plugins[$name] = array(
550
+				'type'     => self::FUNC_PLUGIN | $compilable,
551
+				'callback' => $callback
552
+			);
553
+		} else {
554
+			throw new Exception(
555
+				'Callback could not be processed correctly, please check that the function/class you 
556 556
             used exists'
557
-            );
558
-        }
559
-    }
560
-
561
-    /**
562
-     * Removes a custom plugin.
563
-     *
564
-     * @param string $name the plugin name
565
-     *
566
-     * @return void
567
-     */
568
-    public function removePlugin($name)
569
-    {
570
-        if (isset($this->plugins[$name])) {
571
-            unset($this->plugins[$name]);
572
-        }
573
-    }
574
-
575
-    /**
576
-     * Adds a filter to this Dwoo instance, it will be used to filter the output of all the templates rendered by this
577
-     * instance.
578
-     *
579
-     * @param mixed $callback a callback or a filter name if it is autoloaded from a plugin directory
580
-     * @param bool  $autoload if true, the first parameter must be a filter name from one of the plugin directories
581
-     *
582
-     * @return void
583
-     * @throws Exception
584
-     */
585
-    public function addFilter($callback, $autoload = false)
586
-    {
587
-        if ($autoload) {
588
-            $class = self::NAMESPACE_PLUGINS_FILTERS . self::toCamelCase($callback);
589
-            if (!class_exists($class) && !function_exists($class)) {
590
-                try {
591
-                    $this->getLoader()->loadPlugin($callback);
592
-                }
593
-                catch (Exception $e) {
594
-                    if (strstr($callback, self::NAMESPACE_PLUGINS_FILTERS)) {
595
-                        throw new Exception(
596
-                            'Wrong filter name : ' . $callback . ', the "Filter" prefix should 
557
+			);
558
+		}
559
+	}
560
+
561
+	/**
562
+	 * Removes a custom plugin.
563
+	 *
564
+	 * @param string $name the plugin name
565
+	 *
566
+	 * @return void
567
+	 */
568
+	public function removePlugin($name)
569
+	{
570
+		if (isset($this->plugins[$name])) {
571
+			unset($this->plugins[$name]);
572
+		}
573
+	}
574
+
575
+	/**
576
+	 * Adds a filter to this Dwoo instance, it will be used to filter the output of all the templates rendered by this
577
+	 * instance.
578
+	 *
579
+	 * @param mixed $callback a callback or a filter name if it is autoloaded from a plugin directory
580
+	 * @param bool  $autoload if true, the first parameter must be a filter name from one of the plugin directories
581
+	 *
582
+	 * @return void
583
+	 * @throws Exception
584
+	 */
585
+	public function addFilter($callback, $autoload = false)
586
+	{
587
+		if ($autoload) {
588
+			$class = self::NAMESPACE_PLUGINS_FILTERS . self::toCamelCase($callback);
589
+			if (!class_exists($class) && !function_exists($class)) {
590
+				try {
591
+					$this->getLoader()->loadPlugin($callback);
592
+				}
593
+				catch (Exception $e) {
594
+					if (strstr($callback, self::NAMESPACE_PLUGINS_FILTERS)) {
595
+						throw new Exception(
596
+							'Wrong filter name : ' . $callback . ', the "Filter" prefix should 
597 597
                         not be used, please only use "' . str_replace('Filter', '', $callback) . '"'
598
-                        );
599
-                    } else {
600
-                        throw new Exception(
601
-                            'Wrong filter name : ' . $callback . ', when using autoload the filter must
598
+						);
599
+					} else {
600
+						throw new Exception(
601
+							'Wrong filter name : ' . $callback . ', when using autoload the filter must
602 602
                          be in one of your plugin dir as "name.php" containig a class or function named
603 603
                          "Filter<name>"'
604
-                        );
605
-                    }
606
-                }
607
-            }
608
-
609
-            if (class_exists($class)) {
610
-                $callback = array(new $class($this), 'process');
611
-            } elseif (function_exists($class)) {
612
-                $callback = $class;
613
-            } else {
614
-                throw new Exception(
615
-                    'Wrong filter name : ' . $callback . ', when using autoload the filter must be in
604
+						);
605
+					}
606
+				}
607
+			}
608
+
609
+			if (class_exists($class)) {
610
+				$callback = array(new $class($this), 'process');
611
+			} elseif (function_exists($class)) {
612
+				$callback = $class;
613
+			} else {
614
+				throw new Exception(
615
+					'Wrong filter name : ' . $callback . ', when using autoload the filter must be in
616 616
                 one of your plugin dir as "name.php" containig a class or function named "Filter<name>"'
617
-                );
618
-            }
619
-
620
-            $this->filters[] = $callback;
621
-        } else {
622
-            $this->filters[] = $callback;
623
-        }
624
-    }
625
-
626
-    /**
627
-     * Removes a filter.
628
-     *
629
-     * @param mixed $callback callback or filter name if it was autoloaded
630
-     *
631
-     * @return void
632
-     */
633
-    public function removeFilter($callback)
634
-    {
635
-        if (($index = array_search(self::NAMESPACE_PLUGINS_FILTERS. 'Filter' . self::toCamelCase($callback), $this->filters,
636
-                true)) !==
637
-            false) {
638
-            unset($this->filters[$index]);
639
-        } elseif (($index = array_search($callback, $this->filters, true)) !== false) {
640
-            unset($this->filters[$index]);
641
-        } else {
642
-            $class = self::NAMESPACE_PLUGINS_FILTERS . 'Filter' . $callback;
643
-            foreach ($this->filters as $index => $filter) {
644
-                if (is_array($filter) && $filter[0] instanceof $class) {
645
-                    unset($this->filters[$index]);
646
-                    break;
647
-                }
648
-            }
649
-        }
650
-    }
651
-
652
-    /**
653
-     * Adds a resource or overrides a default one.
654
-     *
655
-     * @param string   $name            the resource name
656
-     * @param string   $class           the resource class (which must implement ITemplate)
657
-     * @param callback $compilerFactory the compiler factory callback, a function that must return a compiler instance
658
-     *                                  used to compile this resource, if none is provided. by default it will produce
659
-     *                                  a Compiler object
660
-     *
661
-     * @return void
662
-     * @throws Exception
663
-     */
664
-    public function addResource($name, $class, $compilerFactory = null)
665
-    {
666
-        if (strlen($name) < 2) {
667
-            throw new Exception('Resource names must be at least two-character long to avoid conflicts with Windows paths');
668
-        }
669
-
670
-        if (!class_exists($class)) {
671
-            throw new Exception(sprintf('Resource class %s does not exist', $class));
672
-        }
673
-
674
-        $interfaces = class_implements($class);
675
-        if (in_array('Dwoo\ITemplate', $interfaces) === false) {
676
-            throw new Exception('Resource class must implement ITemplate');
677
-        }
678
-
679
-        $this->resources[$name] = array(
680
-            'class'    => $class,
681
-            'compiler' => $compilerFactory
682
-        );
683
-    }
684
-
685
-    /**
686
-     * Removes a custom resource.
687
-     *
688
-     * @param string $name the resource name
689
-     *
690
-     * @return void
691
-     */
692
-    public function removeResource($name)
693
-    {
694
-        unset($this->resources[$name]);
695
-        if ($name === 'file') {
696
-            $this->resources['file'] = array(
697
-                'class'    => 'Dwoo\Template\File',
698
-                'compiler' => null
699
-            );
700
-        }
701
-    }
702
-
703
-    /**
704
-     * Sets the loader object to use to load plugins.
705
-     *
706
-     * @param ILoader $loader loader
707
-     *
708
-     * @return void
709
-     */
710
-    public function setLoader(ILoader $loader)
711
-    {
712
-        $this->loader = $loader;
713
-    }
714
-
715
-    /**
716
-     * Returns the current loader object or a default one if none is currently found.
717
-     *
718
-     * @return ILoader|Loader
719
-     */
720
-    public function getLoader()
721
-    {
722
-        if ($this->loader === null) {
723
-            $this->loader = new Loader($this->getCompileDir());
724
-        }
725
-
726
-        return $this->loader;
727
-    }
728
-
729
-    /**
730
-     * Returns the custom plugins loaded.
731
-     * Used by the ITemplate classes to pass the custom plugins to their ICompiler instance.
732
-     *
733
-     * @return array
734
-     */
735
-    public function getCustomPlugins()
736
-    {
737
-        return $this->plugins;
738
-    }
739
-
740
-    /**
741
-     * Return a specified custom plugin loaded by his name.
742
-     * Used by the compiler, for executing a Closure.
743
-     *
744
-     * @param string $name
745
-     *
746
-     * @return mixed|null
747
-     */
748
-    public function getCustomPlugin($name)
749
-    {
750
-        if (isset($this->plugins[$name])) {
751
-            return $this->plugins[$name]['callback'];
752
-        }
753
-
754
-        return null;
755
-    }
756
-
757
-    /**
758
-     * Returns the cache directory with a trailing DIRECTORY_SEPARATOR.
759
-     *
760
-     * @return string
761
-     */
762
-    public function getCacheDir()
763
-    {
764
-        if ($this->cacheDir === null) {
765
-            $this->setCacheDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR);
766
-        }
767
-
768
-        return $this->cacheDir;
769
-    }
770
-
771
-    /**
772
-     * Sets the cache directory and automatically appends a DIRECTORY_SEPARATOR.
773
-     *
774
-     * @param string $dir the cache directory
775
-     *
776
-     * @return void
777
-     * @throws Exception
778
-     */
779
-    public function setCacheDir($dir)
780
-    {
781
-        $this->cacheDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
782
-        if (is_writable($this->cacheDir) === false) {
783
-            throw new Exception('The cache directory must be writable, chmod "' . $this->cacheDir . '" to make it writable');
784
-        }
785
-    }
786
-
787
-    /**
788
-     * Returns the compile directory with a trailing DIRECTORY_SEPARATOR.
789
-     *
790
-     * @return string
791
-     */
792
-    public function getCompileDir()
793
-    {
794
-        if ($this->compileDir === null) {
795
-            $this->setCompileDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'compiled' . DIRECTORY_SEPARATOR);
796
-        }
797
-
798
-        return $this->compileDir;
799
-    }
800
-
801
-    /**
802
-     * Sets the compile directory and automatically appends a DIRECTORY_SEPARATOR.
803
-     *
804
-     * @param string $dir the compile directory
805
-     *
806
-     * @return void
807
-     * @throws Exception
808
-     */
809
-    public function setCompileDir($dir)
810
-    {
811
-        $this->compileDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
812
-        if (is_writable($this->compileDir) === false) {
813
-            throw new Exception('The compile directory must be writable, chmod "' . $this->compileDir . '" to make it writable');
814
-        }
815
-    }
816
-
817
-    /**
818
-     * Returns an array of the template directory with a trailing DIRECTORY_SEPARATOR
819
-     *
820
-     * @return array
821
-     */
822
-    public function getTemplateDir()
823
-    {
824
-        return $this->templateDir;
825
-    }
826
-
827
-    /**
828
-     * sets the template directory and automatically appends a DIRECTORY_SEPARATOR
829
-     * template directory is stored in an array
830
-     *
831
-     * @param string $dir
832
-     *
833
-     * @throws Exception
834
-     */
835
-    public function setTemplateDir($dir)
836
-    {
837
-        $tmpDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
838
-        if (is_dir($tmpDir) === false) {
839
-            throw new Exception('The template directory: "' . $tmpDir . '" does not exists, create the directory or specify an other location !');
840
-        }
841
-        $this->templateDir[] = $tmpDir;
842
-    }
843
-
844
-    /**
845
-     * Returns the default cache time that is used with templates that do not have a cache time set.
846
-     *
847
-     * @return int the duration in seconds
848
-     */
849
-    public function getCacheTime()
850
-    {
851
-        return $this->cacheTime;
852
-    }
853
-
854
-    /**
855
-     * Sets the default cache time to use with templates that do not have a cache time set.
856
-     *
857
-     * @param int $seconds the duration in seconds
858
-     *
859
-     * @return void
860
-     */
861
-    public function setCacheTime($seconds)
862
-    {
863
-        $this->cacheTime = (int)$seconds;
864
-    }
865
-
866
-    /**
867
-     * Returns the character set used by the string manipulation plugins.
868
-     * the charset is automatically lowercased
869
-     *
870
-     * @return string
871
-     */
872
-    public function getCharset()
873
-    {
874
-        return $this->charset;
875
-    }
876
-
877
-    /**
878
-     * Sets the character set used by the string manipulation plugins.
879
-     * the charset will be automatically lowercased
880
-     *
881
-     * @param string $charset the character set
882
-     *
883
-     * @return void
884
-     */
885
-    public function setCharset($charset)
886
-    {
887
-        $this->charset = strtolower((string)$charset);
888
-    }
889
-
890
-    /**
891
-     * Returns the current template being rendered, when applicable, or null.
892
-     *
893
-     * @return ITemplate|null
894
-     */
895
-    public function getTemplate()
896
-    {
897
-        return $this->template;
898
-    }
899
-
900
-    /**
901
-     * Sets the current template being rendered.
902
-     *
903
-     * @param ITemplate $tpl template object
904
-     *
905
-     * @return void
906
-     */
907
-    public function setTemplate(ITemplate $tpl)
908
-    {
909
-        $this->template = $tpl;
910
-    }
911
-
912
-    /**
913
-     * Sets the default compiler factory function for the given resource name.
914
-     * a compiler factory must return a ICompiler object pre-configured to fit your needs
915
-     *
916
-     * @param string   $resourceName    the resource name (i.e. file, string)
917
-     * @param callback $compilerFactory the compiler factory callback
918
-     *
919
-     * @return void
920
-     */
921
-    public function setDefaultCompilerFactory($resourceName, $compilerFactory)
922
-    {
923
-        $this->resources[$resourceName]['compiler'] = $compilerFactory;
924
-    }
925
-
926
-    /**
927
-     * Returns the default compiler factory function for the given resource name.
928
-     *
929
-     * @param string $resourceName the resource name
930
-     *
931
-     * @return callback the compiler factory callback
932
-     */
933
-    public function getDefaultCompilerFactory($resourceName)
934
-    {
935
-        return $this->resources[$resourceName]['compiler'];
936
-    }
937
-
938
-    /**
939
-     * Sets the security policy object to enforce some php security settings.
940
-     * use this if untrusted persons can modify templates
941
-     *
942
-     * @param SecurityPolicy $policy the security policy object
943
-     *
944
-     * @return void
945
-     */
946
-    public function setSecurityPolicy(SecurityPolicy $policy = null)
947
-    {
948
-        $this->securityPolicy = $policy;
949
-    }
950
-
951
-    /**
952
-     * Returns the current security policy object or null by default.
953
-     *
954
-     * @return SecurityPolicy|null the security policy object if any
955
-     */
956
-    public function getSecurityPolicy()
957
-    {
958
-        return $this->securityPolicy;
959
-    }
960
-
961
-    /**
962
-     * Sets the object that must be used as a plugin proxy when plugin can't be found
963
-     * by dwoo's loader.
964
-     *
965
-     * @param IPluginProxy $pluginProxy the proxy object
966
-     *
967
-     * @return void
968
-     */
969
-    public function setPluginProxy(IPluginProxy $pluginProxy)
970
-    {
971
-        $this->pluginProxy = $pluginProxy;
972
-    }
973
-
974
-    /**
975
-     * Returns the current plugin proxy object or null by default.
976
-     *
977
-     * @return IPluginProxy
978
-     */
979
-    public function getPluginProxy()
980
-    {
981
-        return $this->pluginProxy;
982
-    }
983
-
984
-    /**
985
-     * Checks whether the given template is cached or not.
986
-     *
987
-     * @param ITemplate $tpl the template object
988
-     *
989
-     * @return bool
990
-     */
991
-    public function isCached(ITemplate $tpl)
992
-    {
993
-        return is_string($tpl->getCachedTemplate($this));
994
-    }
995
-
996
-    /**
997
-     * Clear templates inside the compiled directory.
998
-     *
999
-     * @return int
1000
-     */
1001
-    public function clearCompiled()
1002
-    {
1003
-        $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getCompileDir()), \RecursiveIteratorIterator::SELF_FIRST);
1004
-        $count    = 0;
1005
-        foreach ($iterator as $file) {
1006
-            if ($file->isFile()) {
1007
-                $count += unlink($file->__toString()) ? 1 : 0;
1008
-            }
1009
-        }
1010
-
1011
-        return $count;
1012
-    }
1013
-
1014
-    /**
1015
-     * Clears the cached templates if they are older than the given time.
1016
-     *
1017
-     * @param int $olderThan minimum time (in seconds) required for a cached template to be cleared
1018
-     *
1019
-     * @return int the amount of templates cleared
1020
-     */
1021
-    public function clearCache($olderThan = - 1)
1022
-    {
1023
-        $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getCacheDir()), \RecursiveIteratorIterator::SELF_FIRST);
1024
-        $expired  = time() - $olderThan;
1025
-        $count    = 0;
1026
-        foreach ($iterator as $file) {
1027
-            if ($file->isFile() && $file->getCTime() < $expired) {
1028
-                $count += unlink((string)$file) ? 1 : 0;
1029
-            }
1030
-        }
1031
-
1032
-        return $count;
1033
-    }
1034
-
1035
-    /**
1036
-     * Fetches a template object of the given resource.
1037
-     *
1038
-     * @param string    $resourceName   the resource name (i.e. file, string)
1039
-     * @param string    $resourceId     the resource identifier (i.e. file path)
1040
-     * @param int       $cacheTime      the cache time setting for this resource
1041
-     * @param string    $cacheId        the unique cache identifier
1042
-     * @param string    $compileId      the unique compiler identifier
1043
-     * @param ITemplate $parentTemplate the parent template
1044
-     *
1045
-     * @return ITemplate
1046
-     * @throws Exception
1047
-     */
1048
-    public function templateFactory($resourceName, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, ITemplate $parentTemplate = null)
1049
-    {
1050
-        if (isset($this->resources[$resourceName])) {
1051
-            /**
1052
-             * Interface ITemplate
1053
-             *
1054
-             * @var ITemplate $class
1055
-             */
1056
-            $class = $this->resources[$resourceName]['class'];
1057
-
1058
-            return $class::templateFactory($this, $resourceId, $cacheTime, $cacheId, $compileId, $parentTemplate);
1059
-        }
1060
-
1061
-        throw new Exception('Unknown resource type : ' . $resourceName);
1062
-    }
1063
-
1064
-    /**
1065
-     * Checks if the input is an array or arrayaccess object, optionally it can also check if it's
1066
-     * empty.
1067
-     *
1068
-     * @param mixed $value        the variable to check
1069
-     * @param bool  $checkIsEmpty if true, the function will also check if the array|arrayaccess is empty,
1070
-     *                            and return true only if it's not empty
1071
-     *
1072
-     * @return int|bool true if it's an array|arrayaccess (or the item count if $checkIsEmpty is true) or false if it's
1073
-     *                  not an array|arrayaccess (or 0 if $checkIsEmpty is true)
1074
-     */
1075
-    public function isArray($value, $checkIsEmpty = false)
1076
-    {
1077
-        if (is_array($value) === true || $value instanceof ArrayAccess) {
1078
-            if ($checkIsEmpty === false) {
1079
-                return true;
1080
-            }
1081
-
1082
-            return $this->count($value);
1083
-        }
1084
-
1085
-        return false;
1086
-    }
1087
-
1088
-    /**
1089
-     * Checks if the input is an array or a traversable object, optionally it can also check if it's
1090
-     * empty.
1091
-     *
1092
-     * @param mixed $value        the variable to check
1093
-     * @param bool  $checkIsEmpty if true, the function will also check if the array|traversable is empty,
1094
-     *                            and return true only if it's not empty
1095
-     *
1096
-     * @return int|bool true if it's an array|traversable (or the item count if $checkIsEmpty is true) or false if it's
1097
-     *                  not an array|traversable (or 0 if $checkIsEmpty is true)
1098
-     */
1099
-    public function isTraversable($value, $checkIsEmpty = false)
1100
-    {
1101
-        if (is_array($value) === true) {
1102
-            if ($checkIsEmpty === false) {
1103
-                return true;
1104
-            } else {
1105
-                return count($value) > 0;
1106
-            }
1107
-        } elseif ($value instanceof Traversable) {
1108
-            if ($checkIsEmpty === false) {
1109
-                return true;
1110
-            } else {
1111
-                return $this->count($value);
1112
-            }
1113
-        }
1114
-
1115
-        return false;
1116
-    }
1117
-
1118
-    /**
1119
-     * Counts an array or arrayaccess/traversable object.
1120
-     *
1121
-     * @param mixed $value the value to count
1122
-     *
1123
-     * @return int|bool the count for arrays and objects that implement countable, true for other objects that don't,
1124
-     *                  and 0 for empty elements
1125
-     */
1126
-    public function count($value)
1127
-    {
1128
-        if (is_array($value) === true || $value instanceof Countable) {
1129
-            return count($value);
1130
-        } elseif ($value instanceof ArrayAccess) {
1131
-            if ($value->offsetExists(0)) {
1132
-                return true;
1133
-            }
1134
-        } elseif ($value instanceof Iterator) {
1135
-            $value->rewind();
1136
-            if ($value->valid()) {
1137
-                return true;
1138
-            }
1139
-        } elseif ($value instanceof Traversable) {
1140
-            foreach ($value as $dummy) {
1141
-                return true;
1142
-            }
1143
-        }
1144
-
1145
-        return 0;
1146
-    }
1147
-
1148
-    /**
1149
-     * Triggers a dwoo error.
1150
-     *
1151
-     * @param string $message the error message
1152
-     * @param int    $level   the error level, one of the PHP's E_* constants
1153
-     *
1154
-     * @return void
1155
-     */
1156
-    public function triggerError($message, $level = E_USER_NOTICE)
1157
-    {
1158
-        if (!($tplIdentifier = $this->template->getResourceIdentifier())) {
1159
-            $tplIdentifier = $this->template->getResourceName();
1160
-        }
1161
-        trigger_error('Dwoo error (in ' . $tplIdentifier . ') : ' . $message, $level);
1162
-    }
1163
-
1164
-    /**
1165
-     * Adds a block to the block stack.
1166
-     *
1167
-     * @param string $blockName the block name (without `Plugin` prefix)
1168
-     * @param array  $args      the arguments to be passed to the block's init() function
1169
-     *
1170
-     * @return BlockPlugin the newly created block
1171
-     */
1172
-    public function addStack($blockName, array $args = array())
1173
-    {
1174
-        if (isset($this->plugins[$blockName])) {
1175
-            $class = $this->plugins[$blockName]['class'];
1176
-        } else {
1177
-            $class = self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . self::toCamelCase($blockName);
1178
-        }
1179
-
1180
-        if ($this->curBlock !== null) {
1181
-            $this->curBlock->buffer(ob_get_contents());
1182
-            ob_clean();
1183
-        } else {
1184
-            $this->buffer .= ob_get_contents();
1185
-            ob_clean();
1186
-        }
1187
-
1188
-        $block = new $class($this);
1189
-
1190
-        call_user_func_array(array($block, 'init'), $args);
1191
-
1192
-        $this->stack[] = $this->curBlock = $block;
1193
-
1194
-        return $block;
1195
-    }
1196
-
1197
-    /**
1198
-     * Removes the plugin at the top of the block stack.
1199
-     * Calls the block buffer() function, followed by a call to end() and finally a call to process()
1200
-     *
1201
-     * @return void
1202
-     */
1203
-    public function delStack()
1204
-    {
1205
-        $args = func_get_args();
1206
-
1207
-        $this->curBlock->buffer(ob_get_contents());
1208
-        ob_clean();
1209
-
1210
-        call_user_func_array(array($this->curBlock, 'end'), $args);
1211
-
1212
-        $tmp = array_pop($this->stack);
1213
-
1214
-        if (count($this->stack) > 0) {
1215
-            $this->curBlock = end($this->stack);
1216
-            $this->curBlock->buffer($tmp->process());
1217
-        } else {
1218
-            if ($this->buffer !== '') {
1219
-                echo $this->buffer;
1220
-                $this->buffer = '';
1221
-            }
1222
-            $this->curBlock = null;
1223
-            echo $tmp->process();
1224
-        }
1225
-
1226
-        unset($tmp);
1227
-    }
1228
-
1229
-    /**
1230
-     * Returns the parent block of the given block.
1231
-     *
1232
-     * @param BlockPlugin $block the block class plugin
1233
-     *
1234
-     * @return BlockPlugin|false if the given block isn't in the stack
1235
-     */
1236
-    public function getParentBlock(BlockPlugin $block)
1237
-    {
1238
-        $index = array_search($block, $this->stack, true);
1239
-        if ($index !== false && $index > 0) {
1240
-            return $this->stack[$index - 1];
1241
-        }
1242
-
1243
-        return false;
1244
-    }
1245
-
1246
-    /**
1247
-     * Finds the closest block of the given type, starting at the top of the stack.
1248
-     *
1249
-     * @param string $type the type of plugin you want to find
1250
-     *
1251
-     * @return BlockPlugin|false if no plugin of such type is in the stack
1252
-     */
1253
-    public function findBlock($type)
1254
-    {
1255
-        if (isset($this->plugins[$type])) {
1256
-            $type = $this->plugins[$type]['class'];
1257
-        } else {
1258
-            $type = self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin_' . str_replace(self::NAMESPACE_PLUGINS_BLOCKS.'Plugin',
1259
-                    '', $type);
1260
-        }
1261
-
1262
-        $keys = array_keys($this->stack);
1263
-        while (($key = array_pop($keys)) !== false) {
1264
-            if ($this->stack[$key] instanceof $type) {
1265
-                return $this->stack[$key];
1266
-            }
1267
-        }
1268
-
1269
-        return false;
1270
-    }
1271
-
1272
-    /**
1273
-     * Returns a Plugin of the given class.
1274
-     * this is so a single instance of every class plugin is created at each template run,
1275
-     * allowing class plugins to have "per-template-run" static variables
1276
-     *
1277
-     * @param string $class the class name
1278
-     *
1279
-     * @return mixed an object of the given class
1280
-     */
1281
-    public function getObjectPlugin($class)
1282
-    {
1283
-        if (isset($this->runtimePlugins[$class])) {
1284
-            return $this->runtimePlugins[$class];
1285
-        }
1286
-
1287
-        return $this->runtimePlugins[$class] = new $class($this);
1288
-    }
1289
-
1290
-    /**
1291
-     * Calls the process() method of the given class-plugin name.
1292
-     *
1293
-     * @param string $plugName the class plugin name (without `Plugin` prefix)
1294
-     * @param array  $params   an array of parameters to send to the process() method
1295
-     *
1296
-     * @return string the process() return value
1297
-     */
1298
-    public function classCall($plugName, array $params = array())
1299
-    {
1300
-        $class  = self::toCamelCase($plugName);
1301
-        $plugin = $this->getObjectPlugin($class);
1302
-
1303
-        return call_user_func_array(array($plugin, 'process'), $params);
1304
-    }
1305
-
1306
-    /**
1307
-     * Calls a php function.
1308
-     *
1309
-     * @param string $callback the function to call
1310
-     * @param array  $params   an array of parameters to send to the function
1311
-     *
1312
-     * @return mixed the return value of the called function
1313
-     */
1314
-    public function arrayMap($callback, array $params)
1315
-    {
1316
-        if ($params[0] === $this) {
1317
-            $addThis = true;
1318
-            array_shift($params);
1319
-        }
1320
-        if ((is_array($params[0]) || ($params[0] instanceof Iterator && $params[0] instanceof ArrayAccess))) {
1321
-            if (empty($params[0])) {
1322
-                return $params[0];
1323
-            }
1324
-
1325
-            // array map
1326
-            $out = array();
1327
-            $cnt = count($params);
1328
-
1329
-            if (isset($addThis)) {
1330
-                array_unshift($params, $this);
1331
-                $items = $params[1];
1332
-                $keys  = array_keys($items);
1333
-
1334
-                if (is_string($callback) === false) {
1335
-                    while (($i = array_shift($keys)) !== null) {
1336
-                        $out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1337
-                    }
1338
-                } elseif ($cnt === 1) {
1339
-                    while (($i = array_shift($keys)) !== null) {
1340
-                        $out[] = $callback($this, $items[$i]);
1341
-                    }
1342
-                } elseif ($cnt === 2) {
1343
-                    while (($i = array_shift($keys)) !== null) {
1344
-                        $out[] = $callback($this, $items[$i], $params[2]);
1345
-                    }
1346
-                } elseif ($cnt === 3) {
1347
-                    while (($i = array_shift($keys)) !== null) {
1348
-                        $out[] = $callback($this, $items[$i], $params[2], $params[3]);
1349
-                    }
1350
-                } else {
1351
-                    while (($i = array_shift($keys)) !== null) {
1352
-                        $out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1353
-                    }
1354
-                }
1355
-            } else {
1356
-                $items = $params[0];
1357
-                $keys  = array_keys($items);
1358
-
1359
-                if (is_string($callback) === false) {
1360
-                    while (($i = array_shift($keys)) !== null) {
1361
-                        $out[] = call_user_func_array($callback, array($items[$i]) + $params);
1362
-                    }
1363
-                } elseif ($cnt === 1) {
1364
-                    while (($i = array_shift($keys)) !== null) {
1365
-                        $out[] = $callback($items[$i]);
1366
-                    }
1367
-                } elseif ($cnt === 2) {
1368
-                    while (($i = array_shift($keys)) !== null) {
1369
-                        $out[] = $callback($items[$i], $params[1]);
1370
-                    }
1371
-                } elseif ($cnt === 3) {
1372
-                    while (($i = array_shift($keys)) !== null) {
1373
-                        $out[] = $callback($items[$i], $params[1], $params[2]);
1374
-                    }
1375
-                } elseif ($cnt === 4) {
1376
-                    while (($i = array_shift($keys)) !== null) {
1377
-                        $out[] = $callback($items[$i], $params[1], $params[2], $params[3]);
1378
-                    }
1379
-                } else {
1380
-                    while (($i = array_shift($keys)) !== null) {
1381
-                        $out[] = call_user_func_array($callback, array($items[$i]) + $params);
1382
-                    }
1383
-                }
1384
-            }
1385
-
1386
-            return $out;
1387
-        } else {
1388
-            return $params[0];
1389
-        }
1390
-    }
1391
-
1392
-    /**
1393
-     * Reads a variable into the given data array.
1394
-     *
1395
-     * @param string $varstr   the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1396
-     * @param mixed  $data     the data array or object to read from
1397
-     * @param bool   $safeRead if true, the function will check whether the index exists to prevent any notices from
1398
-     *                         being output
1399
-     *
1400
-     * @return mixed
1401
-     */
1402
-    public function readVarInto($varstr, $data, $safeRead = false)
1403
-    {
1404
-        if ($data === null) {
1405
-            return null;
1406
-        }
1407
-
1408
-        if (is_array($varstr) === false) {
1409
-            preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1410
-        } else {
1411
-            $m = $varstr;
1412
-        }
1413
-        unset($varstr);
1414
-
1415
-        foreach ($m[1] as $k => $sep) {
1416
-            if ($sep === '.' || $sep === '[' || $sep === '') {
1417
-                // strip enclosing quotes if present
1418
-                $m[2][$k] = preg_replace('#^(["\']?)(.*?)\1$#', '$2', $m[2][$k]);
1419
-
1420
-                if ((is_array($data) || $data instanceof ArrayAccess) && ($safeRead === false || isset($data[$m[2][$k]]))) {
1421
-                    $data = $data[$m[2][$k]];
1422
-                } else {
1423
-                    return null;
1424
-                }
1425
-            } else {
1426
-                if (is_object($data) && ($safeRead === false || isset($data->{$m[2][$k]}))) {
1427
-                    $data = $data->{$m[2][$k]};
1428
-                } else {
1429
-                    return null;
1430
-                }
1431
-            }
1432
-        }
1433
-
1434
-        return $data;
1435
-    }
1436
-
1437
-    /**
1438
-     * Reads a variable into the parent scope.
1439
-     *
1440
-     * @param int    $parentLevels the amount of parent levels to go from the current scope
1441
-     * @param string $varstr       the variable string, using dwoo variable syntax (i.e.
1442
-     *                             "var.subvar[subsubvar]->property")
1443
-     *
1444
-     * @return mixed
1445
-     */
1446
-    public function readParentVar($parentLevels, $varstr = null)
1447
-    {
1448
-        $tree = $this->scopeTree;
1449
-        $cur  = $this->data;
1450
-
1451
-        while ($parentLevels -- !== 0) {
1452
-            array_pop($tree);
1453
-        }
1454
-
1455
-        while (($i = array_shift($tree)) !== null) {
1456
-            if (is_object($cur)) {
1457
-                $cur = $cur->{$i};
1458
-            } else {
1459
-                $cur = $cur[$i];
1460
-            }
1461
-        }
1462
-
1463
-        if ($varstr !== null) {
1464
-            return $this->readVarInto($varstr, $cur);
1465
-        } else {
1466
-            return $cur;
1467
-        }
1468
-    }
1469
-
1470
-    /**
1471
-     * Reads a variable into the current scope.
1472
-     *
1473
-     * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1474
-     *
1475
-     * @return mixed
1476
-     */
1477
-    public function readVar($varstr)
1478
-    {
1479
-        if (is_array($varstr) === true) {
1480
-            $m = $varstr;
1481
-            unset($varstr);
1482
-        } else {
1483
-            if (strstr($varstr, '.') === false && strstr($varstr, '[') === false && strstr($varstr, '->') === false) {
1484
-                if ($varstr === 'dwoo') {
1485
-                    return $this->getGlobals();
1486
-                } elseif ($varstr === '__' || $varstr === '_root') {
1487
-                    return $this->data;
1488
-                } elseif ($varstr === '_' || $varstr === '_parent') {
1489
-                    $varstr = '.' . $varstr;
1490
-                    $tree   = $this->scopeTree;
1491
-                    $cur    = $this->data;
1492
-                    array_pop($tree);
1493
-
1494
-                    while (($i = array_shift($tree)) !== null) {
1495
-                        if (is_object($cur)) {
1496
-                            $cur = $cur->{$i};
1497
-                        } else {
1498
-                            $cur = $cur[$i];
1499
-                        }
1500
-                    }
1501
-
1502
-                    return $cur;
1503
-                }
1504
-
1505
-                $cur = $this->scope;
1506
-
1507
-                if (isset($cur[$varstr])) {
1508
-                    return $cur[$varstr];
1509
-                } else {
1510
-                    return null;
1511
-                }
1512
-            }
1513
-
1514
-            if (substr($varstr, 0, 1) === '.') {
1515
-                $varstr = 'dwoo' . $varstr;
1516
-            }
1517
-
1518
-            preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1519
-        }
1520
-
1521
-        $i = $m[2][0];
1522
-        if ($i === 'dwoo') {
1523
-            $cur = $this->getGlobals();
1524
-            array_shift($m[2]);
1525
-            array_shift($m[1]);
1526
-            switch ($m[2][0]) {
1527
-            case 'get':
1528
-                $cur = $_GET;
1529
-                break;
1530
-            case 'post':
1531
-                $cur = $_POST;
1532
-                break;
1533
-            case 'session':
1534
-                $cur = $_SESSION;
1535
-                break;
1536
-            case 'cookies':
1537
-            case 'cookie':
1538
-                $cur = $_COOKIE;
1539
-                break;
1540
-            case 'server':
1541
-                $cur = $_SERVER;
1542
-                break;
1543
-            case 'env':
1544
-                $cur = $_ENV;
1545
-                break;
1546
-            case 'request':
1547
-                $cur = $_REQUEST;
1548
-                break;
1549
-            case 'const':
1550
-                array_shift($m[2]);
1551
-                if (defined($m[2][0])) {
1552
-                    return constant($m[2][0]);
1553
-                } else {
1554
-                    return null;
1555
-                }
1556
-            }
1557
-            if ($cur !== $this->getGlobals()) {
1558
-                array_shift($m[2]);
1559
-                array_shift($m[1]);
1560
-            }
1561
-        } elseif ($i === '__' || $i === '_root') {
1562
-            $cur = $this->data;
1563
-            array_shift($m[2]);
1564
-            array_shift($m[1]);
1565
-        } elseif ($i === '_' || $i === '_parent') {
1566
-            $tree = $this->scopeTree;
1567
-            $cur  = $this->data;
1568
-
1569
-            while (true) {
1570
-                array_pop($tree);
1571
-                array_shift($m[2]);
1572
-                array_shift($m[1]);
1573
-                if (current($m[2]) === '_' || current($m[2]) === '_parent') {
1574
-                    continue;
1575
-                }
1576
-
1577
-                while (($i = array_shift($tree)) !== null) {
1578
-                    if (is_object($cur)) {
1579
-                        $cur = $cur->{$i};
1580
-                    } else {
1581
-                        $cur = $cur[$i];
1582
-                    }
1583
-                }
1584
-                break;
1585
-            }
1586
-        } else {
1587
-            $cur = $this->scope;
1588
-        }
1589
-
1590
-        foreach ($m[1] as $k => $sep) {
1591
-            if ($sep === '.' || $sep === '[' || $sep === '') {
1592
-                if ((is_array($cur) || $cur instanceof ArrayAccess) && isset($cur[$m[2][$k]])) {
1593
-                    $cur = $cur[$m[2][$k]];
1594
-                } else {
1595
-                    return null;
1596
-                }
1597
-            } elseif ($sep === '->') {
1598
-                if (is_object($cur)) {
1599
-                    $cur = $cur->{$m[2][$k]};
1600
-                } else {
1601
-                    return null;
1602
-                }
1603
-            } else {
1604
-                return null;
1605
-            }
1606
-        }
1607
-
1608
-        return $cur;
1609
-    }
1610
-
1611
-    /**
1612
-     * Assign the value to the given variable.
1613
-     *
1614
-     * @param mixed  $value the value to assign
1615
-     * @param string $scope the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1616
-     *
1617
-     * @return bool true if assigned correctly or false if a problem occured while parsing the var string
1618
-     */
1619
-    public function assignInScope($value, $scope)
1620
-    {
1621
-        if (!is_string($scope)) {
1622
-            $this->triggerError('Assignments must be done into strings, (' . gettype($scope) . ') ' . var_export($scope, true) . ' given', E_USER_ERROR);
1623
-        }
1624
-        if (strstr($scope, '.') === false && strstr($scope, '->') === false) {
1625
-            $this->scope[$scope] = $value;
1626
-        } else {
1627
-            // TODO handle _root/_parent scopes ?
1628
-            preg_match_all('#(\[|->|\.)?([^.[\]-]+)\]?#i', $scope, $m);
1629
-
1630
-            $cur  = &$this->scope;
1631
-            $last = array(
1632
-                array_pop($m[1]),
1633
-                array_pop($m[2])
1634
-            );
1635
-
1636
-            foreach ($m[1] as $k => $sep) {
1637
-                if ($sep === '.' || $sep === '[' || $sep === '') {
1638
-                    if (is_array($cur) === false) {
1639
-                        $cur = array();
1640
-                    }
1641
-                    $cur = &$cur[$m[2][$k]];
1642
-                } elseif ($sep === '->') {
1643
-                    if (is_object($cur) === false) {
1644
-                        $cur = new stdClass();
1645
-                    }
1646
-                    $cur = &$cur->{$m[2][$k]};
1647
-                } else {
1648
-                    return false;
1649
-                }
1650
-            }
1651
-
1652
-            if ($last[0] === '.' || $last[0] === '[' || $last[0] === '') {
1653
-                if (is_array($cur) === false) {
1654
-                    $cur = array();
1655
-                }
1656
-                $cur[$last[1]] = $value;
1657
-            } elseif ($last[0] === '->') {
1658
-                if (is_object($cur) === false) {
1659
-                    $cur = new stdClass();
1660
-                }
1661
-                $cur->{$last[1]} = $value;
1662
-            } else {
1663
-                return false;
1664
-            }
1665
-        }
1666
-    }
1667
-
1668
-    /**
1669
-     * Sets the scope to the given scope string or array.
1670
-     *
1671
-     * @param mixed $scope    a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1672
-     * @param bool  $absolute if true, the scope is set from the top level scope and not from the current scope
1673
-     *
1674
-     * @return array the current scope tree
1675
-     */
1676
-    public function setScope($scope, $absolute = false)
1677
-    {
1678
-        $old = $this->scopeTree;
1679
-
1680
-        if (is_string($scope) === true) {
1681
-            $scope = explode('.', $scope);
1682
-        }
1683
-
1684
-        if ($absolute === true) {
1685
-            $this->scope     = &$this->data;
1686
-            $this->scopeTree = array();
1687
-        }
1688
-
1689
-        while (($bit = array_shift($scope)) !== null) {
1690
-            if ($bit === '_' || $bit === '_parent') {
1691
-                array_pop($this->scopeTree);
1692
-                $this->scope = &$this->data;
1693
-                $cnt         = count($this->scopeTree);
1694
-                for ($i = 0; $i < $cnt; ++ $i) {
1695
-                    $this->scope = &$this->scope[$this->scopeTree[$i]];
1696
-                }
1697
-            } elseif ($bit === '__' || $bit === '_root') {
1698
-                $this->scope     = &$this->data;
1699
-                $this->scopeTree = array();
1700
-            } elseif (isset($this->scope[$bit])) {
1701
-                if ($this->scope instanceof ArrayAccess) {
1702
-                    $tmp         = $this->scope[$bit];
1703
-                    $this->scope = &$tmp;
1704
-                } else {
1705
-                    $this->scope = &$this->scope[$bit];
1706
-                }
1707
-                $this->scopeTree[] = $bit;
1708
-            } else {
1709
-                unset($this->scope);
1710
-                $this->scope = null;
1711
-            }
1712
-        }
1713
-
1714
-        return $old;
1715
-    }
1716
-
1717
-    /**
1718
-     * Returns the entire data array.
1719
-     *
1720
-     * @return array
1721
-     */
1722
-    public function getData()
1723
-    {
1724
-        return $this->data;
1725
-    }
1726
-
1727
-    /**
1728
-     * Sets a return value for the currently running template.
1729
-     *
1730
-     * @param string $name  var name
1731
-     * @param mixed  $value var value
1732
-     *
1733
-     * @return void
1734
-     */
1735
-    public function setReturnValue($name, $value)
1736
-    {
1737
-        $this->returnData[$name] = $value;
1738
-    }
1739
-
1740
-    /**
1741
-     * Retrieves the return values set by the template.
1742
-     *
1743
-     * @return array
1744
-     */
1745
-    public function getReturnValues()
1746
-    {
1747
-        return $this->returnData;
1748
-    }
1749
-
1750
-    /**
1751
-     * Returns a reference to the current scope.
1752
-     *
1753
-     * @return mixed
1754
-     */
1755
-    public function &getScope()
1756
-    {
1757
-        return $this->scope;
1758
-    }
1759
-
1760
-    /**
1761
-     * Redirects all calls to unexisting to plugin proxy.
1762
-     *
1763
-     * @param string $method the method name
1764
-     * @param array  $args   array of arguments
1765
-     *
1766
-     * @return mixed
1767
-     * @throws Exception
1768
-     */
1769
-    public function __call($method, $args)
1770
-    {
1771
-        $proxy = $this->getPluginProxy();
1772
-        if (!$proxy) {
1773
-            throw new Exception('Call to undefined method ' . __CLASS__ . '::' . $method . '()');
1774
-        }
1775
-
1776
-        return call_user_func_array($proxy->getCallback($method), $args);
1777
-    }
1778
-
1779
-    /**
1780
-     * Convert plugin name from `auto_escape` to `AutoEscape`.
1781
-     * @param string $input
1782
-     * @param string $separator
1783
-     *
1784
-     * @return mixed
1785
-     */
1786
-    public static function toCamelCase($input, $separator = '_')
1787
-    {
1788
-        return join(array_map('ucfirst', explode($separator, $input)));
1789
-
1790
-        // TODO >= PHP5.4.32
1791
-        //return str_replace($separator, '', ucwords($input, $separator));
1792
-    }
617
+				);
618
+			}
619
+
620
+			$this->filters[] = $callback;
621
+		} else {
622
+			$this->filters[] = $callback;
623
+		}
624
+	}
625
+
626
+	/**
627
+	 * Removes a filter.
628
+	 *
629
+	 * @param mixed $callback callback or filter name if it was autoloaded
630
+	 *
631
+	 * @return void
632
+	 */
633
+	public function removeFilter($callback)
634
+	{
635
+		if (($index = array_search(self::NAMESPACE_PLUGINS_FILTERS. 'Filter' . self::toCamelCase($callback), $this->filters,
636
+				true)) !==
637
+			false) {
638
+			unset($this->filters[$index]);
639
+		} elseif (($index = array_search($callback, $this->filters, true)) !== false) {
640
+			unset($this->filters[$index]);
641
+		} else {
642
+			$class = self::NAMESPACE_PLUGINS_FILTERS . 'Filter' . $callback;
643
+			foreach ($this->filters as $index => $filter) {
644
+				if (is_array($filter) && $filter[0] instanceof $class) {
645
+					unset($this->filters[$index]);
646
+					break;
647
+				}
648
+			}
649
+		}
650
+	}
651
+
652
+	/**
653
+	 * Adds a resource or overrides a default one.
654
+	 *
655
+	 * @param string   $name            the resource name
656
+	 * @param string   $class           the resource class (which must implement ITemplate)
657
+	 * @param callback $compilerFactory the compiler factory callback, a function that must return a compiler instance
658
+	 *                                  used to compile this resource, if none is provided. by default it will produce
659
+	 *                                  a Compiler object
660
+	 *
661
+	 * @return void
662
+	 * @throws Exception
663
+	 */
664
+	public function addResource($name, $class, $compilerFactory = null)
665
+	{
666
+		if (strlen($name) < 2) {
667
+			throw new Exception('Resource names must be at least two-character long to avoid conflicts with Windows paths');
668
+		}
669
+
670
+		if (!class_exists($class)) {
671
+			throw new Exception(sprintf('Resource class %s does not exist', $class));
672
+		}
673
+
674
+		$interfaces = class_implements($class);
675
+		if (in_array('Dwoo\ITemplate', $interfaces) === false) {
676
+			throw new Exception('Resource class must implement ITemplate');
677
+		}
678
+
679
+		$this->resources[$name] = array(
680
+			'class'    => $class,
681
+			'compiler' => $compilerFactory
682
+		);
683
+	}
684
+
685
+	/**
686
+	 * Removes a custom resource.
687
+	 *
688
+	 * @param string $name the resource name
689
+	 *
690
+	 * @return void
691
+	 */
692
+	public function removeResource($name)
693
+	{
694
+		unset($this->resources[$name]);
695
+		if ($name === 'file') {
696
+			$this->resources['file'] = array(
697
+				'class'    => 'Dwoo\Template\File',
698
+				'compiler' => null
699
+			);
700
+		}
701
+	}
702
+
703
+	/**
704
+	 * Sets the loader object to use to load plugins.
705
+	 *
706
+	 * @param ILoader $loader loader
707
+	 *
708
+	 * @return void
709
+	 */
710
+	public function setLoader(ILoader $loader)
711
+	{
712
+		$this->loader = $loader;
713
+	}
714
+
715
+	/**
716
+	 * Returns the current loader object or a default one if none is currently found.
717
+	 *
718
+	 * @return ILoader|Loader
719
+	 */
720
+	public function getLoader()
721
+	{
722
+		if ($this->loader === null) {
723
+			$this->loader = new Loader($this->getCompileDir());
724
+		}
725
+
726
+		return $this->loader;
727
+	}
728
+
729
+	/**
730
+	 * Returns the custom plugins loaded.
731
+	 * Used by the ITemplate classes to pass the custom plugins to their ICompiler instance.
732
+	 *
733
+	 * @return array
734
+	 */
735
+	public function getCustomPlugins()
736
+	{
737
+		return $this->plugins;
738
+	}
739
+
740
+	/**
741
+	 * Return a specified custom plugin loaded by his name.
742
+	 * Used by the compiler, for executing a Closure.
743
+	 *
744
+	 * @param string $name
745
+	 *
746
+	 * @return mixed|null
747
+	 */
748
+	public function getCustomPlugin($name)
749
+	{
750
+		if (isset($this->plugins[$name])) {
751
+			return $this->plugins[$name]['callback'];
752
+		}
753
+
754
+		return null;
755
+	}
756
+
757
+	/**
758
+	 * Returns the cache directory with a trailing DIRECTORY_SEPARATOR.
759
+	 *
760
+	 * @return string
761
+	 */
762
+	public function getCacheDir()
763
+	{
764
+		if ($this->cacheDir === null) {
765
+			$this->setCacheDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR);
766
+		}
767
+
768
+		return $this->cacheDir;
769
+	}
770
+
771
+	/**
772
+	 * Sets the cache directory and automatically appends a DIRECTORY_SEPARATOR.
773
+	 *
774
+	 * @param string $dir the cache directory
775
+	 *
776
+	 * @return void
777
+	 * @throws Exception
778
+	 */
779
+	public function setCacheDir($dir)
780
+	{
781
+		$this->cacheDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
782
+		if (is_writable($this->cacheDir) === false) {
783
+			throw new Exception('The cache directory must be writable, chmod "' . $this->cacheDir . '" to make it writable');
784
+		}
785
+	}
786
+
787
+	/**
788
+	 * Returns the compile directory with a trailing DIRECTORY_SEPARATOR.
789
+	 *
790
+	 * @return string
791
+	 */
792
+	public function getCompileDir()
793
+	{
794
+		if ($this->compileDir === null) {
795
+			$this->setCompileDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'compiled' . DIRECTORY_SEPARATOR);
796
+		}
797
+
798
+		return $this->compileDir;
799
+	}
800
+
801
+	/**
802
+	 * Sets the compile directory and automatically appends a DIRECTORY_SEPARATOR.
803
+	 *
804
+	 * @param string $dir the compile directory
805
+	 *
806
+	 * @return void
807
+	 * @throws Exception
808
+	 */
809
+	public function setCompileDir($dir)
810
+	{
811
+		$this->compileDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
812
+		if (is_writable($this->compileDir) === false) {
813
+			throw new Exception('The compile directory must be writable, chmod "' . $this->compileDir . '" to make it writable');
814
+		}
815
+	}
816
+
817
+	/**
818
+	 * Returns an array of the template directory with a trailing DIRECTORY_SEPARATOR
819
+	 *
820
+	 * @return array
821
+	 */
822
+	public function getTemplateDir()
823
+	{
824
+		return $this->templateDir;
825
+	}
826
+
827
+	/**
828
+	 * sets the template directory and automatically appends a DIRECTORY_SEPARATOR
829
+	 * template directory is stored in an array
830
+	 *
831
+	 * @param string $dir
832
+	 *
833
+	 * @throws Exception
834
+	 */
835
+	public function setTemplateDir($dir)
836
+	{
837
+		$tmpDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
838
+		if (is_dir($tmpDir) === false) {
839
+			throw new Exception('The template directory: "' . $tmpDir . '" does not exists, create the directory or specify an other location !');
840
+		}
841
+		$this->templateDir[] = $tmpDir;
842
+	}
843
+
844
+	/**
845
+	 * Returns the default cache time that is used with templates that do not have a cache time set.
846
+	 *
847
+	 * @return int the duration in seconds
848
+	 */
849
+	public function getCacheTime()
850
+	{
851
+		return $this->cacheTime;
852
+	}
853
+
854
+	/**
855
+	 * Sets the default cache time to use with templates that do not have a cache time set.
856
+	 *
857
+	 * @param int $seconds the duration in seconds
858
+	 *
859
+	 * @return void
860
+	 */
861
+	public function setCacheTime($seconds)
862
+	{
863
+		$this->cacheTime = (int)$seconds;
864
+	}
865
+
866
+	/**
867
+	 * Returns the character set used by the string manipulation plugins.
868
+	 * the charset is automatically lowercased
869
+	 *
870
+	 * @return string
871
+	 */
872
+	public function getCharset()
873
+	{
874
+		return $this->charset;
875
+	}
876
+
877
+	/**
878
+	 * Sets the character set used by the string manipulation plugins.
879
+	 * the charset will be automatically lowercased
880
+	 *
881
+	 * @param string $charset the character set
882
+	 *
883
+	 * @return void
884
+	 */
885
+	public function setCharset($charset)
886
+	{
887
+		$this->charset = strtolower((string)$charset);
888
+	}
889
+
890
+	/**
891
+	 * Returns the current template being rendered, when applicable, or null.
892
+	 *
893
+	 * @return ITemplate|null
894
+	 */
895
+	public function getTemplate()
896
+	{
897
+		return $this->template;
898
+	}
899
+
900
+	/**
901
+	 * Sets the current template being rendered.
902
+	 *
903
+	 * @param ITemplate $tpl template object
904
+	 *
905
+	 * @return void
906
+	 */
907
+	public function setTemplate(ITemplate $tpl)
908
+	{
909
+		$this->template = $tpl;
910
+	}
911
+
912
+	/**
913
+	 * Sets the default compiler factory function for the given resource name.
914
+	 * a compiler factory must return a ICompiler object pre-configured to fit your needs
915
+	 *
916
+	 * @param string   $resourceName    the resource name (i.e. file, string)
917
+	 * @param callback $compilerFactory the compiler factory callback
918
+	 *
919
+	 * @return void
920
+	 */
921
+	public function setDefaultCompilerFactory($resourceName, $compilerFactory)
922
+	{
923
+		$this->resources[$resourceName]['compiler'] = $compilerFactory;
924
+	}
925
+
926
+	/**
927
+	 * Returns the default compiler factory function for the given resource name.
928
+	 *
929
+	 * @param string $resourceName the resource name
930
+	 *
931
+	 * @return callback the compiler factory callback
932
+	 */
933
+	public function getDefaultCompilerFactory($resourceName)
934
+	{
935
+		return $this->resources[$resourceName]['compiler'];
936
+	}
937
+
938
+	/**
939
+	 * Sets the security policy object to enforce some php security settings.
940
+	 * use this if untrusted persons can modify templates
941
+	 *
942
+	 * @param SecurityPolicy $policy the security policy object
943
+	 *
944
+	 * @return void
945
+	 */
946
+	public function setSecurityPolicy(SecurityPolicy $policy = null)
947
+	{
948
+		$this->securityPolicy = $policy;
949
+	}
950
+
951
+	/**
952
+	 * Returns the current security policy object or null by default.
953
+	 *
954
+	 * @return SecurityPolicy|null the security policy object if any
955
+	 */
956
+	public function getSecurityPolicy()
957
+	{
958
+		return $this->securityPolicy;
959
+	}
960
+
961
+	/**
962
+	 * Sets the object that must be used as a plugin proxy when plugin can't be found
963
+	 * by dwoo's loader.
964
+	 *
965
+	 * @param IPluginProxy $pluginProxy the proxy object
966
+	 *
967
+	 * @return void
968
+	 */
969
+	public function setPluginProxy(IPluginProxy $pluginProxy)
970
+	{
971
+		$this->pluginProxy = $pluginProxy;
972
+	}
973
+
974
+	/**
975
+	 * Returns the current plugin proxy object or null by default.
976
+	 *
977
+	 * @return IPluginProxy
978
+	 */
979
+	public function getPluginProxy()
980
+	{
981
+		return $this->pluginProxy;
982
+	}
983
+
984
+	/**
985
+	 * Checks whether the given template is cached or not.
986
+	 *
987
+	 * @param ITemplate $tpl the template object
988
+	 *
989
+	 * @return bool
990
+	 */
991
+	public function isCached(ITemplate $tpl)
992
+	{
993
+		return is_string($tpl->getCachedTemplate($this));
994
+	}
995
+
996
+	/**
997
+	 * Clear templates inside the compiled directory.
998
+	 *
999
+	 * @return int
1000
+	 */
1001
+	public function clearCompiled()
1002
+	{
1003
+		$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getCompileDir()), \RecursiveIteratorIterator::SELF_FIRST);
1004
+		$count    = 0;
1005
+		foreach ($iterator as $file) {
1006
+			if ($file->isFile()) {
1007
+				$count += unlink($file->__toString()) ? 1 : 0;
1008
+			}
1009
+		}
1010
+
1011
+		return $count;
1012
+	}
1013
+
1014
+	/**
1015
+	 * Clears the cached templates if they are older than the given time.
1016
+	 *
1017
+	 * @param int $olderThan minimum time (in seconds) required for a cached template to be cleared
1018
+	 *
1019
+	 * @return int the amount of templates cleared
1020
+	 */
1021
+	public function clearCache($olderThan = - 1)
1022
+	{
1023
+		$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getCacheDir()), \RecursiveIteratorIterator::SELF_FIRST);
1024
+		$expired  = time() - $olderThan;
1025
+		$count    = 0;
1026
+		foreach ($iterator as $file) {
1027
+			if ($file->isFile() && $file->getCTime() < $expired) {
1028
+				$count += unlink((string)$file) ? 1 : 0;
1029
+			}
1030
+		}
1031
+
1032
+		return $count;
1033
+	}
1034
+
1035
+	/**
1036
+	 * Fetches a template object of the given resource.
1037
+	 *
1038
+	 * @param string    $resourceName   the resource name (i.e. file, string)
1039
+	 * @param string    $resourceId     the resource identifier (i.e. file path)
1040
+	 * @param int       $cacheTime      the cache time setting for this resource
1041
+	 * @param string    $cacheId        the unique cache identifier
1042
+	 * @param string    $compileId      the unique compiler identifier
1043
+	 * @param ITemplate $parentTemplate the parent template
1044
+	 *
1045
+	 * @return ITemplate
1046
+	 * @throws Exception
1047
+	 */
1048
+	public function templateFactory($resourceName, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, ITemplate $parentTemplate = null)
1049
+	{
1050
+		if (isset($this->resources[$resourceName])) {
1051
+			/**
1052
+			 * Interface ITemplate
1053
+			 *
1054
+			 * @var ITemplate $class
1055
+			 */
1056
+			$class = $this->resources[$resourceName]['class'];
1057
+
1058
+			return $class::templateFactory($this, $resourceId, $cacheTime, $cacheId, $compileId, $parentTemplate);
1059
+		}
1060
+
1061
+		throw new Exception('Unknown resource type : ' . $resourceName);
1062
+	}
1063
+
1064
+	/**
1065
+	 * Checks if the input is an array or arrayaccess object, optionally it can also check if it's
1066
+	 * empty.
1067
+	 *
1068
+	 * @param mixed $value        the variable to check
1069
+	 * @param bool  $checkIsEmpty if true, the function will also check if the array|arrayaccess is empty,
1070
+	 *                            and return true only if it's not empty
1071
+	 *
1072
+	 * @return int|bool true if it's an array|arrayaccess (or the item count if $checkIsEmpty is true) or false if it's
1073
+	 *                  not an array|arrayaccess (or 0 if $checkIsEmpty is true)
1074
+	 */
1075
+	public function isArray($value, $checkIsEmpty = false)
1076
+	{
1077
+		if (is_array($value) === true || $value instanceof ArrayAccess) {
1078
+			if ($checkIsEmpty === false) {
1079
+				return true;
1080
+			}
1081
+
1082
+			return $this->count($value);
1083
+		}
1084
+
1085
+		return false;
1086
+	}
1087
+
1088
+	/**
1089
+	 * Checks if the input is an array or a traversable object, optionally it can also check if it's
1090
+	 * empty.
1091
+	 *
1092
+	 * @param mixed $value        the variable to check
1093
+	 * @param bool  $checkIsEmpty if true, the function will also check if the array|traversable is empty,
1094
+	 *                            and return true only if it's not empty
1095
+	 *
1096
+	 * @return int|bool true if it's an array|traversable (or the item count if $checkIsEmpty is true) or false if it's
1097
+	 *                  not an array|traversable (or 0 if $checkIsEmpty is true)
1098
+	 */
1099
+	public function isTraversable($value, $checkIsEmpty = false)
1100
+	{
1101
+		if (is_array($value) === true) {
1102
+			if ($checkIsEmpty === false) {
1103
+				return true;
1104
+			} else {
1105
+				return count($value) > 0;
1106
+			}
1107
+		} elseif ($value instanceof Traversable) {
1108
+			if ($checkIsEmpty === false) {
1109
+				return true;
1110
+			} else {
1111
+				return $this->count($value);
1112
+			}
1113
+		}
1114
+
1115
+		return false;
1116
+	}
1117
+
1118
+	/**
1119
+	 * Counts an array or arrayaccess/traversable object.
1120
+	 *
1121
+	 * @param mixed $value the value to count
1122
+	 *
1123
+	 * @return int|bool the count for arrays and objects that implement countable, true for other objects that don't,
1124
+	 *                  and 0 for empty elements
1125
+	 */
1126
+	public function count($value)
1127
+	{
1128
+		if (is_array($value) === true || $value instanceof Countable) {
1129
+			return count($value);
1130
+		} elseif ($value instanceof ArrayAccess) {
1131
+			if ($value->offsetExists(0)) {
1132
+				return true;
1133
+			}
1134
+		} elseif ($value instanceof Iterator) {
1135
+			$value->rewind();
1136
+			if ($value->valid()) {
1137
+				return true;
1138
+			}
1139
+		} elseif ($value instanceof Traversable) {
1140
+			foreach ($value as $dummy) {
1141
+				return true;
1142
+			}
1143
+		}
1144
+
1145
+		return 0;
1146
+	}
1147
+
1148
+	/**
1149
+	 * Triggers a dwoo error.
1150
+	 *
1151
+	 * @param string $message the error message
1152
+	 * @param int    $level   the error level, one of the PHP's E_* constants
1153
+	 *
1154
+	 * @return void
1155
+	 */
1156
+	public function triggerError($message, $level = E_USER_NOTICE)
1157
+	{
1158
+		if (!($tplIdentifier = $this->template->getResourceIdentifier())) {
1159
+			$tplIdentifier = $this->template->getResourceName();
1160
+		}
1161
+		trigger_error('Dwoo error (in ' . $tplIdentifier . ') : ' . $message, $level);
1162
+	}
1163
+
1164
+	/**
1165
+	 * Adds a block to the block stack.
1166
+	 *
1167
+	 * @param string $blockName the block name (without `Plugin` prefix)
1168
+	 * @param array  $args      the arguments to be passed to the block's init() function
1169
+	 *
1170
+	 * @return BlockPlugin the newly created block
1171
+	 */
1172
+	public function addStack($blockName, array $args = array())
1173
+	{
1174
+		if (isset($this->plugins[$blockName])) {
1175
+			$class = $this->plugins[$blockName]['class'];
1176
+		} else {
1177
+			$class = self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . self::toCamelCase($blockName);
1178
+		}
1179
+
1180
+		if ($this->curBlock !== null) {
1181
+			$this->curBlock->buffer(ob_get_contents());
1182
+			ob_clean();
1183
+		} else {
1184
+			$this->buffer .= ob_get_contents();
1185
+			ob_clean();
1186
+		}
1187
+
1188
+		$block = new $class($this);
1189
+
1190
+		call_user_func_array(array($block, 'init'), $args);
1191
+
1192
+		$this->stack[] = $this->curBlock = $block;
1193
+
1194
+		return $block;
1195
+	}
1196
+
1197
+	/**
1198
+	 * Removes the plugin at the top of the block stack.
1199
+	 * Calls the block buffer() function, followed by a call to end() and finally a call to process()
1200
+	 *
1201
+	 * @return void
1202
+	 */
1203
+	public function delStack()
1204
+	{
1205
+		$args = func_get_args();
1206
+
1207
+		$this->curBlock->buffer(ob_get_contents());
1208
+		ob_clean();
1209
+
1210
+		call_user_func_array(array($this->curBlock, 'end'), $args);
1211
+
1212
+		$tmp = array_pop($this->stack);
1213
+
1214
+		if (count($this->stack) > 0) {
1215
+			$this->curBlock = end($this->stack);
1216
+			$this->curBlock->buffer($tmp->process());
1217
+		} else {
1218
+			if ($this->buffer !== '') {
1219
+				echo $this->buffer;
1220
+				$this->buffer = '';
1221
+			}
1222
+			$this->curBlock = null;
1223
+			echo $tmp->process();
1224
+		}
1225
+
1226
+		unset($tmp);
1227
+	}
1228
+
1229
+	/**
1230
+	 * Returns the parent block of the given block.
1231
+	 *
1232
+	 * @param BlockPlugin $block the block class plugin
1233
+	 *
1234
+	 * @return BlockPlugin|false if the given block isn't in the stack
1235
+	 */
1236
+	public function getParentBlock(BlockPlugin $block)
1237
+	{
1238
+		$index = array_search($block, $this->stack, true);
1239
+		if ($index !== false && $index > 0) {
1240
+			return $this->stack[$index - 1];
1241
+		}
1242
+
1243
+		return false;
1244
+	}
1245
+
1246
+	/**
1247
+	 * Finds the closest block of the given type, starting at the top of the stack.
1248
+	 *
1249
+	 * @param string $type the type of plugin you want to find
1250
+	 *
1251
+	 * @return BlockPlugin|false if no plugin of such type is in the stack
1252
+	 */
1253
+	public function findBlock($type)
1254
+	{
1255
+		if (isset($this->plugins[$type])) {
1256
+			$type = $this->plugins[$type]['class'];
1257
+		} else {
1258
+			$type = self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin_' . str_replace(self::NAMESPACE_PLUGINS_BLOCKS.'Plugin',
1259
+					'', $type);
1260
+		}
1261
+
1262
+		$keys = array_keys($this->stack);
1263
+		while (($key = array_pop($keys)) !== false) {
1264
+			if ($this->stack[$key] instanceof $type) {
1265
+				return $this->stack[$key];
1266
+			}
1267
+		}
1268
+
1269
+		return false;
1270
+	}
1271
+
1272
+	/**
1273
+	 * Returns a Plugin of the given class.
1274
+	 * this is so a single instance of every class plugin is created at each template run,
1275
+	 * allowing class plugins to have "per-template-run" static variables
1276
+	 *
1277
+	 * @param string $class the class name
1278
+	 *
1279
+	 * @return mixed an object of the given class
1280
+	 */
1281
+	public function getObjectPlugin($class)
1282
+	{
1283
+		if (isset($this->runtimePlugins[$class])) {
1284
+			return $this->runtimePlugins[$class];
1285
+		}
1286
+
1287
+		return $this->runtimePlugins[$class] = new $class($this);
1288
+	}
1289
+
1290
+	/**
1291
+	 * Calls the process() method of the given class-plugin name.
1292
+	 *
1293
+	 * @param string $plugName the class plugin name (without `Plugin` prefix)
1294
+	 * @param array  $params   an array of parameters to send to the process() method
1295
+	 *
1296
+	 * @return string the process() return value
1297
+	 */
1298
+	public function classCall($plugName, array $params = array())
1299
+	{
1300
+		$class  = self::toCamelCase($plugName);
1301
+		$plugin = $this->getObjectPlugin($class);
1302
+
1303
+		return call_user_func_array(array($plugin, 'process'), $params);
1304
+	}
1305
+
1306
+	/**
1307
+	 * Calls a php function.
1308
+	 *
1309
+	 * @param string $callback the function to call
1310
+	 * @param array  $params   an array of parameters to send to the function
1311
+	 *
1312
+	 * @return mixed the return value of the called function
1313
+	 */
1314
+	public function arrayMap($callback, array $params)
1315
+	{
1316
+		if ($params[0] === $this) {
1317
+			$addThis = true;
1318
+			array_shift($params);
1319
+		}
1320
+		if ((is_array($params[0]) || ($params[0] instanceof Iterator && $params[0] instanceof ArrayAccess))) {
1321
+			if (empty($params[0])) {
1322
+				return $params[0];
1323
+			}
1324
+
1325
+			// array map
1326
+			$out = array();
1327
+			$cnt = count($params);
1328
+
1329
+			if (isset($addThis)) {
1330
+				array_unshift($params, $this);
1331
+				$items = $params[1];
1332
+				$keys  = array_keys($items);
1333
+
1334
+				if (is_string($callback) === false) {
1335
+					while (($i = array_shift($keys)) !== null) {
1336
+						$out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1337
+					}
1338
+				} elseif ($cnt === 1) {
1339
+					while (($i = array_shift($keys)) !== null) {
1340
+						$out[] = $callback($this, $items[$i]);
1341
+					}
1342
+				} elseif ($cnt === 2) {
1343
+					while (($i = array_shift($keys)) !== null) {
1344
+						$out[] = $callback($this, $items[$i], $params[2]);
1345
+					}
1346
+				} elseif ($cnt === 3) {
1347
+					while (($i = array_shift($keys)) !== null) {
1348
+						$out[] = $callback($this, $items[$i], $params[2], $params[3]);
1349
+					}
1350
+				} else {
1351
+					while (($i = array_shift($keys)) !== null) {
1352
+						$out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1353
+					}
1354
+				}
1355
+			} else {
1356
+				$items = $params[0];
1357
+				$keys  = array_keys($items);
1358
+
1359
+				if (is_string($callback) === false) {
1360
+					while (($i = array_shift($keys)) !== null) {
1361
+						$out[] = call_user_func_array($callback, array($items[$i]) + $params);
1362
+					}
1363
+				} elseif ($cnt === 1) {
1364
+					while (($i = array_shift($keys)) !== null) {
1365
+						$out[] = $callback($items[$i]);
1366
+					}
1367
+				} elseif ($cnt === 2) {
1368
+					while (($i = array_shift($keys)) !== null) {
1369
+						$out[] = $callback($items[$i], $params[1]);
1370
+					}
1371
+				} elseif ($cnt === 3) {
1372
+					while (($i = array_shift($keys)) !== null) {
1373
+						$out[] = $callback($items[$i], $params[1], $params[2]);
1374
+					}
1375
+				} elseif ($cnt === 4) {
1376
+					while (($i = array_shift($keys)) !== null) {
1377
+						$out[] = $callback($items[$i], $params[1], $params[2], $params[3]);
1378
+					}
1379
+				} else {
1380
+					while (($i = array_shift($keys)) !== null) {
1381
+						$out[] = call_user_func_array($callback, array($items[$i]) + $params);
1382
+					}
1383
+				}
1384
+			}
1385
+
1386
+			return $out;
1387
+		} else {
1388
+			return $params[0];
1389
+		}
1390
+	}
1391
+
1392
+	/**
1393
+	 * Reads a variable into the given data array.
1394
+	 *
1395
+	 * @param string $varstr   the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1396
+	 * @param mixed  $data     the data array or object to read from
1397
+	 * @param bool   $safeRead if true, the function will check whether the index exists to prevent any notices from
1398
+	 *                         being output
1399
+	 *
1400
+	 * @return mixed
1401
+	 */
1402
+	public function readVarInto($varstr, $data, $safeRead = false)
1403
+	{
1404
+		if ($data === null) {
1405
+			return null;
1406
+		}
1407
+
1408
+		if (is_array($varstr) === false) {
1409
+			preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1410
+		} else {
1411
+			$m = $varstr;
1412
+		}
1413
+		unset($varstr);
1414
+
1415
+		foreach ($m[1] as $k => $sep) {
1416
+			if ($sep === '.' || $sep === '[' || $sep === '') {
1417
+				// strip enclosing quotes if present
1418
+				$m[2][$k] = preg_replace('#^(["\']?)(.*?)\1$#', '$2', $m[2][$k]);
1419
+
1420
+				if ((is_array($data) || $data instanceof ArrayAccess) && ($safeRead === false || isset($data[$m[2][$k]]))) {
1421
+					$data = $data[$m[2][$k]];
1422
+				} else {
1423
+					return null;
1424
+				}
1425
+			} else {
1426
+				if (is_object($data) && ($safeRead === false || isset($data->{$m[2][$k]}))) {
1427
+					$data = $data->{$m[2][$k]};
1428
+				} else {
1429
+					return null;
1430
+				}
1431
+			}
1432
+		}
1433
+
1434
+		return $data;
1435
+	}
1436
+
1437
+	/**
1438
+	 * Reads a variable into the parent scope.
1439
+	 *
1440
+	 * @param int    $parentLevels the amount of parent levels to go from the current scope
1441
+	 * @param string $varstr       the variable string, using dwoo variable syntax (i.e.
1442
+	 *                             "var.subvar[subsubvar]->property")
1443
+	 *
1444
+	 * @return mixed
1445
+	 */
1446
+	public function readParentVar($parentLevels, $varstr = null)
1447
+	{
1448
+		$tree = $this->scopeTree;
1449
+		$cur  = $this->data;
1450
+
1451
+		while ($parentLevels -- !== 0) {
1452
+			array_pop($tree);
1453
+		}
1454
+
1455
+		while (($i = array_shift($tree)) !== null) {
1456
+			if (is_object($cur)) {
1457
+				$cur = $cur->{$i};
1458
+			} else {
1459
+				$cur = $cur[$i];
1460
+			}
1461
+		}
1462
+
1463
+		if ($varstr !== null) {
1464
+			return $this->readVarInto($varstr, $cur);
1465
+		} else {
1466
+			return $cur;
1467
+		}
1468
+	}
1469
+
1470
+	/**
1471
+	 * Reads a variable into the current scope.
1472
+	 *
1473
+	 * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1474
+	 *
1475
+	 * @return mixed
1476
+	 */
1477
+	public function readVar($varstr)
1478
+	{
1479
+		if (is_array($varstr) === true) {
1480
+			$m = $varstr;
1481
+			unset($varstr);
1482
+		} else {
1483
+			if (strstr($varstr, '.') === false && strstr($varstr, '[') === false && strstr($varstr, '->') === false) {
1484
+				if ($varstr === 'dwoo') {
1485
+					return $this->getGlobals();
1486
+				} elseif ($varstr === '__' || $varstr === '_root') {
1487
+					return $this->data;
1488
+				} elseif ($varstr === '_' || $varstr === '_parent') {
1489
+					$varstr = '.' . $varstr;
1490
+					$tree   = $this->scopeTree;
1491
+					$cur    = $this->data;
1492
+					array_pop($tree);
1493
+
1494
+					while (($i = array_shift($tree)) !== null) {
1495
+						if (is_object($cur)) {
1496
+							$cur = $cur->{$i};
1497
+						} else {
1498
+							$cur = $cur[$i];
1499
+						}
1500
+					}
1501
+
1502
+					return $cur;
1503
+				}
1504
+
1505
+				$cur = $this->scope;
1506
+
1507
+				if (isset($cur[$varstr])) {
1508
+					return $cur[$varstr];
1509
+				} else {
1510
+					return null;
1511
+				}
1512
+			}
1513
+
1514
+			if (substr($varstr, 0, 1) === '.') {
1515
+				$varstr = 'dwoo' . $varstr;
1516
+			}
1517
+
1518
+			preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1519
+		}
1520
+
1521
+		$i = $m[2][0];
1522
+		if ($i === 'dwoo') {
1523
+			$cur = $this->getGlobals();
1524
+			array_shift($m[2]);
1525
+			array_shift($m[1]);
1526
+			switch ($m[2][0]) {
1527
+			case 'get':
1528
+				$cur = $_GET;
1529
+				break;
1530
+			case 'post':
1531
+				$cur = $_POST;
1532
+				break;
1533
+			case 'session':
1534
+				$cur = $_SESSION;
1535
+				break;
1536
+			case 'cookies':
1537
+			case 'cookie':
1538
+				$cur = $_COOKIE;
1539
+				break;
1540
+			case 'server':
1541
+				$cur = $_SERVER;
1542
+				break;
1543
+			case 'env':
1544
+				$cur = $_ENV;
1545
+				break;
1546
+			case 'request':
1547
+				$cur = $_REQUEST;
1548
+				break;
1549
+			case 'const':
1550
+				array_shift($m[2]);
1551
+				if (defined($m[2][0])) {
1552
+					return constant($m[2][0]);
1553
+				} else {
1554
+					return null;
1555
+				}
1556
+			}
1557
+			if ($cur !== $this->getGlobals()) {
1558
+				array_shift($m[2]);
1559
+				array_shift($m[1]);
1560
+			}
1561
+		} elseif ($i === '__' || $i === '_root') {
1562
+			$cur = $this->data;
1563
+			array_shift($m[2]);
1564
+			array_shift($m[1]);
1565
+		} elseif ($i === '_' || $i === '_parent') {
1566
+			$tree = $this->scopeTree;
1567
+			$cur  = $this->data;
1568
+
1569
+			while (true) {
1570
+				array_pop($tree);
1571
+				array_shift($m[2]);
1572
+				array_shift($m[1]);
1573
+				if (current($m[2]) === '_' || current($m[2]) === '_parent') {
1574
+					continue;
1575
+				}
1576
+
1577
+				while (($i = array_shift($tree)) !== null) {
1578
+					if (is_object($cur)) {
1579
+						$cur = $cur->{$i};
1580
+					} else {
1581
+						$cur = $cur[$i];
1582
+					}
1583
+				}
1584
+				break;
1585
+			}
1586
+		} else {
1587
+			$cur = $this->scope;
1588
+		}
1589
+
1590
+		foreach ($m[1] as $k => $sep) {
1591
+			if ($sep === '.' || $sep === '[' || $sep === '') {
1592
+				if ((is_array($cur) || $cur instanceof ArrayAccess) && isset($cur[$m[2][$k]])) {
1593
+					$cur = $cur[$m[2][$k]];
1594
+				} else {
1595
+					return null;
1596
+				}
1597
+			} elseif ($sep === '->') {
1598
+				if (is_object($cur)) {
1599
+					$cur = $cur->{$m[2][$k]};
1600
+				} else {
1601
+					return null;
1602
+				}
1603
+			} else {
1604
+				return null;
1605
+			}
1606
+		}
1607
+
1608
+		return $cur;
1609
+	}
1610
+
1611
+	/**
1612
+	 * Assign the value to the given variable.
1613
+	 *
1614
+	 * @param mixed  $value the value to assign
1615
+	 * @param string $scope the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1616
+	 *
1617
+	 * @return bool true if assigned correctly or false if a problem occured while parsing the var string
1618
+	 */
1619
+	public function assignInScope($value, $scope)
1620
+	{
1621
+		if (!is_string($scope)) {
1622
+			$this->triggerError('Assignments must be done into strings, (' . gettype($scope) . ') ' . var_export($scope, true) . ' given', E_USER_ERROR);
1623
+		}
1624
+		if (strstr($scope, '.') === false && strstr($scope, '->') === false) {
1625
+			$this->scope[$scope] = $value;
1626
+		} else {
1627
+			// TODO handle _root/_parent scopes ?
1628
+			preg_match_all('#(\[|->|\.)?([^.[\]-]+)\]?#i', $scope, $m);
1629
+
1630
+			$cur  = &$this->scope;
1631
+			$last = array(
1632
+				array_pop($m[1]),
1633
+				array_pop($m[2])
1634
+			);
1635
+
1636
+			foreach ($m[1] as $k => $sep) {
1637
+				if ($sep === '.' || $sep === '[' || $sep === '') {
1638
+					if (is_array($cur) === false) {
1639
+						$cur = array();
1640
+					}
1641
+					$cur = &$cur[$m[2][$k]];
1642
+				} elseif ($sep === '->') {
1643
+					if (is_object($cur) === false) {
1644
+						$cur = new stdClass();
1645
+					}
1646
+					$cur = &$cur->{$m[2][$k]};
1647
+				} else {
1648
+					return false;
1649
+				}
1650
+			}
1651
+
1652
+			if ($last[0] === '.' || $last[0] === '[' || $last[0] === '') {
1653
+				if (is_array($cur) === false) {
1654
+					$cur = array();
1655
+				}
1656
+				$cur[$last[1]] = $value;
1657
+			} elseif ($last[0] === '->') {
1658
+				if (is_object($cur) === false) {
1659
+					$cur = new stdClass();
1660
+				}
1661
+				$cur->{$last[1]} = $value;
1662
+			} else {
1663
+				return false;
1664
+			}
1665
+		}
1666
+	}
1667
+
1668
+	/**
1669
+	 * Sets the scope to the given scope string or array.
1670
+	 *
1671
+	 * @param mixed $scope    a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1672
+	 * @param bool  $absolute if true, the scope is set from the top level scope and not from the current scope
1673
+	 *
1674
+	 * @return array the current scope tree
1675
+	 */
1676
+	public function setScope($scope, $absolute = false)
1677
+	{
1678
+		$old = $this->scopeTree;
1679
+
1680
+		if (is_string($scope) === true) {
1681
+			$scope = explode('.', $scope);
1682
+		}
1683
+
1684
+		if ($absolute === true) {
1685
+			$this->scope     = &$this->data;
1686
+			$this->scopeTree = array();
1687
+		}
1688
+
1689
+		while (($bit = array_shift($scope)) !== null) {
1690
+			if ($bit === '_' || $bit === '_parent') {
1691
+				array_pop($this->scopeTree);
1692
+				$this->scope = &$this->data;
1693
+				$cnt         = count($this->scopeTree);
1694
+				for ($i = 0; $i < $cnt; ++ $i) {
1695
+					$this->scope = &$this->scope[$this->scopeTree[$i]];
1696
+				}
1697
+			} elseif ($bit === '__' || $bit === '_root') {
1698
+				$this->scope     = &$this->data;
1699
+				$this->scopeTree = array();
1700
+			} elseif (isset($this->scope[$bit])) {
1701
+				if ($this->scope instanceof ArrayAccess) {
1702
+					$tmp         = $this->scope[$bit];
1703
+					$this->scope = &$tmp;
1704
+				} else {
1705
+					$this->scope = &$this->scope[$bit];
1706
+				}
1707
+				$this->scopeTree[] = $bit;
1708
+			} else {
1709
+				unset($this->scope);
1710
+				$this->scope = null;
1711
+			}
1712
+		}
1713
+
1714
+		return $old;
1715
+	}
1716
+
1717
+	/**
1718
+	 * Returns the entire data array.
1719
+	 *
1720
+	 * @return array
1721
+	 */
1722
+	public function getData()
1723
+	{
1724
+		return $this->data;
1725
+	}
1726
+
1727
+	/**
1728
+	 * Sets a return value for the currently running template.
1729
+	 *
1730
+	 * @param string $name  var name
1731
+	 * @param mixed  $value var value
1732
+	 *
1733
+	 * @return void
1734
+	 */
1735
+	public function setReturnValue($name, $value)
1736
+	{
1737
+		$this->returnData[$name] = $value;
1738
+	}
1739
+
1740
+	/**
1741
+	 * Retrieves the return values set by the template.
1742
+	 *
1743
+	 * @return array
1744
+	 */
1745
+	public function getReturnValues()
1746
+	{
1747
+		return $this->returnData;
1748
+	}
1749
+
1750
+	/**
1751
+	 * Returns a reference to the current scope.
1752
+	 *
1753
+	 * @return mixed
1754
+	 */
1755
+	public function &getScope()
1756
+	{
1757
+		return $this->scope;
1758
+	}
1759
+
1760
+	/**
1761
+	 * Redirects all calls to unexisting to plugin proxy.
1762
+	 *
1763
+	 * @param string $method the method name
1764
+	 * @param array  $args   array of arguments
1765
+	 *
1766
+	 * @return mixed
1767
+	 * @throws Exception
1768
+	 */
1769
+	public function __call($method, $args)
1770
+	{
1771
+		$proxy = $this->getPluginProxy();
1772
+		if (!$proxy) {
1773
+			throw new Exception('Call to undefined method ' . __CLASS__ . '::' . $method . '()');
1774
+		}
1775
+
1776
+		return call_user_func_array($proxy->getCallback($method), $args);
1777
+	}
1778
+
1779
+	/**
1780
+	 * Convert plugin name from `auto_escape` to `AutoEscape`.
1781
+	 * @param string $input
1782
+	 * @param string $separator
1783
+	 *
1784
+	 * @return mixed
1785
+	 */
1786
+	public static function toCamelCase($input, $separator = '_')
1787
+	{
1788
+		return join(array_map('ucfirst', explode($separator, $input)));
1789
+
1790
+		// TODO >= PHP5.4.32
1791
+		//return str_replace($separator, '', ucwords($input, $separator));
1792
+	}
1793 1793
 }
Please login to merge, or discard this patch.
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -589,8 +589,7 @@
 block discarded – undo
589 589
             if (!class_exists($class) && !function_exists($class)) {
590 590
                 try {
591 591
                     $this->getLoader()->loadPlugin($callback);
592
-                }
593
-                catch (Exception $e) {
592
+                } catch (Exception $e) {
594 593
                     if (strstr($callback, self::NAMESPACE_PLUGINS_FILTERS)) {
595 594
                         throw new Exception(
596 595
                             'Wrong filter name : ' . $callback . ', the "Filter" prefix should 
Please login to merge, or discard this patch.
lib/Dwoo/Compiler.php 3 patches
Indentation   +3630 added lines, -3630 removed lines patch added patch discarded remove patch
@@ -31,3636 +31,3636 @@
 block discarded – undo
31 31
  */
32 32
 class Compiler implements ICompiler
33 33
 {
34
-    /**
35
-     * Constant that represents a php opening tag.
36
-     * use it in case it needs to be adjusted
37
-     *
38
-     * @var string
39
-     */
40
-    const PHP_OPEN = '<?php ';
41
-
42
-    /**
43
-     * Constant that represents a php closing tag.
44
-     * use it in case it needs to be adjusted
45
-     *
46
-     * @var string
47
-     */
48
-    const PHP_CLOSE = '?>';
49
-
50
-    /**
51
-     * Boolean flag to enable or disable debugging output.
52
-     *
53
-     * @var bool
54
-     */
55
-    public $debug = false;
56
-
57
-    /**
58
-     * Left script delimiter.
59
-     *
60
-     * @var string
61
-     */
62
-    protected $ld = '{';
63
-
64
-    /**
65
-     * Left script delimiter with escaped regex meta characters.
66
-     *
67
-     * @var string
68
-     */
69
-    protected $ldr = '\\{';
70
-
71
-    /**
72
-     * Right script delimiter.
73
-     *
74
-     * @var string
75
-     */
76
-    protected $rd = '}';
77
-
78
-    /**
79
-     * Right script delimiter with escaped regex meta characters.
80
-     *
81
-     * @var string
82
-     */
83
-    protected $rdr = '\\}';
84
-
85
-    /**
86
-     * Defines whether the nested comments should be parsed as nested or not.
87
-     * defaults to false (classic block comment parsing as in all languages)
88
-     *
89
-     * @var bool
90
-     */
91
-    protected $allowNestedComments = false;
92
-
93
-    /**
94
-     * Defines whether opening and closing tags can contain spaces before valid data or not.
95
-     * turn to true if you want to be sloppy with the syntax, but when set to false it allows
96
-     * to skip javascript and css tags as long as they are in the form "{ something", which is
97
-     * nice. default is false.
98
-     *
99
-     * @var bool
100
-     */
101
-    protected $allowLooseOpenings = false;
102
-
103
-    /**
104
-     * Defines whether the compiler will automatically html-escape variables or not.
105
-     * default is false
106
-     *
107
-     * @var bool
108
-     */
109
-    protected $autoEscape = false;
110
-
111
-    /**
112
-     * Security policy object.
113
-     *
114
-     * @var SecurityPolicy
115
-     */
116
-    protected $securityPolicy;
117
-
118
-    /**
119
-     * Stores the custom plugins registered with this compiler.
120
-     *
121
-     * @var array
122
-     */
123
-    protected $customPlugins = array();
124
-
125
-    /**
126
-     * Stores the template plugins registered with this compiler.
127
-     *
128
-     * @var array
129
-     */
130
-    protected $templatePlugins = array();
131
-
132
-    /**
133
-     * Stores the pre- and post-processors callbacks.
134
-     *
135
-     * @var array
136
-     */
137
-    protected $processors = array('pre' => array(), 'post' => array());
138
-
139
-    /**
140
-     * Stores a list of plugins that are used in the currently compiled
141
-     * template, and that are not compilable. these plugins will be loaded
142
-     * during the template's runtime if required.
143
-     * it is a 1D array formatted as key:pluginName value:pluginType
144
-     *
145
-     * @var array
146
-     */
147
-    protected $usedPlugins;
148
-
149
-    /**
150
-     * Stores the template undergoing compilation.
151
-     *
152
-     * @var string
153
-     */
154
-    protected $template;
155
-
156
-    /**
157
-     * Stores the current pointer position inside the template.
158
-     *
159
-     * @var int
160
-     */
161
-    protected $pointer;
162
-
163
-    /**
164
-     * Stores the current line count inside the template for debugging purposes.
165
-     *
166
-     * @var int
167
-     */
168
-    protected $line;
169
-
170
-    /**
171
-     * Stores the current template source while compiling it.
172
-     *
173
-     * @var string
174
-     */
175
-    protected $templateSource;
176
-
177
-    /**
178
-     * Stores the data within which the scope moves.
179
-     *
180
-     * @var array
181
-     */
182
-    protected $data;
183
-
184
-    /**
185
-     * Variable scope of the compiler, set to null if
186
-     * it can not be resolved to a static string (i.e. if some
187
-     * plugin defines a new scope based on a variable array key).
188
-     *
189
-     * @var mixed
190
-     */
191
-    protected $scope;
192
-
193
-    /**
194
-     * Variable scope tree, that allows to rebuild the current
195
-     * scope if required, i.e. when going to a parent level.
196
-     *
197
-     * @var array
198
-     */
199
-    protected $scopeTree;
200
-
201
-    /**
202
-     * Block plugins stack, accessible through some methods.
203
-     *
204
-     * @see findBlock
205
-     * @see getCurrentBlock
206
-     * @see addBlock
207
-     * @see addCustomBlock
208
-     * @see injectBlock
209
-     * @see removeBlock
210
-     * @see removeTopBlock
211
-     * @var array
212
-     */
213
-    protected $stack = array();
214
-
215
-    /**
216
-     * Current block at the top of the block plugins stack,
217
-     * accessible through getCurrentBlock.
218
-     *
219
-     * @see getCurrentBlock
220
-     * @var array
221
-     */
222
-    protected $curBlock;
223
-
224
-    /**
225
-     * Current dwoo object that uses this compiler, or null.
226
-     *
227
-     * @var Core
228
-     */
229
-    public $dwoo;
230
-
231
-    /**
232
-     * Holds an instance of this class, used by getInstance when you don't
233
-     * provide a custom compiler in order to save resources.
234
-     *
235
-     * @var Compiler
236
-     */
237
-    protected static $instance;
238
-
239
-    /**
240
-     * Token types.
241
-     *
242
-     * @var int
243
-     */
244
-    const T_UNQUOTED_STRING = 1;
245
-    const T_NUMERIC         = 2;
246
-    const T_NULL            = 4;
247
-    const T_BOOL            = 8;
248
-    const T_MATH            = 16;
249
-    const T_BREAKCHAR       = 32;
250
-
251
-    /**
252
-     * Compiler constructor.
253
-     * saves the created instance so that child templates get the same one
254
-     */
255
-    public function __construct()
256
-    {
257
-        self::$instance = $this;
258
-    }
259
-
260
-    /**
261
-     * Sets the delimiters to use in the templates.
262
-     * delimiters can be multi-character strings but should not be one of those as they will
263
-     * make it very hard to work with templates or might even break the compiler entirely : "\", "$", "|", ":" and
264
-     * finally "#" only if you intend to use config-vars with the #var# syntax.
265
-     *
266
-     * @param string $left  left delimiter
267
-     * @param string $right right delimiter
268
-     */
269
-    public function setDelimiters($left, $right)
270
-    {
271
-        $this->ld  = $left;
272
-        $this->rd  = $right;
273
-        $this->ldr = preg_quote($left, '/');
274
-        $this->rdr = preg_quote($right, '/');
275
-    }
276
-
277
-    /**
278
-     * Returns the left and right template delimiters.
279
-     *
280
-     * @return array containing the left and the right delimiters
281
-     */
282
-    public function getDelimiters()
283
-    {
284
-        return array($this->ld, $this->rd);
285
-    }
286
-
287
-    /**
288
-     * Sets the way to handle nested comments, if set to true
289
-     * {* foo {* some other *} comment *} will be stripped correctly.
290
-     * if false it will remove {* foo {* some other *} and leave "comment *}" alone,
291
-     * this is the default behavior
292
-     *
293
-     * @param bool $allow allow nested comments or not, defaults to true (but the default internal value is false)
294
-     */
295
-    public function setNestedCommentsHandling($allow = true)
296
-    {
297
-        $this->allowNestedComments = (bool)$allow;
298
-    }
299
-
300
-    /**
301
-     * Returns the nested comments handling setting.
302
-     *
303
-     * @see    setNestedCommentsHandling
304
-     * @return bool true if nested comments are allowed
305
-     */
306
-    public function getNestedCommentsHandling()
307
-    {
308
-        return $this->allowNestedComments;
309
-    }
310
-
311
-    /**
312
-     * Sets the tag openings handling strictness, if set to true, template tags can
313
-     * contain spaces before the first function/string/variable such as { $foo} is valid.
314
-     * if set to false (default setting), { $foo} is invalid but that is however a good thing
315
-     * as it allows css (i.e. #foo { color:red; }) to be parsed silently without triggering
316
-     * an error, same goes for javascript.
317
-     *
318
-     * @param bool $allow true to allow loose handling, false to restore default setting
319
-     */
320
-    public function setLooseOpeningHandling($allow = false)
321
-    {
322
-        $this->allowLooseOpenings = (bool)$allow;
323
-    }
324
-
325
-    /**
326
-     * Returns the tag openings handling strictness setting.
327
-     *
328
-     * @see    setLooseOpeningHandling
329
-     * @return bool true if loose tags are allowed
330
-     */
331
-    public function getLooseOpeningHandling()
332
-    {
333
-        return $this->allowLooseOpenings;
334
-    }
335
-
336
-    /**
337
-     * Changes the auto escape setting.
338
-     * if enabled, the compiler will automatically html-escape variables,
339
-     * unless they are passed through the safe function such as {$var|safe}
340
-     * or {safe $var}
341
-     * default setting is disabled/false
342
-     *
343
-     * @param bool $enabled set to true to enable, false to disable
344
-     */
345
-    public function setAutoEscape($enabled)
346
-    {
347
-        $this->autoEscape = (bool)$enabled;
348
-    }
349
-
350
-    /**
351
-     * Returns the auto escape setting.
352
-     * default setting is disabled/false
353
-     *
354
-     * @return bool
355
-     */
356
-    public function getAutoEscape()
357
-    {
358
-        return $this->autoEscape;
359
-    }
360
-
361
-    /**
362
-     * Adds a preprocessor to the compiler, it will be called
363
-     * before the template is compiled.
364
-     *
365
-     * @param mixed $callback either a valid callback to the preprocessor or a simple name if the autoload is set to
366
-     *                        true
367
-     * @param bool  $autoload if set to true, the preprocessor is auto-loaded from one of the plugin directories, else
368
-     *                        you must provide a valid callback
369
-     */
370
-    public function addPreProcessor($callback, $autoload = false)
371
-    {
372
-        if ($autoload) {
373
-            $name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', Core::toCamelCase($callback));
374
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . $name;
375
-
376
-            if (class_exists($class)) {
377
-                $callback = array(new $class($this), 'process');
378
-            } elseif (function_exists($class)) {
379
-                $callback = $class;
380
-            } else {
381
-                $callback = array('autoload' => true, 'class' => $class, 'name' => $name);
382
-            }
383
-
384
-            $this->processors['pre'][] = $callback;
385
-        } else {
386
-            $this->processors['pre'][] = $callback;
387
-        }
388
-    }
389
-
390
-    /**
391
-     * Removes a preprocessor from the compiler.
392
-     *
393
-     * @param mixed $callback either a valid callback to the preprocessor or a simple name if it was autoloaded
394
-     */
395
-    public function removePreProcessor($callback)
396
-    {
397
-        if (($index = array_search($callback, $this->processors['pre'], true)) !== false) {
398
-            unset($this->processors['pre'][$index]);
399
-        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
400
-                    $callback),
401
-                $this->processors['pre'], true)) !== false) {
402
-            unset($this->processors['pre'][$index]);
403
-        } else {
404
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
405
-            foreach ($this->processors['pre'] as $index => $proc) {
406
-                if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
407
-                    unset($this->processors['pre'][$index]);
408
-                    break;
409
-                }
410
-            }
411
-        }
412
-    }
413
-
414
-    /**
415
-     * Adds a postprocessor to the compiler, it will be called
416
-     * before the template is compiled.
417
-     *
418
-     * @param mixed $callback either a valid callback to the postprocessor or a simple name if the autoload is set to
419
-     *                        true
420
-     * @param bool  $autoload if set to true, the postprocessor is auto-loaded from one of the plugin directories, else
421
-     *                        you must provide a valid callback
422
-     */
423
-    public function addPostProcessor($callback, $autoload = false)
424
-    {
425
-        if ($autoload) {
426
-            $name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
427
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . Core::toCamelCase($name);
428
-
429
-            if (class_exists($class)) {
430
-                $callback = array(new $class($this), 'process');
431
-            } elseif (function_exists($class)) {
432
-                $callback = $class;
433
-            } else {
434
-                $callback = array('autoload' => true, 'class' => $class, 'name' => $name);
435
-            }
436
-
437
-            $this->processors['post'][] = $callback;
438
-        } else {
439
-            $this->processors['post'][] = $callback;
440
-        }
441
-    }
442
-
443
-    /**
444
-     * Removes a postprocessor from the compiler.
445
-     *
446
-     * @param mixed $callback either a valid callback to the postprocessor or a simple name if it was autoloaded
447
-     */
448
-    public function removePostProcessor($callback)
449
-    {
450
-        if (($index = array_search($callback, $this->processors['post'], true)) !== false) {
451
-            unset($this->processors['post'][$index]);
452
-        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
453
-                    $callback),
454
-                $this->processors['post'], true)) !== false) {
455
-            unset($this->processors['post'][$index]);
456
-        } else {
457
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
458
-            foreach ($this->processors['post'] as $index => $proc) {
459
-                if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
460
-                    unset($this->processors['post'][$index]);
461
-                    break;
462
-                }
463
-            }
464
-        }
465
-    }
466
-
467
-    /**
468
-     * Internal function to autoload processors at runtime if required.
469
-     *
470
-     * @param string $class the class/function name
471
-     * @param string $name  the plugin name (without Dwoo_Plugin_ prefix)
472
-     *
473
-     * @return array|string
474
-     * @throws Exception
475
-     */
476
-    protected function loadProcessor($class, $name)
477
-    {
478
-        if (!class_exists($class) && !function_exists($class)) {
479
-            try {
480
-                $this->getDwoo()->getLoader()->loadPlugin($name);
481
-            }
482
-            catch (Exception $e) {
483
-                throw new Exception('Processor ' . $name . ' could not be found in your plugin directories, please ensure it is in a file named ' . $name . '.php in the plugin directory');
484
-            }
485
-        }
486
-
487
-        if (class_exists($class)) {
488
-            return array(new $class($this), 'process');
489
-        }
490
-
491
-        if (function_exists($class)) {
492
-            return $class;
493
-        }
494
-
495
-        throw new Exception('Wrong processor name, when using autoload the processor must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Processor_name"');
496
-    }
497
-
498
-    /**
499
-     * Adds an used plugin, this is reserved for use by the {template} plugin.
500
-     * this is required so that plugin loading bubbles up from loaded
501
-     * template files to the current one
502
-     *
503
-     * @private
504
-     *
505
-     * @param string $name function name
506
-     * @param int    $type plugin type (Core::*_PLUGIN)
507
-     */
508
-    public function addUsedPlugin($name, $type)
509
-    {
510
-        $this->usedPlugins[$name] = $type;
511
-    }
512
-
513
-    /**
514
-     * Returns all the plugins this template uses.
515
-     *
516
-     * @private
517
-     * @return  array the list of used plugins in the parsed template
518
-     */
519
-    public function getUsedPlugins()
520
-    {
521
-        return $this->usedPlugins;
522
-    }
523
-
524
-    /**
525
-     * Adds a template plugin, this is reserved for use by the {template} plugin.
526
-     * this is required because the template functions are not declared yet
527
-     * during compilation, so we must have a way of validating their argument
528
-     * signature without using the reflection api
529
-     *
530
-     * @private
531
-     *
532
-     * @param string $name   function name
533
-     * @param array  $params parameter array to help validate the function call
534
-     * @param string $uuid   unique id of the function
535
-     * @param string $body   function php code
536
-     */
537
-    public function addTemplatePlugin($name, array $params, $uuid, $body = null)
538
-    {
539
-        $this->templatePlugins[$name] = array('params' => $params, 'body' => $body, 'uuid' => $uuid);
540
-    }
541
-
542
-    /**
543
-     * Returns all the parsed sub-templates.
544
-     *
545
-     * @private
546
-     * @return  array the parsed sub-templates
547
-     */
548
-    public function getTemplatePlugins()
549
-    {
550
-        return $this->templatePlugins;
551
-    }
552
-
553
-    /**
554
-     * Marks a template plugin as being called, which means its source must be included in the compiled template.
555
-     *
556
-     * @param string $name function name
557
-     */
558
-    public function useTemplatePlugin($name)
559
-    {
560
-        $this->templatePlugins[$name]['called'] = true;
561
-    }
562
-
563
-    /**
564
-     * Adds the custom plugins loaded into Dwoo to the compiler so it can load them.
565
-     *
566
-     * @see Core::addPlugin
567
-     *
568
-     * @param array $customPlugins an array of custom plugins
569
-     */
570
-    public function setCustomPlugins(array $customPlugins)
571
-    {
572
-        $this->customPlugins = $customPlugins;
573
-    }
574
-
575
-    /**
576
-     * Sets the security policy object to enforce some php security settings.
577
-     * use this if untrusted persons can modify templates,
578
-     * set it on the Dwoo object as it will be passed onto the compiler automatically
579
-     *
580
-     * @param SecurityPolicy $policy the security policy object
581
-     */
582
-    public function setSecurityPolicy(SecurityPolicy $policy = null)
583
-    {
584
-        $this->securityPolicy = $policy;
585
-    }
586
-
587
-    /**
588
-     * Returns the current security policy object or null by default.
589
-     *
590
-     * @return SecurityPolicy|null the security policy object if any
591
-     */
592
-    public function getSecurityPolicy()
593
-    {
594
-        return $this->securityPolicy;
595
-    }
596
-
597
-    /**
598
-     * Sets the pointer position.
599
-     *
600
-     * @param int  $position the new pointer position
601
-     * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
602
-     */
603
-    public function setPointer($position, $isOffset = false)
604
-    {
605
-        if ($isOffset) {
606
-            $this->pointer += $position;
607
-        } else {
608
-            $this->pointer = $position;
609
-        }
610
-    }
611
-
612
-    /**
613
-     * Returns the current pointer position, only available during compilation of a template.
614
-     *
615
-     * @return int
616
-     */
617
-    public function getPointer()
618
-    {
619
-        return $this->pointer;
620
-    }
621
-
622
-    /**
623
-     * Sets the line number.
624
-     *
625
-     * @param int  $number   the new line number
626
-     * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
627
-     */
628
-    public function setLine($number, $isOffset = false)
629
-    {
630
-        if ($isOffset) {
631
-            $this->line += $number;
632
-        } else {
633
-            $this->line = $number;
634
-        }
635
-    }
636
-
637
-    /**
638
-     * Returns the current line number, only available during compilation of a template.
639
-     *
640
-     * @return int
641
-     */
642
-    public function getLine()
643
-    {
644
-        return $this->line;
645
-    }
646
-
647
-    /**
648
-     * Returns the dwoo object that initiated this template compilation, only available during compilation of a
649
-     * template.
650
-     *
651
-     * @return Core
652
-     */
653
-    public function getDwoo()
654
-    {
655
-        return $this->dwoo;
656
-    }
657
-
658
-    /**
659
-     * Overwrites the template that is being compiled.
660
-     *
661
-     * @param string $newSource   the template source that must replace the current one
662
-     * @param bool   $fromPointer if set to true, only the source from the current pointer position is replaced
663
-     *
664
-     * @return void
665
-     */
666
-    public function setTemplateSource($newSource, $fromPointer = false)
667
-    {
668
-        if ($fromPointer === true) {
669
-            $this->templateSource = substr($this->templateSource, 0, $this->pointer) . $newSource;
670
-        } else {
671
-            $this->templateSource = $newSource;
672
-        }
673
-    }
674
-
675
-    /**
676
-     * Returns the template that is being compiled.
677
-     *
678
-     * @param mixed $fromPointer if set to true, only the source from the current pointer
679
-     *                           position is returned, if a number is given it overrides the current pointer
680
-     *
681
-     * @return string the template or partial template
682
-     */
683
-    public function getTemplateSource($fromPointer = false)
684
-    {
685
-        if ($fromPointer === true) {
686
-            return substr($this->templateSource, $this->pointer);
687
-        } elseif (is_numeric($fromPointer)) {
688
-            return substr($this->templateSource, $fromPointer);
689
-        } else {
690
-            return $this->templateSource;
691
-        }
692
-    }
693
-
694
-    /**
695
-     * Resets the compilation pointer, effectively restarting the compilation process.
696
-     * this is useful if a plugin modifies the template source since it might need to be recompiled
697
-     */
698
-    public function recompile()
699
-    {
700
-        $this->setPointer(0);
701
-    }
702
-
703
-    /**
704
-     * Compiles the provided string down to php code.
705
-     *
706
-     * @param Core      $dwoo
707
-     * @param ITemplate $template the template to compile
708
-     *
709
-     * @return string a compiled php string
710
-     * @throws CompilationException
711
-     */
712
-    public function compile(Core $dwoo, ITemplate $template)
713
-    {
714
-        // init vars
715
-        //		$compiled = '';
716
-        $tpl                  = $template->getSource();
717
-        $ptr                  = 0;
718
-        $this->dwoo           = $dwoo;
719
-        $this->template       = $template;
720
-        $this->templateSource = &$tpl;
721
-        $this->pointer        = &$ptr;
722
-
723
-        while (true) {
724
-            // if pointer is at the beginning, reset everything, that allows a plugin to externally reset the compiler if everything must be reparsed
725
-            if ($ptr === 0) {
726
-                // resets variables
727
-                $this->usedPlugins     = array();
728
-                $this->data            = array();
729
-                $this->scope           = &$this->data;
730
-                $this->scopeTree       = array();
731
-                $this->stack           = array();
732
-                $this->line            = 1;
733
-                $this->templatePlugins = array();
734
-                // add top level block
735
-                $compiled                 = $this->addBlock('TopLevelBlock', array(), 0);
736
-                $this->stack[0]['buffer'] = '';
737
-
738
-                if ($this->debug) {
739
-                    echo "\n";
740
-                    echo 'COMPILER INIT' . "\n";
741
-                }
742
-
743
-                if ($this->debug) {
744
-                    echo 'PROCESSING PREPROCESSORS (' . count($this->processors['pre']) . ')' . "\n";
745
-                }
746
-
747
-                // runs preprocessors
748
-                foreach ($this->processors['pre'] as $preProc) {
749
-                    if (is_array($preProc) && isset($preProc['autoload'])) {
750
-                        $preProc = $this->loadProcessor($preProc['class'], $preProc['name']);
751
-                    }
752
-                    if (is_array($preProc) && $preProc[0] instanceof Processor) {
753
-                        $tpl = call_user_func($preProc, $tpl);
754
-                    } else {
755
-                        $tpl = call_user_func($preProc, $this, $tpl);
756
-                    }
757
-                }
758
-                unset($preProc);
759
-
760
-                // show template source if debug
761
-                if ($this->debug) {
762
-                    echo '<pre>'.print_r(htmlentities($tpl), true).'</pre>'."\n";
763
-                }
764
-
765
-                // strips php tags if required by the security policy
766
-                if ($this->securityPolicy !== null) {
767
-                    $search = array('{<\?php.*?\?>}');
768
-                    if (ini_get('short_open_tags')) {
769
-                        $search = array('{<\?.*?\?>}', '{<%.*?%>}');
770
-                    }
771
-                    switch ($this->securityPolicy->getPhpHandling()) {
772
-                        case SecurityPolicy::PHP_ALLOW:
773
-                            break;
774
-                        case SecurityPolicy::PHP_ENCODE:
775
-                            $tpl = preg_replace_callback($search, array($this, 'phpTagEncodingHelper'), $tpl);
776
-                            break;
777
-                        case SecurityPolicy::PHP_REMOVE:
778
-                            $tpl = preg_replace($search, '', $tpl);
779
-                    }
780
-                }
781
-            }
782
-
783
-            $pos = strpos($tpl, $this->ld, $ptr);
784
-
785
-            if ($pos === false) {
786
-                $this->push(substr($tpl, $ptr), 0);
787
-                break;
788
-            } elseif (substr($tpl, $pos - 1, 1) === '\\' && substr($tpl, $pos - 2, 1) !== '\\') {
789
-                $this->push(substr($tpl, $ptr, $pos - $ptr - 1) . $this->ld);
790
-                $ptr = $pos + strlen($this->ld);
791
-            } elseif (preg_match('/^' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . 'literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', substr($tpl, $pos), $litOpen)) {
792
-                if (!preg_match('/' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . '\/literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', $tpl, $litClose, PREG_OFFSET_CAPTURE, $pos)) {
793
-                    throw new CompilationException($this, 'The {literal} blocks must be closed explicitly with {/literal}');
794
-                }
795
-                $endpos = $litClose[0][1];
796
-                $this->push(substr($tpl, $ptr, $pos - $ptr) . substr($tpl, $pos + strlen($litOpen[0]), $endpos - $pos - strlen($litOpen[0])));
797
-                $ptr = $endpos + strlen($litClose[0][0]);
798
-            } else {
799
-                if (substr($tpl, $pos - 2, 1) === '\\' && substr($tpl, $pos - 1, 1) === '\\') {
800
-                    $this->push(substr($tpl, $ptr, $pos - $ptr - 1));
801
-                    $ptr = $pos;
802
-                }
803
-
804
-                $this->push(substr($tpl, $ptr, $pos - $ptr));
805
-                $ptr = $pos;
806
-
807
-                $pos += strlen($this->ld);
808
-                if ($this->allowLooseOpenings) {
809
-                    while (substr($tpl, $pos, 1) === ' ') {
810
-                        $pos += 1;
811
-                    }
812
-                } else {
813
-                    if (substr($tpl, $pos, 1) === ' ' || substr($tpl, $pos, 1) === "\r" || substr($tpl, $pos, 1) === "\n" || substr($tpl, $pos, 1) === "\t") {
814
-                        $ptr = $pos;
815
-                        $this->push($this->ld);
816
-                        continue;
817
-                    }
818
-                }
819
-
820
-                // check that there is an end tag present
821
-                if (strpos($tpl, $this->rd, $pos) === false) {
822
-                    throw new CompilationException($this, 'A template tag was not closed, started with "' . substr($tpl, $ptr, 30) . '"');
823
-                }
824
-
825
-                $ptr += strlen($this->ld);
826
-                $subptr = $ptr;
827
-
828
-                while (true) {
829
-                    $parsed = $this->parse($tpl, $subptr, null, false, 'root', $subptr);
830
-
831
-                    // reload loop if the compiler was reset
832
-                    if ($ptr === 0) {
833
-                        continue 2;
834
-                    }
835
-
836
-                    $len = $subptr - $ptr;
837
-                    $this->push($parsed, substr_count(substr($tpl, $ptr, $len), "\n"));
838
-                    $ptr += $len;
839
-
840
-                    if ($parsed === false) {
841
-                        break;
842
-                    }
843
-                }
844
-            }
845
-        }
846
-
847
-        $compiled .= $this->removeBlock('TopLevelBlock');
848
-
849
-        if ($this->debug) {
850
-            echo 'PROCESSING POSTPROCESSORS' . "\n";
851
-        }
852
-
853
-        foreach ($this->processors['post'] as $postProc) {
854
-            if (is_array($postProc) && isset($postProc['autoload'])) {
855
-                $postProc = $this->loadProcessor($postProc['class'], $postProc['name']);
856
-            }
857
-            if (is_array($postProc) && $postProc[0] instanceof Processor) {
858
-                $compiled = call_user_func($postProc, $compiled);
859
-            } else {
860
-                $compiled = call_user_func($postProc, $this, $compiled);
861
-            }
862
-        }
863
-        unset($postProc);
864
-
865
-        if ($this->debug) {
866
-            echo 'COMPILATION COMPLETE : MEM USAGE : ' . memory_get_usage() . "\n";
867
-        }
868
-
869
-        $output = "<?php\n/* template head */\n";
870
-
871
-        // build plugin preloader
872
-        foreach ($this->getUsedPlugins() as $plugin => $type) {
873
-            if ($type & Core::CUSTOM_PLUGIN) {
874
-                continue;
875
-            }
876
-
877
-            switch ($type) {
878
-                case Core::CLASS_PLUGIN:
879
-                case Core::CLASS_PLUGIN + Core::BLOCK_PLUGIN:
880
-                    if (class_exists('Plugin' . $plugin) !== false) {
881
-                        $output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
882
-                        "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
883
-                    } else {
884
-                        $output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_BLOCKS . "Plugin" . $plugin . "')===false)".
885
-                        "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
886
-                    }
887
-                    break;
888
-                case Core::CLASS_PLUGIN + Core::FUNC_PLUGIN:
889
-                    if (class_exists('Plugin' . $plugin) !== false) {
890
-                        $output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
891
-                            "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
892
-                    } else {
893
-                        $output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
894
-                            "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
895
-                    }
896
-                    break;
897
-                case Core::FUNC_PLUGIN:
898
-                    if (function_exists('Plugin' . $plugin) !== false) {
899
-                        $output .= "if (function_exists('" . "Plugin" . $plugin . "')===false)".
900
-                        "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
901
-                    } else {
902
-                        $output .= "if (function_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
903
-                        "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
904
-                    }
905
-                    break;
906
-                case Core::SMARTY_MODIFIER:
907
-                    $output .= "if (function_exists('smarty_modifier_$plugin')===false)".
908
-                    "\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
909
-                    break;
910
-                case Core::SMARTY_FUNCTION:
911
-                    $output .= "if (function_exists('smarty_function_$plugin')===false)".
912
-                    "\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
913
-                    break;
914
-                case Core::SMARTY_BLOCK:
915
-                    $output .= "if (function_exists('smarty_block_$plugin')===false)".
916
-                    "\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
917
-                    break;
918
-                case Core::PROXY_PLUGIN:
919
-                    $output .= $this->getDwoo()->getPluginProxy()->getLoader($plugin);
920
-                    break;
921
-                default:
922
-                    throw new CompilationException($this, 'Type error for ' . $plugin . ' with type' . $type);
923
-            }
924
-        }
925
-
926
-        foreach ($this->templatePlugins as $function => $attr) {
927
-            if (isset($attr['called']) && $attr['called'] === true && !isset($attr['checked'])) {
928
-                $this->resolveSubTemplateDependencies($function);
929
-            }
930
-        }
931
-        foreach ($this->templatePlugins as $function) {
932
-            if (isset($function['called']) && $function['called'] === true) {
933
-                $output .= $function['body'] . PHP_EOL;
934
-            }
935
-        }
936
-
937
-        $output .= $compiled . "\n?>";
938
-
939
-        $output = preg_replace('/(?<!;|\}|\*\/|\n|\{)(\s*' . preg_quote(self::PHP_CLOSE, '/') . preg_quote(self::PHP_OPEN, '/') . ')/', ";\n", $output);
940
-        $output = str_replace(self::PHP_CLOSE . self::PHP_OPEN, "\n", $output);
941
-
942
-        // handle <?xml tag at the beginning
943
-        $output = preg_replace('#(/\* template body \*/ \?>\s*)<\?xml#is', '$1<?php echo \'<?xml\'; ?>', $output);
944
-
945
-        // add another line break after PHP closing tags that have a line break following,
946
-        // as we do not know whether it's intended, and PHP will strip it otherwise
947
-        $output = preg_replace('/(?<!"|<\?xml)\s*\?>\n/', '$0' . "\n", $output);
948
-
949
-        if ($this->debug) {
950
-            echo '=============================================================================================' . "\n";
951
-            $lines = preg_split('{\r\n|\n|<br />}', $output);
952
-            array_shift($lines);
953
-            foreach ($lines as $i => $line) {
954
-                echo ($i + 1) . '. ' . $line . "\r\n";
955
-            }
956
-            echo '=============================================================================================' . "\n";
957
-        }
958
-
959
-        $this->template = $this->dwoo = null;
960
-        $tpl            = null;
961
-
962
-        return $output;
963
-    }
964
-
965
-    /**
966
-     * Checks what sub-templates are used in every sub-template so that we're sure they are all compiled.
967
-     *
968
-     * @param string $function the sub-template name
969
-     */
970
-    protected function resolveSubTemplateDependencies($function)
971
-    {
972
-        if ($this->debug) {
973
-            echo 'Compiler::' . __FUNCTION__ . "\n";
974
-        }
975
-
976
-        $body = $this->templatePlugins[$function]['body'];
977
-        foreach ($this->templatePlugins as $func => $attr) {
978
-            if ($func !== $function && !isset($attr['called']) && strpos($body, Core::NAMESPACE_PLUGINS_FUNCTIONS .
979
-            'Plugin' . Core::toCamelCase($func)) !== false) {
980
-                $this->templatePlugins[$func]['called'] = true;
981
-                $this->resolveSubTemplateDependencies($func);
982
-            }
983
-        }
984
-        $this->templatePlugins[$function]['checked'] = true;
985
-    }
986
-
987
-    /**
988
-     * Adds compiled content to the current block.
989
-     *
990
-     * @param string $content   the content to push
991
-     * @param int    $lineCount newlines count in content, optional
992
-     *
993
-     * @throws CompilationException
994
-     */
995
-    public function push($content, $lineCount = null)
996
-    {
997
-        if ($lineCount === null) {
998
-            $lineCount = substr_count($content, "\n");
999
-        }
1000
-
1001
-        if ($this->curBlock['buffer'] === null && count($this->stack) > 1) {
1002
-            // buffer is not initialized yet (the block has just been created)
1003
-            $this->stack[count($this->stack) - 2]['buffer'] .= (string)$content;
1004
-            $this->curBlock['buffer'] = '';
1005
-        } else {
1006
-            if (!isset($this->curBlock['buffer'])) {
1007
-                throw new CompilationException($this, 'The template has been closed too early, you probably have an extra block-closing tag somewhere');
1008
-            }
1009
-            // append current content to current block's buffer
1010
-            $this->curBlock['buffer'] .= (string)$content;
1011
-        }
1012
-        $this->line += $lineCount;
1013
-    }
1014
-
1015
-    /**
1016
-     * Sets the scope.
1017
-     * set to null if the scope becomes "unstable" (i.e. too variable or unknown) so that
1018
-     * variables are compiled in a more evaluative way than just $this->scope['key']
1019
-     *
1020
-     * @param mixed $scope    a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1021
-     * @param bool  $absolute if true, the scope is set from the top level scope and not from the current scope
1022
-     *
1023
-     * @return array the current scope tree
1024
-     */
1025
-    public function setScope($scope, $absolute = false)
1026
-    {
1027
-        $old = $this->scopeTree;
1028
-
1029
-        if ($scope === null) {
1030
-            unset($this->scope);
1031
-            $this->scope = null;
1032
-        }
1033
-
1034
-        if (is_array($scope) === false) {
1035
-            $scope = explode('.', $scope);
1036
-        }
1037
-
1038
-        if ($absolute === true) {
1039
-            $this->scope     = &$this->data;
1040
-            $this->scopeTree = array();
1041
-        }
1042
-
1043
-        while (($bit = array_shift($scope)) !== null) {
1044
-            if ($bit === '_parent' || $bit === '_') {
1045
-                array_pop($this->scopeTree);
1046
-                reset($this->scopeTree);
1047
-                $this->scope = &$this->data;
1048
-                $cnt         = count($this->scopeTree);
1049
-                for ($i = 0; $i < $cnt; ++ $i) {
1050
-                    $this->scope = &$this->scope[$this->scopeTree[$i]];
1051
-                }
1052
-            } elseif ($bit === '_root' || $bit === '__') {
1053
-                $this->scope     = &$this->data;
1054
-                $this->scopeTree = array();
1055
-            } elseif (isset($this->scope[$bit])) {
1056
-                $this->scope       = &$this->scope[$bit];
1057
-                $this->scopeTree[] = $bit;
1058
-            } else {
1059
-                $this->scope[$bit] = array();
1060
-                $this->scope       = &$this->scope[$bit];
1061
-                $this->scopeTree[] = $bit;
1062
-            }
1063
-        }
1064
-
1065
-        return $old;
1066
-    }
1067
-
1068
-    /**
1069
-     * Adds a block to the top of the block stack.
1070
-     *
1071
-     * @param string $type      block type (name)
1072
-     * @param array  $params    the parameters array
1073
-     * @param int    $paramtype the parameters type (see mapParams), 0, 1 or 2
1074
-     *
1075
-     * @return string the preProcessing() method's output
1076
-     */
1077
-    public function addBlock($type, array $params, $paramtype)
1078
-    {
1079
-        if ($this->debug) {
1080
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1081
-        }
1082
-
1083
-        $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type);
1084
-        if (class_exists($class) === false) {
1085
-            $this->getDwoo()->getLoader()->loadPlugin($type);
1086
-        }
1087
-        $params = $this->mapParams($params, array($class, 'init'), $paramtype);
1088
-
1089
-        $this->stack[]  = array(
1090
-            'type'   => $type,
1091
-            'params' => $params,
1092
-            'custom' => false,
1093
-            'class'  => $class,
1094
-            'buffer' => null
1095
-        );
1096
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1097
-
1098
-        return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1099
-    }
1100
-
1101
-    /**
1102
-     * Adds a custom block to the top of the block stack.
1103
-     *
1104
-     * @param string $type      block type (name)
1105
-     * @param array  $params    the parameters array
1106
-     * @param int    $paramtype the parameters type (see mapParams), 0, 1 or 2
1107
-     *
1108
-     * @return string the preProcessing() method's output
1109
-     */
1110
-    public function addCustomBlock($type, array $params, $paramtype)
1111
-    {
1112
-        $callback = $this->customPlugins[$type]['callback'];
1113
-        if (is_array($callback)) {
1114
-            $class = is_object($callback[0]) ? get_class($callback[0]) : $callback[0];
1115
-        } else {
1116
-            $class = $callback;
1117
-        }
1118
-
1119
-        $params = $this->mapParams($params, array($class, 'init'), $paramtype);
1120
-
1121
-        $this->stack[]  = array(
1122
-            'type'   => $type,
1123
-            'params' => $params,
1124
-            'custom' => true,
1125
-            'class'  => $class,
1126
-            'buffer' => null
1127
-        );
1128
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1129
-
1130
-        return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1131
-    }
1132
-
1133
-    /**
1134
-     * Injects a block at the top of the plugin stack without calling its preProcessing method.
1135
-     * used by {else} blocks to re-add themselves after having closed everything up to their parent
1136
-     *
1137
-     * @param string $type   block type (name)
1138
-     * @param array  $params parameters array
1139
-     */
1140
-    public function injectBlock($type, array $params)
1141
-    {
1142
-        if ($this->debug) {
1143
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1144
-        }
1145
-
1146
-        $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type);
1147
-        if (class_exists($class) === false) {
1148
-            $this->getDwoo()->getLoader()->loadPlugin($type);
1149
-        }
1150
-        $this->stack[]  = array(
1151
-            'type'   => $type,
1152
-            'params' => $params,
1153
-            'custom' => false,
1154
-            'class'  => $class,
1155
-            'buffer' => null
1156
-        );
1157
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1158
-    }
1159
-
1160
-    /**
1161
-     * Removes the closest-to-top block of the given type and all other
1162
-     * blocks encountered while going down the block stack.
1163
-     *
1164
-     * @param string $type block type (name)
1165
-     *
1166
-     * @return string the output of all postProcessing() method's return values of the closed blocks
1167
-     * @throws CompilationException
1168
-     */
1169
-    public function removeBlock($type)
1170
-    {
1171
-        if ($this->debug) {
1172
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1173
-        }
1174
-
1175
-        $output = '';
1176
-
1177
-        $pluginType = $this->getPluginType($type);
1178
-        if ($pluginType & Core::SMARTY_BLOCK) {
1179
-            $type = 'Smartyinterface';
1180
-        }
1181
-        while (true) {
1182
-            while ($top = array_pop($this->stack)) {
1183
-                if ($top['custom']) {
1184
-                    $class = $top['class'];
1185
-                } else {
1186
-                    $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($top['type']);
1187
-                }
1188
-                if (count($this->stack)) {
1189
-                    $this->curBlock = &$this->stack[count($this->stack) - 1];
1190
-                    $this->push(call_user_func(array(
1191
-                        $class,
1192
-                        'postProcessing'
1193
-                    ), $this, $top['params'], '', '', $top['buffer']), 0);
1194
-                } else {
1195
-                    $null           = null;
1196
-                    $this->curBlock = &$null;
1197
-                    $output         = call_user_func(
1198
-                        array(
1199
-                        $class,
1200
-                        'postProcessing'
1201
-                        ), $this, $top['params'], '', '', $top['buffer']
1202
-                    );
1203
-                }
1204
-
1205
-                if ($top['type'] === $type) {
1206
-                    break 2;
1207
-                }
1208
-            }
1209
-
1210
-            throw new CompilationException($this, 'Syntax malformation, a block of type "' . $type . '" was closed but was not opened');
1211
-            break;
1212
-        }
1213
-
1214
-        return $output;
1215
-    }
1216
-
1217
-    /**
1218
-     * Returns a reference to the first block of the given type encountered and
1219
-     * optionally closes all blocks until it finds it
1220
-     * this is mainly used by {else} plugins to close everything that was opened
1221
-     * between their parent and themselves.
1222
-     *
1223
-     * @param string $type       the block type (name)
1224
-     * @param bool   $closeAlong whether to close all blocks encountered while going down the block stack or not
1225
-     *
1226
-     * @return mixed &array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
1227
-     *               'custom'=>bool defining whether it's a custom plugin or not, for internal use)
1228
-     * @throws CompilationException
1229
-     */
1230
-    public function &findBlock($type, $closeAlong = false)
1231
-    {
1232
-        if ($closeAlong === true) {
1233
-            while ($b = end($this->stack)) {
1234
-                if ($b['type'] === $type) {
1235
-                    return $this->stack[key($this->stack)];
1236
-                }
1237
-                $this->push($this->removeTopBlock(), 0);
1238
-            }
1239
-        } else {
1240
-            end($this->stack);
1241
-            while ($b = current($this->stack)) {
1242
-                if ($b['type'] === $type) {
1243
-                    return $this->stack[key($this->stack)];
1244
-                }
1245
-                prev($this->stack);
1246
-            }
1247
-        }
1248
-
1249
-        throw new CompilationException($this, 'A parent block of type "' . $type . '" is required and can not be found');
1250
-    }
1251
-
1252
-    /**
1253
-     * Returns a reference to the current block array.
1254
-     *
1255
-     * @return array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
1256
-     *                'custom'=>bool defining whether it's a custom plugin or not, for internal use)
1257
-     */
1258
-    public function &getCurrentBlock()
1259
-    {
1260
-        return $this->curBlock;
1261
-    }
1262
-
1263
-    /**
1264
-     * Removes the block at the top of the stack and calls its postProcessing() method.
1265
-     *
1266
-     * @return string the postProcessing() method's output
1267
-     * @throws CompilationException
1268
-     */
1269
-    public function removeTopBlock()
1270
-    {
1271
-        if ($this->debug) {
1272
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1273
-        }
1274
-
1275
-        $o = array_pop($this->stack);
1276
-        if ($o === null) {
1277
-            throw new CompilationException($this, 'Syntax malformation, a block of unknown type was closed but was not opened.');
1278
-        }
1279
-        if ($o['custom']) {
1280
-            $class = $o['class'];
1281
-        } else {
1282
-            $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($o['type']);
1283
-        }
1284
-
1285
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1286
-
1287
-        return call_user_func(array($class, 'postProcessing'), $this, $o['params'], '', '', $o['buffer']);
1288
-    }
1289
-
1290
-    /**
1291
-     * Returns the compiled parameters (for example a variable's compiled parameter will be "$this->scope['key']") out
1292
-     * of the given parameter array.
1293
-     *
1294
-     * @param array $params parameter array
1295
-     *
1296
-     * @return array filtered parameters
1297
-     */
1298
-    public function getCompiledParams(array $params)
1299
-    {
1300
-        foreach ($params as $k => $p) {
1301
-            if (is_array($p)) {
1302
-                $params[$k] = $p[0];
1303
-            }
1304
-        }
1305
-
1306
-        return $params;
1307
-    }
1308
-
1309
-    /**
1310
-     * Returns the real parameters (for example a variable's real parameter will be its key, etc) out of the given
1311
-     * parameter array.
1312
-     *
1313
-     * @param array $params parameter array
1314
-     *
1315
-     * @return array filtered parameters
1316
-     */
1317
-    public function getRealParams(array $params)
1318
-    {
1319
-        foreach ($params as $k => $p) {
1320
-            if (is_array($p)) {
1321
-                $params[$k] = $p[1];
1322
-            }
1323
-        }
1324
-
1325
-        return $params;
1326
-    }
1327
-
1328
-    /**
1329
-     * Returns the token of each parameter out of the given parameter array.
1330
-     *
1331
-     * @param array $params parameter array
1332
-     *
1333
-     * @return array tokens
1334
-     */
1335
-    public function getParamTokens(array $params)
1336
-    {
1337
-        foreach ($params as $k => $p) {
1338
-            if (is_array($p)) {
1339
-                $params[$k] = isset($p[2]) ? $p[2] : 0;
1340
-            }
1341
-        }
1342
-
1343
-        return $params;
1344
-    }
1345
-
1346
-    /**
1347
-     * Entry point of the parser, it redirects calls to other parse* functions.
1348
-     *
1349
-     * @param string $in            the string within which we must parse something
1350
-     * @param int    $from          the starting offset of the parsed area
1351
-     * @param int    $to            the ending offset of the parsed area
1352
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
1353
-     *                              default
1354
-     * @param string $curBlock      the current parser-block being processed
1355
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
1356
-     *                              or null by default
1357
-     *
1358
-     * @return string parsed values
1359
-     * @throws CompilationException
1360
-     */
1361
-    protected function parse($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1362
-    {
1363
-        if ($this->debug) {
1364
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1365
-        }
1366
-
1367
-        if ($to === null) {
1368
-            $to = strlen($in);
1369
-        }
1370
-        $first = substr($in, $from, 1);
1371
-
1372
-        if ($first === false) {
1373
-            throw new CompilationException($this, 'Unexpected EOF, a template tag was not closed');
1374
-        }
1375
-
1376
-        while ($first === ' ' || $first === "\n" || $first === "\t" || $first === "\r") {
1377
-            if ($curBlock === 'root' && substr($in, $from, strlen($this->rd)) === $this->rd) {
1378
-                // end template tag
1379
-                $pointer += strlen($this->rd);
1380
-                if ($this->debug) {
1381
-                    echo 'TEMPLATE PARSING ENDED' . "\n";
1382
-                }
1383
-
1384
-                return false;
1385
-            }
1386
-            ++ $from;
1387
-            if ($pointer !== null) {
1388
-                ++ $pointer;
1389
-            }
1390
-            if ($from >= $to) {
1391
-                if (is_array($parsingParams)) {
1392
-                    return $parsingParams;
1393
-                } else {
1394
-                    return '';
1395
-                }
1396
-            }
1397
-            $first = $in[$from];
1398
-        }
1399
-
1400
-        $substr = substr($in, $from, $to - $from);
1401
-
1402
-        if ($this->debug) {
1403
-            echo 'PARSE CALL : PARSING "' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . '" @ ' . $from . ':' . $to . ' in ' . $curBlock . ' : pointer=' . $pointer . "\n";
1404
-        }
1405
-        $parsed = '';
1406
-
1407
-        if ($curBlock === 'root' && $first === '*') {
1408
-            $src      = $this->getTemplateSource();
1409
-            $startpos = $this->getPointer() - strlen($this->ld);
1410
-            if (substr($src, $startpos, strlen($this->ld)) === $this->ld) {
1411
-                if ($startpos > 0) {
1412
-                    do {
1413
-                        $char = substr($src, -- $startpos, 1);
1414
-                        if ($char == "\n") {
1415
-                            ++ $startpos;
1416
-                            $whitespaceStart = true;
1417
-                            break;
1418
-                        }
1419
-                    }
1420
-                    while ($startpos > 0 && ($char == ' ' || $char == "\t"));
1421
-                }
1422
-
1423
-                if (!isset($whitespaceStart)) {
1424
-                    $startpos = $this->getPointer();
1425
-                } else {
1426
-                    $pointer -= $this->getPointer() - $startpos;
1427
-                }
1428
-
1429
-                if ($this->allowNestedComments && strpos($src, $this->ld . '*', $this->getPointer()) !== false) {
1430
-                    $comOpen  = $this->ld . '*';
1431
-                    $comClose = '*' . $this->rd;
1432
-                    $level    = 1;
1433
-                    $ptr      = $this->getPointer();
1434
-
1435
-                    while ($level > 0 && $ptr < strlen($src)) {
1436
-                        $open  = strpos($src, $comOpen, $ptr);
1437
-                        $close = strpos($src, $comClose, $ptr);
1438
-
1439
-                        if ($open !== false && $close !== false) {
1440
-                            if ($open < $close) {
1441
-                                $ptr = $open + strlen($comOpen);
1442
-                                ++ $level;
1443
-                            } else {
1444
-                                $ptr = $close + strlen($comClose);
1445
-                                -- $level;
1446
-                            }
1447
-                        } elseif ($open !== false) {
1448
-                            $ptr = $open + strlen($comOpen);
1449
-                            ++ $level;
1450
-                        } elseif ($close !== false) {
1451
-                            $ptr = $close + strlen($comClose);
1452
-                            -- $level;
1453
-                        } else {
1454
-                            $ptr = strlen($src);
1455
-                        }
1456
-                    }
1457
-                    $endpos = $ptr - strlen('*' . $this->rd);
1458
-                } else {
1459
-                    $endpos = strpos($src, '*' . $this->rd, $startpos);
1460
-                    if ($endpos == false) {
1461
-                        throw new CompilationException($this, 'Un-ended comment');
1462
-                    }
1463
-                }
1464
-                $pointer += $endpos - $startpos + strlen('*' . $this->rd);
1465
-                if (isset($whitespaceStart) && preg_match('#^[\t ]*\r?\n#', substr($src, $endpos + strlen('*' . $this->rd)), $m)) {
1466
-                    $pointer += strlen($m[0]);
1467
-                    $this->curBlock['buffer'] = substr($this->curBlock['buffer'], 0, strlen($this->curBlock['buffer']) - ($this->getPointer() - $startpos - strlen($this->ld)));
1468
-                }
1469
-
1470
-                return false;
1471
-            }
1472
-        }
1473
-
1474
-        if ($first === '$') {
1475
-            // var
1476
-            $out    = $this->parseVar($in, $from, $to, $parsingParams, $curBlock, $pointer);
1477
-            $parsed = 'var';
1478
-        } elseif ($first === '%' && preg_match('#^%[a-z_\\\\]#i', $substr)) {
1479
-            // Short constant
1480
-            $out = $this->parseConst($in, $from, $to, $parsingParams, $curBlock, $pointer);
1481
-        } elseif (($first === '"' || $first === "'") && !(is_array($parsingParams) && preg_match('#^([\'"])[a-z0-9_]+\1\s*=>?(?:\s+|[^=])#i', $substr))) {
1482
-            // string
1483
-            $out = $this->parseString($in, $from, $to, $parsingParams, $curBlock, $pointer);
1484
-        } elseif (preg_match('/^\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?(' . (is_array($parsingParams) || $curBlock != 'root' ? '' : '\s+[^(]|') . '\s*\(|\s*' . $this->rdr . '|\s*;)/i', $substr)) {
1485
-            // func
1486
-            $out    = $this->parseFunction($in, $from, $to, $parsingParams, $curBlock, $pointer);
1487
-            $parsed = 'func';
1488
-        } elseif ($first === ';') {
1489
-            // instruction end
1490
-            if ($this->debug) {
1491
-                echo 'END OF INSTRUCTION' . "\n";
1492
-            }
1493
-            if ($pointer !== null) {
1494
-                ++ $pointer;
1495
-            }
1496
-
1497
-            return $this->parse($in, $from + 1, $to, false, 'root', $pointer);
1498
-        } elseif ($curBlock === 'root' && preg_match('#^/([a-z_][a-z0-9_]*)?#i', $substr, $match)) {
1499
-            // close block
1500
-            if (!empty($match[1]) && $match[1] == 'else') {
1501
-                throw new CompilationException($this, 'Else blocks must not be closed explicitly, they are automatically closed when their parent block is closed');
1502
-            }
1503
-            if (!empty($match[1]) && $match[1] == 'elseif') {
1504
-                throw new CompilationException($this, 'Elseif blocks must not be closed explicitly, they are automatically closed when their parent block is closed or a new else/elseif block is declared after them');
1505
-            }
1506
-            if ($pointer !== null) {
1507
-                $pointer += strlen($match[0]);
1508
-            }
1509
-            if (empty($match[1])) {
1510
-                if ($this->curBlock['type'] == 'else' || $this->curBlock['type'] == 'elseif') {
1511
-                    $pointer -= strlen($match[0]);
1512
-                }
1513
-                if ($this->debug) {
1514
-                    echo 'TOP BLOCK CLOSED' . "\n";
1515
-                }
1516
-
1517
-                return $this->removeTopBlock();
1518
-            } else {
1519
-                if ($this->debug) {
1520
-                    echo 'BLOCK OF TYPE ' . $match[1] . ' CLOSED' . "\n";
1521
-                }
1522
-
1523
-                return $this->removeBlock($match[1]);
1524
-            }
1525
-        } elseif ($curBlock === 'root' && substr($substr, 0, strlen($this->rd)) === $this->rd) {
1526
-            // end template tag
1527
-            if ($this->debug) {
1528
-                echo 'TAG PARSING ENDED' . "\n";
1529
-            }
1530
-            $pointer += strlen($this->rd);
1531
-
1532
-            return false;
1533
-        } elseif (is_array($parsingParams) && preg_match('#^(([\'"]?)[a-z0-9_]+\2\s*=' . ($curBlock === 'array' ? '>?' : '') . ')(?:\s+|[^=]).*#i', $substr, $match)) {
1534
-            // named parameter
1535
-            if ($this->debug) {
1536
-                echo 'NAMED PARAM FOUND' . "\n";
1537
-            }
1538
-            $len = strlen($match[1]);
1539
-            while (substr($in, $from + $len, 1) === ' ') {
1540
-                ++ $len;
1541
-            }
1542
-            if ($pointer !== null) {
1543
-                $pointer += $len;
1544
-            }
1545
-
1546
-            $output = array(
1547
-                trim($match[1], " \t\r\n=>'\""),
1548
-                $this->parse($in, $from + $len, $to, false, 'namedparam', $pointer)
1549
-            );
1550
-
1551
-            $parsingParams[] = $output;
1552
-
1553
-            return $parsingParams;
1554
-        } elseif (preg_match('#^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*::\$[a-z0-9_]+)#i', $substr, $match)) {
1555
-            // static member access
1556
-            $parsed = 'var';
1557
-            if (is_array($parsingParams)) {
1558
-                $parsingParams[] = array($match[1], $match[1]);
1559
-                $out             = $parsingParams;
1560
-            } else {
1561
-                $out = $match[1];
1562
-            }
1563
-            $pointer += strlen($match[1]);
1564
-        } elseif ($substr !== '' && (is_array($parsingParams) || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'expression')) {
1565
-            // unquoted string, bool or number
1566
-            $out = $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1567
-        } else {
1568
-            // parse error
1569
-            throw new CompilationException($this, 'Parse error in "' . substr($in, $from, $to - $from) . '"');
1570
-        }
1571
-
1572
-        if (empty($out)) {
1573
-            return '';
1574
-        }
1575
-
1576
-        $substr = substr($in, $pointer, $to - $pointer);
1577
-
1578
-        // var parsed, check if any var-extension applies
1579
-        if ($parsed === 'var') {
1580
-            if (preg_match('#^\s*([/%+*-])\s*([a-z0-9]|\$)#i', $substr, $match)) {
1581
-                if ($this->debug) {
1582
-                    echo 'PARSING POST-VAR EXPRESSION ' . $substr . "\n";
1583
-                }
1584
-                // parse expressions
1585
-                $pointer += strlen($match[0]) - 1;
1586
-                if (is_array($parsingParams)) {
1587
-                    if ($match[2] == '$') {
1588
-                        $expr = $this->parseVar($in, $pointer, $to, array(), $curBlock, $pointer);
1589
-                    } else {
1590
-                        $expr = $this->parse($in, $pointer, $to, array(), 'expression', $pointer);
1591
-                    }
1592
-                    $out[count($out) - 1][0] .= $match[1] . $expr[0][0];
1593
-                    $out[count($out) - 1][1] .= $match[1] . $expr[0][1];
1594
-                } else {
1595
-                    if ($match[2] == '$') {
1596
-                        $expr = $this->parseVar($in, $pointer, $to, false, $curBlock, $pointer);
1597
-                    } else {
1598
-                        $expr = $this->parse($in, $pointer, $to, false, 'expression', $pointer);
1599
-                    }
1600
-                    if (is_array($out) && is_array($expr)) {
1601
-                        $out[0] .= $match[1] . $expr[0];
1602
-                        $out[1] .= $match[1] . $expr[1];
1603
-                    } elseif (is_array($out)) {
1604
-                        $out[0] .= $match[1] . $expr;
1605
-                        $out[1] .= $match[1] . $expr;
1606
-                    } elseif (is_array($expr)) {
1607
-                        $out .= $match[1] . $expr[0];
1608
-                    } else {
1609
-                        $out .= $match[1] . $expr;
1610
-                    }
1611
-                }
1612
-            } elseif ($curBlock === 'root' && preg_match('#^(\s*(?:[+/*%-.]=|=|\+\+|--)\s*)(.*)#s', $substr, $match)) {
1613
-                if ($this->debug) {
1614
-                    echo 'PARSING POST-VAR ASSIGNMENT ' . $substr . "\n";
1615
-                }
1616
-                // parse assignment
1617
-                $value    = $match[2];
1618
-                $operator = trim($match[1]);
1619
-                if (substr($value, 0, 1) == '=') {
1620
-                    throw new CompilationException($this, 'Unexpected "=" in <em>' . $substr . '</em>');
1621
-                }
1622
-
1623
-                if ($pointer !== null) {
1624
-                    $pointer += strlen($match[1]);
1625
-                }
1626
-
1627
-                if ($operator !== '++' && $operator !== '--') {
1628
-                    $parts = array();
1629
-                    $ptr   = 0;
1630
-                    $parts = $this->parse($value, 0, strlen($value), $parts, 'condition', $ptr);
1631
-                    $pointer += $ptr;
1632
-
1633
-                    // load if plugin
1634
-                    try {
1635
-                        $this->getPluginType('if');
1636
-                    }
1637
-                    catch (Exception $e) {
1638
-                        throw new CompilationException($this, 'Assignments require the "if" plugin to be accessible');
1639
-                    }
1640
-
1641
-                    $parts  = $this->mapParams($parts, array(Core::NAMESPACE_PLUGINS_BLOCKS . 'PluginIf', 'init'), 1);
1642
-                    $tokens = $this->getParamTokens($parts);
1643
-                    $parts  = $this->getCompiledParams($parts);
1644
-
1645
-                    $value = PluginIf::replaceKeywords($parts['*'], $tokens['*'], $this);
1646
-                    $echo  = '';
1647
-                } else {
1648
-                    $value = array();
1649
-                    $echo  = 'echo ';
1650
-                }
1651
-
1652
-                if ($this->autoEscape) {
1653
-                    $out = preg_replace('#\(is_string\(\$tmp=(.+?)\) \? htmlspecialchars\(\$tmp, ENT_QUOTES, \$this->charset\) : \$tmp\)#', '$1', $out);
1654
-                }
1655
-                $out = self::PHP_OPEN . $echo . $out . $operator . implode(' ', $value) . self::PHP_CLOSE;
1656
-            } elseif ($curBlock === 'array' && is_array($parsingParams) && preg_match('#^(\s*=>?\s*)#', $substr, $match)) {
1657
-                // parse namedparam with var as name (only for array)
1658
-                if ($this->debug) {
1659
-                    echo 'VARIABLE NAMED PARAM (FOR ARRAY) FOUND' . "\n";
1660
-                }
1661
-                $len = strlen($match[1]);
1662
-                $var = $out[count($out) - 1];
1663
-                $pointer += $len;
1664
-
1665
-                $output = array($var[0], $this->parse($substr, $len, null, false, 'namedparam', $pointer));
1666
-
1667
-                $parsingParams[] = $output;
1668
-
1669
-                return $parsingParams;
1670
-            }
1671
-        }
1672
-
1673
-        if ($curBlock !== 'modifier' && ($parsed === 'func' || $parsed === 'var') && preg_match('#^(\|@?[a-z0-9_]+(:.*)?)+#i', $substr, $match)) {
1674
-            // parse modifier on funcs or vars
1675
-            $srcPointer = $pointer;
1676
-            if (is_array($parsingParams)) {
1677
-                $tmp                     = $this->replaceModifiers(
1678
-                    array(
1679
-                    null,
1680
-                    null,
1681
-                    $out[count($out) - 1][0],
1682
-                    $match[0]
1683
-                    ), $curBlock, $pointer
1684
-                );
1685
-                $out[count($out) - 1][0] = $tmp;
1686
-                $out[count($out) - 1][1] .= substr($substr, $srcPointer, $srcPointer - $pointer);
1687
-            } else {
1688
-                $out = $this->replaceModifiers(array(null, null, $out, $match[0]), $curBlock, $pointer);
1689
-            }
1690
-        }
1691
-
1692
-        // func parsed, check if any func-extension applies
1693
-        if ($parsed === 'func' && preg_match('#^->[a-z0-9_]+(\s*\(.+|->[a-z_].*)?#is', $substr, $match)) {
1694
-            // parse method call or property read
1695
-            $ptr = 0;
1696
-
1697
-            if (is_array($parsingParams)) {
1698
-                $output = $this->parseMethodCall($out[count($out) - 1][1], $match[0], $curBlock, $ptr);
1699
-
1700
-                $out[count($out) - 1][0] = $output;
1701
-                $out[count($out) - 1][1] .= substr($match[0], 0, $ptr);
1702
-            } else {
1703
-                $out = $this->parseMethodCall($out, $match[0], $curBlock, $ptr);
1704
-            }
1705
-
1706
-            $pointer += $ptr;
1707
-        }
1708
-
1709
-        if ($curBlock === 'root' && substr($out, 0, strlen(self::PHP_OPEN)) !== self::PHP_OPEN) {
1710
-            return self::PHP_OPEN . 'echo ' . $out . ';' . self::PHP_CLOSE;
1711
-        } else {
1712
-            return $out;
1713
-        }
1714
-    }
1715
-
1716
-    /**
1717
-     * Parses a function call.
1718
-     *
1719
-     * @param string $in            the string within which we must parse something
1720
-     * @param int    $from          the starting offset of the parsed area
1721
-     * @param int    $to            the ending offset of the parsed area
1722
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
1723
-     *                              default
1724
-     * @param string $curBlock      the current parser-block being processed
1725
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
1726
-     *                              or null by default
1727
-     *
1728
-     * @return string parsed values
1729
-     * @throws CompilationException
1730
-     * @throws Exception
1731
-     * @throws SecurityException
1732
-     */
1733
-    protected function parseFunction($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1734
-    {
1735
-        $output = '';
1736
-        $cmdstr = substr($in, $from, $to - $from);
1737
-        preg_match('/^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?)(\s*' . $this->rdr . '|\s*;)?/i', $cmdstr, $match);
1738
-
1739
-        if (empty($match[1])) {
1740
-            throw new CompilationException($this, 'Parse error, invalid function name : ' . substr($cmdstr, 0, 15));
1741
-        }
1742
-
1743
-        $func = $match[1];
1744
-
1745
-        if (!empty($match[2])) {
1746
-            $cmdstr = $match[1];
1747
-        }
1748
-
1749
-        if ($this->debug) {
1750
-            echo 'FUNC FOUND (' . $func . ')' . "\n";
1751
-        }
1752
-
1753
-        $paramsep = '';
1754
-
1755
-        if (is_array($parsingParams) || $curBlock != 'root') {
1756
-            $paramspos = strpos($cmdstr, '(');
1757
-            $paramsep  = ')';
1758
-        } elseif (preg_match_all('#^\s*[\\\\:a-z0-9_]+(\s*\(|\s+[^(])#i', $cmdstr, $match, PREG_OFFSET_CAPTURE)) {
1759
-            $paramspos = $match[1][0][1];
1760
-            $paramsep  = substr($match[1][0][0], - 1) === '(' ? ')' : '';
1761
-            if ($paramsep === ')') {
1762
-                $paramspos += strlen($match[1][0][0]) - 1;
1763
-                if (substr($cmdstr, 0, 2) === 'if' || substr($cmdstr, 0, 6) === 'elseif') {
1764
-                    $paramsep = '';
1765
-                    if (strlen($match[1][0][0]) > 1) {
1766
-                        -- $paramspos;
1767
-                    }
1768
-                }
1769
-            }
1770
-        } else {
1771
-            $paramspos = false;
1772
-        }
1773
-
1774
-        $state = 0;
1775
-
1776
-        if ($paramspos === false) {
1777
-            $params = array();
1778
-
1779
-            if ($curBlock !== 'root') {
1780
-                return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1781
-            }
1782
-        } else {
1783
-            if ($curBlock === 'condition') {
1784
-                // load if plugin
1785
-                $this->getPluginType('if');
1786
-
1787
-                if (PluginIf::replaceKeywords(array($func), array(self::T_UNQUOTED_STRING), $this) !== array($func)) {
1788
-                    return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1789
-                }
1790
-            }
1791
-            $whitespace = strlen(substr($cmdstr, strlen($func), $paramspos - strlen($func)));
1792
-            $paramstr   = substr($cmdstr, $paramspos + 1);
1793
-            if (substr($paramstr, - 1, 1) === $paramsep) {
1794
-                $paramstr = substr($paramstr, 0, - 1);
1795
-            }
1796
-
1797
-            if (strlen($paramstr) === 0) {
1798
-                $params   = array();
1799
-                $paramstr = '';
1800
-            } else {
1801
-                $ptr    = 0;
1802
-                $params = array();
1803
-                if ($func === 'empty') {
1804
-                    $params = $this->parseVar($paramstr, $ptr, strlen($paramstr), $params, 'root', $ptr);
1805
-                } else {
1806
-                    while ($ptr < strlen($paramstr)) {
1807
-                        while (true) {
1808
-                            if ($ptr >= strlen($paramstr)) {
1809
-                                break 2;
1810
-                            }
1811
-
1812
-                            if ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === ')') {
1813
-                                if ($this->debug) {
1814
-                                    echo 'PARAM PARSING ENDED, ")" FOUND, POINTER AT ' . $ptr . "\n";
1815
-                                }
1816
-                                break 2;
1817
-                            } elseif ($paramstr[$ptr] === ';') {
1818
-                                ++ $ptr;
1819
-                                if ($this->debug) {
1820
-                                    echo 'PARAM PARSING ENDED, ";" FOUND, POINTER AT ' . $ptr . "\n";
1821
-                                }
1822
-                                break 2;
1823
-                            } elseif ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === '/') {
1824
-                                if ($this->debug) {
1825
-                                    echo 'PARAM PARSING ENDED, "/" FOUND, POINTER AT ' . $ptr . "\n";
1826
-                                }
1827
-                                break 2;
1828
-                            } elseif (substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
1829
-                                if ($this->debug) {
1830
-                                    echo 'PARAM PARSING ENDED, RIGHT DELIMITER FOUND, POINTER AT ' . $ptr . "\n";
1831
-                                }
1832
-                                break 2;
1833
-                            }
1834
-
1835
-                            if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === ',' || $paramstr[$ptr] === "\r" || $paramstr[$ptr] === "\n" || $paramstr[$ptr] === "\t") {
1836
-                                ++ $ptr;
1837
-                            } else {
1838
-                                break;
1839
-                            }
1840
-                        }
1841
-
1842
-                        if ($this->debug) {
1843
-                            echo 'FUNC START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
1844
-                        }
1845
-
1846
-                        if ($func === 'if' || $func === 'elseif' || $func === 'tif') {
1847
-                            $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'condition', $ptr);
1848
-                        } elseif ($func === 'array') {
1849
-                            $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'array', $ptr);
1850
-                        } else {
1851
-                            $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'function', $ptr);
1852
-                        }
1853
-
1854
-                        if ($this->debug) {
1855
-                            echo 'PARAM PARSED, POINTER AT ' . $ptr . ' (' . substr($paramstr, $ptr - 1, 3) . ')' . "\n";
1856
-                        }
1857
-                    }
1858
-                }
1859
-                $paramstr = substr($paramstr, 0, $ptr);
1860
-                $state    = 0;
1861
-                foreach ($params as $k => $p) {
1862
-                    if (is_array($p) && is_array($p[1])) {
1863
-                        $state |= 2;
1864
-                    } else {
1865
-                        if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m) && $func !== 'array') {
1866
-                            $params[$k] = array($m[2], array('true', 'true'));
1867
-                        } else {
1868
-                            if ($state & 2 && $func !== 'array') {
1869
-                                throw new CompilationException($this, 'You can not use an unnamed parameter after a named one');
1870
-                            }
1871
-                            $state |= 1;
1872
-                        }
1873
-                    }
1874
-                }
1875
-            }
1876
-        }
1877
-
1878
-        if ($pointer !== null) {
1879
-            $pointer += (isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func) + (isset($whitespace) ? $whitespace : 0);
1880
-            if ($this->debug) {
1881
-                echo 'FUNC ADDS ' . ((isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func)) . ' TO POINTER' . "\n";
1882
-            }
1883
-        }
1884
-
1885
-        if ($curBlock === 'method' || $func === 'do' || strstr($func, '::') !== false) {
1886
-            // handle static method calls with security policy
1887
-            if (strstr($func, '::') !== false && $this->securityPolicy !== null && $this->securityPolicy->isMethodAllowed(explode('::', strtolower($func))) !== true) {
1888
-                throw new SecurityException('Call to a disallowed php function : ' . $func);
1889
-            }
1890
-            $pluginType = Core::NATIVE_PLUGIN;
1891
-        } else {
1892
-            $pluginType = $this->getPluginType($func);
1893
-        }
1894
-
1895
-        // Blocks plugin
1896
-        if ($pluginType & Core::BLOCK_PLUGIN) {
1897
-            if ($curBlock !== 'root' || is_array($parsingParams)) {
1898
-                throw new CompilationException($this, 'Block plugins can not be used as other plugin\'s arguments');
1899
-            }
1900
-            if ($pluginType & Core::CUSTOM_PLUGIN) {
1901
-                return $this->addCustomBlock($func, $params, $state);
1902
-            } else {
1903
-                return $this->addBlock($func, $params, $state);
1904
-            }
1905
-        } elseif ($pluginType & Core::SMARTY_BLOCK) {
1906
-            if ($curBlock !== 'root' || is_array($parsingParams)) {
1907
-                throw new CompilationException($this, 'Block plugins can not be used as other plugin\'s arguments');
1908
-            }
1909
-
1910
-            if ($state & 2) {
1911
-                array_unshift($params, array('__functype', array($pluginType, $pluginType)));
1912
-                array_unshift($params, array('__funcname', array($func, $func)));
1913
-            } else {
1914
-                array_unshift($params, array($pluginType, $pluginType));
1915
-                array_unshift($params, array($func, $func));
1916
-            }
1917
-
1918
-            return $this->addBlock('smartyinterface', $params, $state);
1919
-        }
1920
-
1921
-        // Native & Smarty plugins
1922
-        if ($pluginType & Core::NATIVE_PLUGIN || $pluginType & Core::SMARTY_FUNCTION || $pluginType & Core::SMARTY_BLOCK) {
1923
-            $params = $this->mapParams($params, null, $state);
1924
-        } // PHP class plugin
1925
-        elseif ($pluginType & Core::CLASS_PLUGIN) {
1926
-            if ($pluginType & Core::CUSTOM_PLUGIN) {
1927
-                $params = $this->mapParams(
1928
-                    $params, array(
1929
-                    $this->customPlugins[$func]['class'],
1930
-                    $this->customPlugins[$func]['function']
1931
-                ), $state);
1932
-            } else {
1933
-                if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
1934
-                    $params = $this->mapParams($params, array(
1935
-                        'Plugin' . Core::toCamelCase($func),
1936
-                        ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1937
-                    ), $state);
1938
-                } elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !== false) {
1939
-                    $params = $this->mapParams($params, array(
1940
-                        Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func),
1941
-                        ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1942
-                    ), $state);
1943
-                } else {
1944
-                    $params = $this->mapParams($params, array(
1945
-                        Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
1946
-                        ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1947
-                    ), $state);
1948
-                }
1949
-            }
1950
-        } // PHP function plugin
1951
-        elseif ($pluginType & Core::FUNC_PLUGIN) {
1952
-            if ($pluginType & Core::CUSTOM_PLUGIN) {
1953
-                $params = $this->mapParams($params, $this->customPlugins[$func]['callback'], $state);
1954
-            } else {
1955
-                // Custom plugin
1956
-                if (function_exists('Plugin' . Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ?
1957
-                        'Compile' : '')) !== false) {
1958
-                    $params = $this->mapParams($params, 'Plugin' . Core::toCamelCase($func) . (($pluginType &
1959
-                            Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1960
-                } // Builtin helper plugin
1961
-                elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . (
1962
-                    ($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '')) !== false) {
1963
-                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase
1964
-                        ($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1965
-                } // Builtin function plugin
1966
-                else {
1967
-                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase
1968
-                        ($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1969
-                }
1970
-            }
1971
-        } // Smarty modifier
1972
-        elseif ($pluginType & Core::SMARTY_MODIFIER) {
1973
-            $output = 'smarty_modifier_' . $func . '(' . implode(', ', $params) . ')';
1974
-        } // Proxy plugin
1975
-        elseif ($pluginType & Core::PROXY_PLUGIN) {
1976
-            $params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state);
1977
-        } // Template plugin
1978
-        elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
1979
-            // transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values))
1980
-            $map = array();
1981
-            foreach ($this->templatePlugins[$func]['params'] as $param => $defValue) {
1982
-                if ($param == 'rest') {
1983
-                    $param = '*';
1984
-                }
1985
-                $hasDefault = $defValue !== null;
1986
-                if ($defValue === 'null') {
1987
-                    $defValue = null;
1988
-                } elseif ($defValue === 'false') {
1989
-                    $defValue = false;
1990
-                } elseif ($defValue === 'true') {
1991
-                    $defValue = true;
1992
-                } elseif (preg_match('#^([\'"]).*?\1$#', $defValue)) {
1993
-                    $defValue = substr($defValue, 1, - 1);
1994
-                }
1995
-                $map[] = array($param, $hasDefault, $defValue);
1996
-            }
1997
-
1998
-            $params = $this->mapParams($params, null, $state, $map);
1999
-        }
2000
-
2001
-        // only keep php-syntax-safe values for non-block plugins
2002
-        $tokens = array();
2003
-        foreach ($params as $k => $p) {
2004
-            $tokens[$k] = isset($p[2]) ? $p[2] : 0;
2005
-            $params[$k] = $p[0];
2006
-        }
2007
-
2008
-        // Native plugin
2009
-        if ($pluginType & Core::NATIVE_PLUGIN) {
2010
-            if ($func === 'do') {
2011
-                $output = '';
2012
-                if (isset($params['*'])) {
2013
-                    $output = implode(';', $params['*']) . ';';
2014
-                }
2015
-
2016
-                if (is_array($parsingParams) || $curBlock !== 'root') {
2017
-                    throw new CompilationException($this, 'Do can not be used inside another function or block');
2018
-                }
2019
-
2020
-                return self::PHP_OPEN . $output . self::PHP_CLOSE;
2021
-            } else {
2022
-                if (isset($params['*'])) {
2023
-                    $output = $func . '(' . implode(', ', $params['*']) . ')';
2024
-                } else {
2025
-                    $output = $func . '()';
2026
-                }
2027
-            }
2028
-        } // Block class OR Function class
2029
-        elseif ($pluginType & Core::CLASS_PLUGIN || ($pluginType & Core::FUNC_PLUGIN && $pluginType & Core::CLASS_PLUGIN)) {
2030
-            if ($pluginType & Core::COMPILABLE_PLUGIN) {
2031
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
2032
-                    $callback = $this->customPlugins[$func]['callback'];
2033
-                    if (!is_array($callback)) {
2034
-                        if (!method_exists($callback, 'compile')) {
2035
-                            throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
2036
-                        }
2037
-                        if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
2038
-                            $funcCompiler = array($callback, 'compile');
2039
-                        } else {
2040
-                            $funcCompiler = array(new $callback(), 'compile');
2041
-                        }
2042
-                    } else {
2043
-                        $funcCompiler = $callback;
2044
-                    }
2045
-                } else {
2046
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2047
-                        $funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
2048
-                    } elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !== false) {
2049
-                        $funcCompiler = array(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func), 'compile');
2050
-                    } else {
2051
-                        $funcCompiler = array(
2052
-                            Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
2053
-                            'compile'
2054
-                        );
2055
-                    }
2056
-                    array_unshift($params, $this);
2057
-                }
2058
-                // @TODO: Is it a real fix ?
2059
-                if ($func === 'tif') {
2060
-                    $params[] = $tokens;
2061
-                }
2062
-                $output = call_user_func_array($funcCompiler, $params);
2063
-            } else {
2064
-                $params = self::implode_r($params);
2065
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
2066
-                    $callback = $this->customPlugins[$func]['callback'];
2067
-                    if (!is_array($callback)) {
2068
-                        if (!method_exists($callback, 'process')) {
2069
-                            throw new Exception('Custom plugin ' . $func . ' must implement the "process" method to be usable, or you should provide a full callback to the method to use');
2070
-                        }
2071
-                        if (($ref = new ReflectionMethod($callback, 'process')) && $ref->isStatic()) {
2072
-                            $output = 'call_user_func(array(\'' . $callback . '\', \'process\'), ' . $params . ')';
2073
-                        } else {
2074
-                            $output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback . '\'), \'process\'), ' . $params . ')';
2075
-                        }
2076
-                    } elseif (is_object($callback[0])) {
2077
-                        $output = 'call_user_func(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), ' . $params . ')';
2078
-                    } elseif (($ref = new ReflectionMethod($callback[0], $callback[1])) && $ref->isStatic()) {
2079
-                        $output = 'call_user_func(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), ' . $params . ')';
2080
-                    } else {
2081
-                        $output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback[0] . '\'), \'' . $callback[1] . '\'), ' . $params . ')';
2082
-                    }
2083
-                    if (empty($params)) {
2084
-                        $output = substr($output, 0, - 3) . ')';
2085
-                    }
2086
-                } else {
2087
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2088
-                        $output = '$this->classCall(\'Plugin' . $func . '\', array(' . $params . '))';
2089
-                    } elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !== false) {
2090
-                        $output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\', 
34
+	/**
35
+	 * Constant that represents a php opening tag.
36
+	 * use it in case it needs to be adjusted
37
+	 *
38
+	 * @var string
39
+	 */
40
+	const PHP_OPEN = '<?php ';
41
+
42
+	/**
43
+	 * Constant that represents a php closing tag.
44
+	 * use it in case it needs to be adjusted
45
+	 *
46
+	 * @var string
47
+	 */
48
+	const PHP_CLOSE = '?>';
49
+
50
+	/**
51
+	 * Boolean flag to enable or disable debugging output.
52
+	 *
53
+	 * @var bool
54
+	 */
55
+	public $debug = false;
56
+
57
+	/**
58
+	 * Left script delimiter.
59
+	 *
60
+	 * @var string
61
+	 */
62
+	protected $ld = '{';
63
+
64
+	/**
65
+	 * Left script delimiter with escaped regex meta characters.
66
+	 *
67
+	 * @var string
68
+	 */
69
+	protected $ldr = '\\{';
70
+
71
+	/**
72
+	 * Right script delimiter.
73
+	 *
74
+	 * @var string
75
+	 */
76
+	protected $rd = '}';
77
+
78
+	/**
79
+	 * Right script delimiter with escaped regex meta characters.
80
+	 *
81
+	 * @var string
82
+	 */
83
+	protected $rdr = '\\}';
84
+
85
+	/**
86
+	 * Defines whether the nested comments should be parsed as nested or not.
87
+	 * defaults to false (classic block comment parsing as in all languages)
88
+	 *
89
+	 * @var bool
90
+	 */
91
+	protected $allowNestedComments = false;
92
+
93
+	/**
94
+	 * Defines whether opening and closing tags can contain spaces before valid data or not.
95
+	 * turn to true if you want to be sloppy with the syntax, but when set to false it allows
96
+	 * to skip javascript and css tags as long as they are in the form "{ something", which is
97
+	 * nice. default is false.
98
+	 *
99
+	 * @var bool
100
+	 */
101
+	protected $allowLooseOpenings = false;
102
+
103
+	/**
104
+	 * Defines whether the compiler will automatically html-escape variables or not.
105
+	 * default is false
106
+	 *
107
+	 * @var bool
108
+	 */
109
+	protected $autoEscape = false;
110
+
111
+	/**
112
+	 * Security policy object.
113
+	 *
114
+	 * @var SecurityPolicy
115
+	 */
116
+	protected $securityPolicy;
117
+
118
+	/**
119
+	 * Stores the custom plugins registered with this compiler.
120
+	 *
121
+	 * @var array
122
+	 */
123
+	protected $customPlugins = array();
124
+
125
+	/**
126
+	 * Stores the template plugins registered with this compiler.
127
+	 *
128
+	 * @var array
129
+	 */
130
+	protected $templatePlugins = array();
131
+
132
+	/**
133
+	 * Stores the pre- and post-processors callbacks.
134
+	 *
135
+	 * @var array
136
+	 */
137
+	protected $processors = array('pre' => array(), 'post' => array());
138
+
139
+	/**
140
+	 * Stores a list of plugins that are used in the currently compiled
141
+	 * template, and that are not compilable. these plugins will be loaded
142
+	 * during the template's runtime if required.
143
+	 * it is a 1D array formatted as key:pluginName value:pluginType
144
+	 *
145
+	 * @var array
146
+	 */
147
+	protected $usedPlugins;
148
+
149
+	/**
150
+	 * Stores the template undergoing compilation.
151
+	 *
152
+	 * @var string
153
+	 */
154
+	protected $template;
155
+
156
+	/**
157
+	 * Stores the current pointer position inside the template.
158
+	 *
159
+	 * @var int
160
+	 */
161
+	protected $pointer;
162
+
163
+	/**
164
+	 * Stores the current line count inside the template for debugging purposes.
165
+	 *
166
+	 * @var int
167
+	 */
168
+	protected $line;
169
+
170
+	/**
171
+	 * Stores the current template source while compiling it.
172
+	 *
173
+	 * @var string
174
+	 */
175
+	protected $templateSource;
176
+
177
+	/**
178
+	 * Stores the data within which the scope moves.
179
+	 *
180
+	 * @var array
181
+	 */
182
+	protected $data;
183
+
184
+	/**
185
+	 * Variable scope of the compiler, set to null if
186
+	 * it can not be resolved to a static string (i.e. if some
187
+	 * plugin defines a new scope based on a variable array key).
188
+	 *
189
+	 * @var mixed
190
+	 */
191
+	protected $scope;
192
+
193
+	/**
194
+	 * Variable scope tree, that allows to rebuild the current
195
+	 * scope if required, i.e. when going to a parent level.
196
+	 *
197
+	 * @var array
198
+	 */
199
+	protected $scopeTree;
200
+
201
+	/**
202
+	 * Block plugins stack, accessible through some methods.
203
+	 *
204
+	 * @see findBlock
205
+	 * @see getCurrentBlock
206
+	 * @see addBlock
207
+	 * @see addCustomBlock
208
+	 * @see injectBlock
209
+	 * @see removeBlock
210
+	 * @see removeTopBlock
211
+	 * @var array
212
+	 */
213
+	protected $stack = array();
214
+
215
+	/**
216
+	 * Current block at the top of the block plugins stack,
217
+	 * accessible through getCurrentBlock.
218
+	 *
219
+	 * @see getCurrentBlock
220
+	 * @var array
221
+	 */
222
+	protected $curBlock;
223
+
224
+	/**
225
+	 * Current dwoo object that uses this compiler, or null.
226
+	 *
227
+	 * @var Core
228
+	 */
229
+	public $dwoo;
230
+
231
+	/**
232
+	 * Holds an instance of this class, used by getInstance when you don't
233
+	 * provide a custom compiler in order to save resources.
234
+	 *
235
+	 * @var Compiler
236
+	 */
237
+	protected static $instance;
238
+
239
+	/**
240
+	 * Token types.
241
+	 *
242
+	 * @var int
243
+	 */
244
+	const T_UNQUOTED_STRING = 1;
245
+	const T_NUMERIC         = 2;
246
+	const T_NULL            = 4;
247
+	const T_BOOL            = 8;
248
+	const T_MATH            = 16;
249
+	const T_BREAKCHAR       = 32;
250
+
251
+	/**
252
+	 * Compiler constructor.
253
+	 * saves the created instance so that child templates get the same one
254
+	 */
255
+	public function __construct()
256
+	{
257
+		self::$instance = $this;
258
+	}
259
+
260
+	/**
261
+	 * Sets the delimiters to use in the templates.
262
+	 * delimiters can be multi-character strings but should not be one of those as they will
263
+	 * make it very hard to work with templates or might even break the compiler entirely : "\", "$", "|", ":" and
264
+	 * finally "#" only if you intend to use config-vars with the #var# syntax.
265
+	 *
266
+	 * @param string $left  left delimiter
267
+	 * @param string $right right delimiter
268
+	 */
269
+	public function setDelimiters($left, $right)
270
+	{
271
+		$this->ld  = $left;
272
+		$this->rd  = $right;
273
+		$this->ldr = preg_quote($left, '/');
274
+		$this->rdr = preg_quote($right, '/');
275
+	}
276
+
277
+	/**
278
+	 * Returns the left and right template delimiters.
279
+	 *
280
+	 * @return array containing the left and the right delimiters
281
+	 */
282
+	public function getDelimiters()
283
+	{
284
+		return array($this->ld, $this->rd);
285
+	}
286
+
287
+	/**
288
+	 * Sets the way to handle nested comments, if set to true
289
+	 * {* foo {* some other *} comment *} will be stripped correctly.
290
+	 * if false it will remove {* foo {* some other *} and leave "comment *}" alone,
291
+	 * this is the default behavior
292
+	 *
293
+	 * @param bool $allow allow nested comments or not, defaults to true (but the default internal value is false)
294
+	 */
295
+	public function setNestedCommentsHandling($allow = true)
296
+	{
297
+		$this->allowNestedComments = (bool)$allow;
298
+	}
299
+
300
+	/**
301
+	 * Returns the nested comments handling setting.
302
+	 *
303
+	 * @see    setNestedCommentsHandling
304
+	 * @return bool true if nested comments are allowed
305
+	 */
306
+	public function getNestedCommentsHandling()
307
+	{
308
+		return $this->allowNestedComments;
309
+	}
310
+
311
+	/**
312
+	 * Sets the tag openings handling strictness, if set to true, template tags can
313
+	 * contain spaces before the first function/string/variable such as { $foo} is valid.
314
+	 * if set to false (default setting), { $foo} is invalid but that is however a good thing
315
+	 * as it allows css (i.e. #foo { color:red; }) to be parsed silently without triggering
316
+	 * an error, same goes for javascript.
317
+	 *
318
+	 * @param bool $allow true to allow loose handling, false to restore default setting
319
+	 */
320
+	public function setLooseOpeningHandling($allow = false)
321
+	{
322
+		$this->allowLooseOpenings = (bool)$allow;
323
+	}
324
+
325
+	/**
326
+	 * Returns the tag openings handling strictness setting.
327
+	 *
328
+	 * @see    setLooseOpeningHandling
329
+	 * @return bool true if loose tags are allowed
330
+	 */
331
+	public function getLooseOpeningHandling()
332
+	{
333
+		return $this->allowLooseOpenings;
334
+	}
335
+
336
+	/**
337
+	 * Changes the auto escape setting.
338
+	 * if enabled, the compiler will automatically html-escape variables,
339
+	 * unless they are passed through the safe function such as {$var|safe}
340
+	 * or {safe $var}
341
+	 * default setting is disabled/false
342
+	 *
343
+	 * @param bool $enabled set to true to enable, false to disable
344
+	 */
345
+	public function setAutoEscape($enabled)
346
+	{
347
+		$this->autoEscape = (bool)$enabled;
348
+	}
349
+
350
+	/**
351
+	 * Returns the auto escape setting.
352
+	 * default setting is disabled/false
353
+	 *
354
+	 * @return bool
355
+	 */
356
+	public function getAutoEscape()
357
+	{
358
+		return $this->autoEscape;
359
+	}
360
+
361
+	/**
362
+	 * Adds a preprocessor to the compiler, it will be called
363
+	 * before the template is compiled.
364
+	 *
365
+	 * @param mixed $callback either a valid callback to the preprocessor or a simple name if the autoload is set to
366
+	 *                        true
367
+	 * @param bool  $autoload if set to true, the preprocessor is auto-loaded from one of the plugin directories, else
368
+	 *                        you must provide a valid callback
369
+	 */
370
+	public function addPreProcessor($callback, $autoload = false)
371
+	{
372
+		if ($autoload) {
373
+			$name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', Core::toCamelCase($callback));
374
+			$class = Core::NAMESPACE_PLUGINS_PROCESSORS . $name;
375
+
376
+			if (class_exists($class)) {
377
+				$callback = array(new $class($this), 'process');
378
+			} elseif (function_exists($class)) {
379
+				$callback = $class;
380
+			} else {
381
+				$callback = array('autoload' => true, 'class' => $class, 'name' => $name);
382
+			}
383
+
384
+			$this->processors['pre'][] = $callback;
385
+		} else {
386
+			$this->processors['pre'][] = $callback;
387
+		}
388
+	}
389
+
390
+	/**
391
+	 * Removes a preprocessor from the compiler.
392
+	 *
393
+	 * @param mixed $callback either a valid callback to the preprocessor or a simple name if it was autoloaded
394
+	 */
395
+	public function removePreProcessor($callback)
396
+	{
397
+		if (($index = array_search($callback, $this->processors['pre'], true)) !== false) {
398
+			unset($this->processors['pre'][$index]);
399
+		} elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
400
+					$callback),
401
+				$this->processors['pre'], true)) !== false) {
402
+			unset($this->processors['pre'][$index]);
403
+		} else {
404
+			$class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
405
+			foreach ($this->processors['pre'] as $index => $proc) {
406
+				if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
407
+					unset($this->processors['pre'][$index]);
408
+					break;
409
+				}
410
+			}
411
+		}
412
+	}
413
+
414
+	/**
415
+	 * Adds a postprocessor to the compiler, it will be called
416
+	 * before the template is compiled.
417
+	 *
418
+	 * @param mixed $callback either a valid callback to the postprocessor or a simple name if the autoload is set to
419
+	 *                        true
420
+	 * @param bool  $autoload if set to true, the postprocessor is auto-loaded from one of the plugin directories, else
421
+	 *                        you must provide a valid callback
422
+	 */
423
+	public function addPostProcessor($callback, $autoload = false)
424
+	{
425
+		if ($autoload) {
426
+			$name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
427
+			$class = Core::NAMESPACE_PLUGINS_PROCESSORS . Core::toCamelCase($name);
428
+
429
+			if (class_exists($class)) {
430
+				$callback = array(new $class($this), 'process');
431
+			} elseif (function_exists($class)) {
432
+				$callback = $class;
433
+			} else {
434
+				$callback = array('autoload' => true, 'class' => $class, 'name' => $name);
435
+			}
436
+
437
+			$this->processors['post'][] = $callback;
438
+		} else {
439
+			$this->processors['post'][] = $callback;
440
+		}
441
+	}
442
+
443
+	/**
444
+	 * Removes a postprocessor from the compiler.
445
+	 *
446
+	 * @param mixed $callback either a valid callback to the postprocessor or a simple name if it was autoloaded
447
+	 */
448
+	public function removePostProcessor($callback)
449
+	{
450
+		if (($index = array_search($callback, $this->processors['post'], true)) !== false) {
451
+			unset($this->processors['post'][$index]);
452
+		} elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
453
+					$callback),
454
+				$this->processors['post'], true)) !== false) {
455
+			unset($this->processors['post'][$index]);
456
+		} else {
457
+			$class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
458
+			foreach ($this->processors['post'] as $index => $proc) {
459
+				if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
460
+					unset($this->processors['post'][$index]);
461
+					break;
462
+				}
463
+			}
464
+		}
465
+	}
466
+
467
+	/**
468
+	 * Internal function to autoload processors at runtime if required.
469
+	 *
470
+	 * @param string $class the class/function name
471
+	 * @param string $name  the plugin name (without Dwoo_Plugin_ prefix)
472
+	 *
473
+	 * @return array|string
474
+	 * @throws Exception
475
+	 */
476
+	protected function loadProcessor($class, $name)
477
+	{
478
+		if (!class_exists($class) && !function_exists($class)) {
479
+			try {
480
+				$this->getDwoo()->getLoader()->loadPlugin($name);
481
+			}
482
+			catch (Exception $e) {
483
+				throw new Exception('Processor ' . $name . ' could not be found in your plugin directories, please ensure it is in a file named ' . $name . '.php in the plugin directory');
484
+			}
485
+		}
486
+
487
+		if (class_exists($class)) {
488
+			return array(new $class($this), 'process');
489
+		}
490
+
491
+		if (function_exists($class)) {
492
+			return $class;
493
+		}
494
+
495
+		throw new Exception('Wrong processor name, when using autoload the processor must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Processor_name"');
496
+	}
497
+
498
+	/**
499
+	 * Adds an used plugin, this is reserved for use by the {template} plugin.
500
+	 * this is required so that plugin loading bubbles up from loaded
501
+	 * template files to the current one
502
+	 *
503
+	 * @private
504
+	 *
505
+	 * @param string $name function name
506
+	 * @param int    $type plugin type (Core::*_PLUGIN)
507
+	 */
508
+	public function addUsedPlugin($name, $type)
509
+	{
510
+		$this->usedPlugins[$name] = $type;
511
+	}
512
+
513
+	/**
514
+	 * Returns all the plugins this template uses.
515
+	 *
516
+	 * @private
517
+	 * @return  array the list of used plugins in the parsed template
518
+	 */
519
+	public function getUsedPlugins()
520
+	{
521
+		return $this->usedPlugins;
522
+	}
523
+
524
+	/**
525
+	 * Adds a template plugin, this is reserved for use by the {template} plugin.
526
+	 * this is required because the template functions are not declared yet
527
+	 * during compilation, so we must have a way of validating their argument
528
+	 * signature without using the reflection api
529
+	 *
530
+	 * @private
531
+	 *
532
+	 * @param string $name   function name
533
+	 * @param array  $params parameter array to help validate the function call
534
+	 * @param string $uuid   unique id of the function
535
+	 * @param string $body   function php code
536
+	 */
537
+	public function addTemplatePlugin($name, array $params, $uuid, $body = null)
538
+	{
539
+		$this->templatePlugins[$name] = array('params' => $params, 'body' => $body, 'uuid' => $uuid);
540
+	}
541
+
542
+	/**
543
+	 * Returns all the parsed sub-templates.
544
+	 *
545
+	 * @private
546
+	 * @return  array the parsed sub-templates
547
+	 */
548
+	public function getTemplatePlugins()
549
+	{
550
+		return $this->templatePlugins;
551
+	}
552
+
553
+	/**
554
+	 * Marks a template plugin as being called, which means its source must be included in the compiled template.
555
+	 *
556
+	 * @param string $name function name
557
+	 */
558
+	public function useTemplatePlugin($name)
559
+	{
560
+		$this->templatePlugins[$name]['called'] = true;
561
+	}
562
+
563
+	/**
564
+	 * Adds the custom plugins loaded into Dwoo to the compiler so it can load them.
565
+	 *
566
+	 * @see Core::addPlugin
567
+	 *
568
+	 * @param array $customPlugins an array of custom plugins
569
+	 */
570
+	public function setCustomPlugins(array $customPlugins)
571
+	{
572
+		$this->customPlugins = $customPlugins;
573
+	}
574
+
575
+	/**
576
+	 * Sets the security policy object to enforce some php security settings.
577
+	 * use this if untrusted persons can modify templates,
578
+	 * set it on the Dwoo object as it will be passed onto the compiler automatically
579
+	 *
580
+	 * @param SecurityPolicy $policy the security policy object
581
+	 */
582
+	public function setSecurityPolicy(SecurityPolicy $policy = null)
583
+	{
584
+		$this->securityPolicy = $policy;
585
+	}
586
+
587
+	/**
588
+	 * Returns the current security policy object or null by default.
589
+	 *
590
+	 * @return SecurityPolicy|null the security policy object if any
591
+	 */
592
+	public function getSecurityPolicy()
593
+	{
594
+		return $this->securityPolicy;
595
+	}
596
+
597
+	/**
598
+	 * Sets the pointer position.
599
+	 *
600
+	 * @param int  $position the new pointer position
601
+	 * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
602
+	 */
603
+	public function setPointer($position, $isOffset = false)
604
+	{
605
+		if ($isOffset) {
606
+			$this->pointer += $position;
607
+		} else {
608
+			$this->pointer = $position;
609
+		}
610
+	}
611
+
612
+	/**
613
+	 * Returns the current pointer position, only available during compilation of a template.
614
+	 *
615
+	 * @return int
616
+	 */
617
+	public function getPointer()
618
+	{
619
+		return $this->pointer;
620
+	}
621
+
622
+	/**
623
+	 * Sets the line number.
624
+	 *
625
+	 * @param int  $number   the new line number
626
+	 * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
627
+	 */
628
+	public function setLine($number, $isOffset = false)
629
+	{
630
+		if ($isOffset) {
631
+			$this->line += $number;
632
+		} else {
633
+			$this->line = $number;
634
+		}
635
+	}
636
+
637
+	/**
638
+	 * Returns the current line number, only available during compilation of a template.
639
+	 *
640
+	 * @return int
641
+	 */
642
+	public function getLine()
643
+	{
644
+		return $this->line;
645
+	}
646
+
647
+	/**
648
+	 * Returns the dwoo object that initiated this template compilation, only available during compilation of a
649
+	 * template.
650
+	 *
651
+	 * @return Core
652
+	 */
653
+	public function getDwoo()
654
+	{
655
+		return $this->dwoo;
656
+	}
657
+
658
+	/**
659
+	 * Overwrites the template that is being compiled.
660
+	 *
661
+	 * @param string $newSource   the template source that must replace the current one
662
+	 * @param bool   $fromPointer if set to true, only the source from the current pointer position is replaced
663
+	 *
664
+	 * @return void
665
+	 */
666
+	public function setTemplateSource($newSource, $fromPointer = false)
667
+	{
668
+		if ($fromPointer === true) {
669
+			$this->templateSource = substr($this->templateSource, 0, $this->pointer) . $newSource;
670
+		} else {
671
+			$this->templateSource = $newSource;
672
+		}
673
+	}
674
+
675
+	/**
676
+	 * Returns the template that is being compiled.
677
+	 *
678
+	 * @param mixed $fromPointer if set to true, only the source from the current pointer
679
+	 *                           position is returned, if a number is given it overrides the current pointer
680
+	 *
681
+	 * @return string the template or partial template
682
+	 */
683
+	public function getTemplateSource($fromPointer = false)
684
+	{
685
+		if ($fromPointer === true) {
686
+			return substr($this->templateSource, $this->pointer);
687
+		} elseif (is_numeric($fromPointer)) {
688
+			return substr($this->templateSource, $fromPointer);
689
+		} else {
690
+			return $this->templateSource;
691
+		}
692
+	}
693
+
694
+	/**
695
+	 * Resets the compilation pointer, effectively restarting the compilation process.
696
+	 * this is useful if a plugin modifies the template source since it might need to be recompiled
697
+	 */
698
+	public function recompile()
699
+	{
700
+		$this->setPointer(0);
701
+	}
702
+
703
+	/**
704
+	 * Compiles the provided string down to php code.
705
+	 *
706
+	 * @param Core      $dwoo
707
+	 * @param ITemplate $template the template to compile
708
+	 *
709
+	 * @return string a compiled php string
710
+	 * @throws CompilationException
711
+	 */
712
+	public function compile(Core $dwoo, ITemplate $template)
713
+	{
714
+		// init vars
715
+		//		$compiled = '';
716
+		$tpl                  = $template->getSource();
717
+		$ptr                  = 0;
718
+		$this->dwoo           = $dwoo;
719
+		$this->template       = $template;
720
+		$this->templateSource = &$tpl;
721
+		$this->pointer        = &$ptr;
722
+
723
+		while (true) {
724
+			// if pointer is at the beginning, reset everything, that allows a plugin to externally reset the compiler if everything must be reparsed
725
+			if ($ptr === 0) {
726
+				// resets variables
727
+				$this->usedPlugins     = array();
728
+				$this->data            = array();
729
+				$this->scope           = &$this->data;
730
+				$this->scopeTree       = array();
731
+				$this->stack           = array();
732
+				$this->line            = 1;
733
+				$this->templatePlugins = array();
734
+				// add top level block
735
+				$compiled                 = $this->addBlock('TopLevelBlock', array(), 0);
736
+				$this->stack[0]['buffer'] = '';
737
+
738
+				if ($this->debug) {
739
+					echo "\n";
740
+					echo 'COMPILER INIT' . "\n";
741
+				}
742
+
743
+				if ($this->debug) {
744
+					echo 'PROCESSING PREPROCESSORS (' . count($this->processors['pre']) . ')' . "\n";
745
+				}
746
+
747
+				// runs preprocessors
748
+				foreach ($this->processors['pre'] as $preProc) {
749
+					if (is_array($preProc) && isset($preProc['autoload'])) {
750
+						$preProc = $this->loadProcessor($preProc['class'], $preProc['name']);
751
+					}
752
+					if (is_array($preProc) && $preProc[0] instanceof Processor) {
753
+						$tpl = call_user_func($preProc, $tpl);
754
+					} else {
755
+						$tpl = call_user_func($preProc, $this, $tpl);
756
+					}
757
+				}
758
+				unset($preProc);
759
+
760
+				// show template source if debug
761
+				if ($this->debug) {
762
+					echo '<pre>'.print_r(htmlentities($tpl), true).'</pre>'."\n";
763
+				}
764
+
765
+				// strips php tags if required by the security policy
766
+				if ($this->securityPolicy !== null) {
767
+					$search = array('{<\?php.*?\?>}');
768
+					if (ini_get('short_open_tags')) {
769
+						$search = array('{<\?.*?\?>}', '{<%.*?%>}');
770
+					}
771
+					switch ($this->securityPolicy->getPhpHandling()) {
772
+						case SecurityPolicy::PHP_ALLOW:
773
+							break;
774
+						case SecurityPolicy::PHP_ENCODE:
775
+							$tpl = preg_replace_callback($search, array($this, 'phpTagEncodingHelper'), $tpl);
776
+							break;
777
+						case SecurityPolicy::PHP_REMOVE:
778
+							$tpl = preg_replace($search, '', $tpl);
779
+					}
780
+				}
781
+			}
782
+
783
+			$pos = strpos($tpl, $this->ld, $ptr);
784
+
785
+			if ($pos === false) {
786
+				$this->push(substr($tpl, $ptr), 0);
787
+				break;
788
+			} elseif (substr($tpl, $pos - 1, 1) === '\\' && substr($tpl, $pos - 2, 1) !== '\\') {
789
+				$this->push(substr($tpl, $ptr, $pos - $ptr - 1) . $this->ld);
790
+				$ptr = $pos + strlen($this->ld);
791
+			} elseif (preg_match('/^' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . 'literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', substr($tpl, $pos), $litOpen)) {
792
+				if (!preg_match('/' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . '\/literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', $tpl, $litClose, PREG_OFFSET_CAPTURE, $pos)) {
793
+					throw new CompilationException($this, 'The {literal} blocks must be closed explicitly with {/literal}');
794
+				}
795
+				$endpos = $litClose[0][1];
796
+				$this->push(substr($tpl, $ptr, $pos - $ptr) . substr($tpl, $pos + strlen($litOpen[0]), $endpos - $pos - strlen($litOpen[0])));
797
+				$ptr = $endpos + strlen($litClose[0][0]);
798
+			} else {
799
+				if (substr($tpl, $pos - 2, 1) === '\\' && substr($tpl, $pos - 1, 1) === '\\') {
800
+					$this->push(substr($tpl, $ptr, $pos - $ptr - 1));
801
+					$ptr = $pos;
802
+				}
803
+
804
+				$this->push(substr($tpl, $ptr, $pos - $ptr));
805
+				$ptr = $pos;
806
+
807
+				$pos += strlen($this->ld);
808
+				if ($this->allowLooseOpenings) {
809
+					while (substr($tpl, $pos, 1) === ' ') {
810
+						$pos += 1;
811
+					}
812
+				} else {
813
+					if (substr($tpl, $pos, 1) === ' ' || substr($tpl, $pos, 1) === "\r" || substr($tpl, $pos, 1) === "\n" || substr($tpl, $pos, 1) === "\t") {
814
+						$ptr = $pos;
815
+						$this->push($this->ld);
816
+						continue;
817
+					}
818
+				}
819
+
820
+				// check that there is an end tag present
821
+				if (strpos($tpl, $this->rd, $pos) === false) {
822
+					throw new CompilationException($this, 'A template tag was not closed, started with "' . substr($tpl, $ptr, 30) . '"');
823
+				}
824
+
825
+				$ptr += strlen($this->ld);
826
+				$subptr = $ptr;
827
+
828
+				while (true) {
829
+					$parsed = $this->parse($tpl, $subptr, null, false, 'root', $subptr);
830
+
831
+					// reload loop if the compiler was reset
832
+					if ($ptr === 0) {
833
+						continue 2;
834
+					}
835
+
836
+					$len = $subptr - $ptr;
837
+					$this->push($parsed, substr_count(substr($tpl, $ptr, $len), "\n"));
838
+					$ptr += $len;
839
+
840
+					if ($parsed === false) {
841
+						break;
842
+					}
843
+				}
844
+			}
845
+		}
846
+
847
+		$compiled .= $this->removeBlock('TopLevelBlock');
848
+
849
+		if ($this->debug) {
850
+			echo 'PROCESSING POSTPROCESSORS' . "\n";
851
+		}
852
+
853
+		foreach ($this->processors['post'] as $postProc) {
854
+			if (is_array($postProc) && isset($postProc['autoload'])) {
855
+				$postProc = $this->loadProcessor($postProc['class'], $postProc['name']);
856
+			}
857
+			if (is_array($postProc) && $postProc[0] instanceof Processor) {
858
+				$compiled = call_user_func($postProc, $compiled);
859
+			} else {
860
+				$compiled = call_user_func($postProc, $this, $compiled);
861
+			}
862
+		}
863
+		unset($postProc);
864
+
865
+		if ($this->debug) {
866
+			echo 'COMPILATION COMPLETE : MEM USAGE : ' . memory_get_usage() . "\n";
867
+		}
868
+
869
+		$output = "<?php\n/* template head */\n";
870
+
871
+		// build plugin preloader
872
+		foreach ($this->getUsedPlugins() as $plugin => $type) {
873
+			if ($type & Core::CUSTOM_PLUGIN) {
874
+				continue;
875
+			}
876
+
877
+			switch ($type) {
878
+				case Core::CLASS_PLUGIN:
879
+				case Core::CLASS_PLUGIN + Core::BLOCK_PLUGIN:
880
+					if (class_exists('Plugin' . $plugin) !== false) {
881
+						$output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
882
+						"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
883
+					} else {
884
+						$output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_BLOCKS . "Plugin" . $plugin . "')===false)".
885
+						"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
886
+					}
887
+					break;
888
+				case Core::CLASS_PLUGIN + Core::FUNC_PLUGIN:
889
+					if (class_exists('Plugin' . $plugin) !== false) {
890
+						$output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
891
+							"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
892
+					} else {
893
+						$output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
894
+							"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
895
+					}
896
+					break;
897
+				case Core::FUNC_PLUGIN:
898
+					if (function_exists('Plugin' . $plugin) !== false) {
899
+						$output .= "if (function_exists('" . "Plugin" . $plugin . "')===false)".
900
+						"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
901
+					} else {
902
+						$output .= "if (function_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
903
+						"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
904
+					}
905
+					break;
906
+				case Core::SMARTY_MODIFIER:
907
+					$output .= "if (function_exists('smarty_modifier_$plugin')===false)".
908
+					"\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
909
+					break;
910
+				case Core::SMARTY_FUNCTION:
911
+					$output .= "if (function_exists('smarty_function_$plugin')===false)".
912
+					"\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
913
+					break;
914
+				case Core::SMARTY_BLOCK:
915
+					$output .= "if (function_exists('smarty_block_$plugin')===false)".
916
+					"\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
917
+					break;
918
+				case Core::PROXY_PLUGIN:
919
+					$output .= $this->getDwoo()->getPluginProxy()->getLoader($plugin);
920
+					break;
921
+				default:
922
+					throw new CompilationException($this, 'Type error for ' . $plugin . ' with type' . $type);
923
+			}
924
+		}
925
+
926
+		foreach ($this->templatePlugins as $function => $attr) {
927
+			if (isset($attr['called']) && $attr['called'] === true && !isset($attr['checked'])) {
928
+				$this->resolveSubTemplateDependencies($function);
929
+			}
930
+		}
931
+		foreach ($this->templatePlugins as $function) {
932
+			if (isset($function['called']) && $function['called'] === true) {
933
+				$output .= $function['body'] . PHP_EOL;
934
+			}
935
+		}
936
+
937
+		$output .= $compiled . "\n?>";
938
+
939
+		$output = preg_replace('/(?<!;|\}|\*\/|\n|\{)(\s*' . preg_quote(self::PHP_CLOSE, '/') . preg_quote(self::PHP_OPEN, '/') . ')/', ";\n", $output);
940
+		$output = str_replace(self::PHP_CLOSE . self::PHP_OPEN, "\n", $output);
941
+
942
+		// handle <?xml tag at the beginning
943
+		$output = preg_replace('#(/\* template body \*/ \?>\s*)<\?xml#is', '$1<?php echo \'<?xml\'; ?>', $output);
944
+
945
+		// add another line break after PHP closing tags that have a line break following,
946
+		// as we do not know whether it's intended, and PHP will strip it otherwise
947
+		$output = preg_replace('/(?<!"|<\?xml)\s*\?>\n/', '$0' . "\n", $output);
948
+
949
+		if ($this->debug) {
950
+			echo '=============================================================================================' . "\n";
951
+			$lines = preg_split('{\r\n|\n|<br />}', $output);
952
+			array_shift($lines);
953
+			foreach ($lines as $i => $line) {
954
+				echo ($i + 1) . '. ' . $line . "\r\n";
955
+			}
956
+			echo '=============================================================================================' . "\n";
957
+		}
958
+
959
+		$this->template = $this->dwoo = null;
960
+		$tpl            = null;
961
+
962
+		return $output;
963
+	}
964
+
965
+	/**
966
+	 * Checks what sub-templates are used in every sub-template so that we're sure they are all compiled.
967
+	 *
968
+	 * @param string $function the sub-template name
969
+	 */
970
+	protected function resolveSubTemplateDependencies($function)
971
+	{
972
+		if ($this->debug) {
973
+			echo 'Compiler::' . __FUNCTION__ . "\n";
974
+		}
975
+
976
+		$body = $this->templatePlugins[$function]['body'];
977
+		foreach ($this->templatePlugins as $func => $attr) {
978
+			if ($func !== $function && !isset($attr['called']) && strpos($body, Core::NAMESPACE_PLUGINS_FUNCTIONS .
979
+			'Plugin' . Core::toCamelCase($func)) !== false) {
980
+				$this->templatePlugins[$func]['called'] = true;
981
+				$this->resolveSubTemplateDependencies($func);
982
+			}
983
+		}
984
+		$this->templatePlugins[$function]['checked'] = true;
985
+	}
986
+
987
+	/**
988
+	 * Adds compiled content to the current block.
989
+	 *
990
+	 * @param string $content   the content to push
991
+	 * @param int    $lineCount newlines count in content, optional
992
+	 *
993
+	 * @throws CompilationException
994
+	 */
995
+	public function push($content, $lineCount = null)
996
+	{
997
+		if ($lineCount === null) {
998
+			$lineCount = substr_count($content, "\n");
999
+		}
1000
+
1001
+		if ($this->curBlock['buffer'] === null && count($this->stack) > 1) {
1002
+			// buffer is not initialized yet (the block has just been created)
1003
+			$this->stack[count($this->stack) - 2]['buffer'] .= (string)$content;
1004
+			$this->curBlock['buffer'] = '';
1005
+		} else {
1006
+			if (!isset($this->curBlock['buffer'])) {
1007
+				throw new CompilationException($this, 'The template has been closed too early, you probably have an extra block-closing tag somewhere');
1008
+			}
1009
+			// append current content to current block's buffer
1010
+			$this->curBlock['buffer'] .= (string)$content;
1011
+		}
1012
+		$this->line += $lineCount;
1013
+	}
1014
+
1015
+	/**
1016
+	 * Sets the scope.
1017
+	 * set to null if the scope becomes "unstable" (i.e. too variable or unknown) so that
1018
+	 * variables are compiled in a more evaluative way than just $this->scope['key']
1019
+	 *
1020
+	 * @param mixed $scope    a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1021
+	 * @param bool  $absolute if true, the scope is set from the top level scope and not from the current scope
1022
+	 *
1023
+	 * @return array the current scope tree
1024
+	 */
1025
+	public function setScope($scope, $absolute = false)
1026
+	{
1027
+		$old = $this->scopeTree;
1028
+
1029
+		if ($scope === null) {
1030
+			unset($this->scope);
1031
+			$this->scope = null;
1032
+		}
1033
+
1034
+		if (is_array($scope) === false) {
1035
+			$scope = explode('.', $scope);
1036
+		}
1037
+
1038
+		if ($absolute === true) {
1039
+			$this->scope     = &$this->data;
1040
+			$this->scopeTree = array();
1041
+		}
1042
+
1043
+		while (($bit = array_shift($scope)) !== null) {
1044
+			if ($bit === '_parent' || $bit === '_') {
1045
+				array_pop($this->scopeTree);
1046
+				reset($this->scopeTree);
1047
+				$this->scope = &$this->data;
1048
+				$cnt         = count($this->scopeTree);
1049
+				for ($i = 0; $i < $cnt; ++ $i) {
1050
+					$this->scope = &$this->scope[$this->scopeTree[$i]];
1051
+				}
1052
+			} elseif ($bit === '_root' || $bit === '__') {
1053
+				$this->scope     = &$this->data;
1054
+				$this->scopeTree = array();
1055
+			} elseif (isset($this->scope[$bit])) {
1056
+				$this->scope       = &$this->scope[$bit];
1057
+				$this->scopeTree[] = $bit;
1058
+			} else {
1059
+				$this->scope[$bit] = array();
1060
+				$this->scope       = &$this->scope[$bit];
1061
+				$this->scopeTree[] = $bit;
1062
+			}
1063
+		}
1064
+
1065
+		return $old;
1066
+	}
1067
+
1068
+	/**
1069
+	 * Adds a block to the top of the block stack.
1070
+	 *
1071
+	 * @param string $type      block type (name)
1072
+	 * @param array  $params    the parameters array
1073
+	 * @param int    $paramtype the parameters type (see mapParams), 0, 1 or 2
1074
+	 *
1075
+	 * @return string the preProcessing() method's output
1076
+	 */
1077
+	public function addBlock($type, array $params, $paramtype)
1078
+	{
1079
+		if ($this->debug) {
1080
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1081
+		}
1082
+
1083
+		$class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type);
1084
+		if (class_exists($class) === false) {
1085
+			$this->getDwoo()->getLoader()->loadPlugin($type);
1086
+		}
1087
+		$params = $this->mapParams($params, array($class, 'init'), $paramtype);
1088
+
1089
+		$this->stack[]  = array(
1090
+			'type'   => $type,
1091
+			'params' => $params,
1092
+			'custom' => false,
1093
+			'class'  => $class,
1094
+			'buffer' => null
1095
+		);
1096
+		$this->curBlock = &$this->stack[count($this->stack) - 1];
1097
+
1098
+		return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1099
+	}
1100
+
1101
+	/**
1102
+	 * Adds a custom block to the top of the block stack.
1103
+	 *
1104
+	 * @param string $type      block type (name)
1105
+	 * @param array  $params    the parameters array
1106
+	 * @param int    $paramtype the parameters type (see mapParams), 0, 1 or 2
1107
+	 *
1108
+	 * @return string the preProcessing() method's output
1109
+	 */
1110
+	public function addCustomBlock($type, array $params, $paramtype)
1111
+	{
1112
+		$callback = $this->customPlugins[$type]['callback'];
1113
+		if (is_array($callback)) {
1114
+			$class = is_object($callback[0]) ? get_class($callback[0]) : $callback[0];
1115
+		} else {
1116
+			$class = $callback;
1117
+		}
1118
+
1119
+		$params = $this->mapParams($params, array($class, 'init'), $paramtype);
1120
+
1121
+		$this->stack[]  = array(
1122
+			'type'   => $type,
1123
+			'params' => $params,
1124
+			'custom' => true,
1125
+			'class'  => $class,
1126
+			'buffer' => null
1127
+		);
1128
+		$this->curBlock = &$this->stack[count($this->stack) - 1];
1129
+
1130
+		return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1131
+	}
1132
+
1133
+	/**
1134
+	 * Injects a block at the top of the plugin stack without calling its preProcessing method.
1135
+	 * used by {else} blocks to re-add themselves after having closed everything up to their parent
1136
+	 *
1137
+	 * @param string $type   block type (name)
1138
+	 * @param array  $params parameters array
1139
+	 */
1140
+	public function injectBlock($type, array $params)
1141
+	{
1142
+		if ($this->debug) {
1143
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1144
+		}
1145
+
1146
+		$class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type);
1147
+		if (class_exists($class) === false) {
1148
+			$this->getDwoo()->getLoader()->loadPlugin($type);
1149
+		}
1150
+		$this->stack[]  = array(
1151
+			'type'   => $type,
1152
+			'params' => $params,
1153
+			'custom' => false,
1154
+			'class'  => $class,
1155
+			'buffer' => null
1156
+		);
1157
+		$this->curBlock = &$this->stack[count($this->stack) - 1];
1158
+	}
1159
+
1160
+	/**
1161
+	 * Removes the closest-to-top block of the given type and all other
1162
+	 * blocks encountered while going down the block stack.
1163
+	 *
1164
+	 * @param string $type block type (name)
1165
+	 *
1166
+	 * @return string the output of all postProcessing() method's return values of the closed blocks
1167
+	 * @throws CompilationException
1168
+	 */
1169
+	public function removeBlock($type)
1170
+	{
1171
+		if ($this->debug) {
1172
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1173
+		}
1174
+
1175
+		$output = '';
1176
+
1177
+		$pluginType = $this->getPluginType($type);
1178
+		if ($pluginType & Core::SMARTY_BLOCK) {
1179
+			$type = 'Smartyinterface';
1180
+		}
1181
+		while (true) {
1182
+			while ($top = array_pop($this->stack)) {
1183
+				if ($top['custom']) {
1184
+					$class = $top['class'];
1185
+				} else {
1186
+					$class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($top['type']);
1187
+				}
1188
+				if (count($this->stack)) {
1189
+					$this->curBlock = &$this->stack[count($this->stack) - 1];
1190
+					$this->push(call_user_func(array(
1191
+						$class,
1192
+						'postProcessing'
1193
+					), $this, $top['params'], '', '', $top['buffer']), 0);
1194
+				} else {
1195
+					$null           = null;
1196
+					$this->curBlock = &$null;
1197
+					$output         = call_user_func(
1198
+						array(
1199
+						$class,
1200
+						'postProcessing'
1201
+						), $this, $top['params'], '', '', $top['buffer']
1202
+					);
1203
+				}
1204
+
1205
+				if ($top['type'] === $type) {
1206
+					break 2;
1207
+				}
1208
+			}
1209
+
1210
+			throw new CompilationException($this, 'Syntax malformation, a block of type "' . $type . '" was closed but was not opened');
1211
+			break;
1212
+		}
1213
+
1214
+		return $output;
1215
+	}
1216
+
1217
+	/**
1218
+	 * Returns a reference to the first block of the given type encountered and
1219
+	 * optionally closes all blocks until it finds it
1220
+	 * this is mainly used by {else} plugins to close everything that was opened
1221
+	 * between their parent and themselves.
1222
+	 *
1223
+	 * @param string $type       the block type (name)
1224
+	 * @param bool   $closeAlong whether to close all blocks encountered while going down the block stack or not
1225
+	 *
1226
+	 * @return mixed &array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
1227
+	 *               'custom'=>bool defining whether it's a custom plugin or not, for internal use)
1228
+	 * @throws CompilationException
1229
+	 */
1230
+	public function &findBlock($type, $closeAlong = false)
1231
+	{
1232
+		if ($closeAlong === true) {
1233
+			while ($b = end($this->stack)) {
1234
+				if ($b['type'] === $type) {
1235
+					return $this->stack[key($this->stack)];
1236
+				}
1237
+				$this->push($this->removeTopBlock(), 0);
1238
+			}
1239
+		} else {
1240
+			end($this->stack);
1241
+			while ($b = current($this->stack)) {
1242
+				if ($b['type'] === $type) {
1243
+					return $this->stack[key($this->stack)];
1244
+				}
1245
+				prev($this->stack);
1246
+			}
1247
+		}
1248
+
1249
+		throw new CompilationException($this, 'A parent block of type "' . $type . '" is required and can not be found');
1250
+	}
1251
+
1252
+	/**
1253
+	 * Returns a reference to the current block array.
1254
+	 *
1255
+	 * @return array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
1256
+	 *                'custom'=>bool defining whether it's a custom plugin or not, for internal use)
1257
+	 */
1258
+	public function &getCurrentBlock()
1259
+	{
1260
+		return $this->curBlock;
1261
+	}
1262
+
1263
+	/**
1264
+	 * Removes the block at the top of the stack and calls its postProcessing() method.
1265
+	 *
1266
+	 * @return string the postProcessing() method's output
1267
+	 * @throws CompilationException
1268
+	 */
1269
+	public function removeTopBlock()
1270
+	{
1271
+		if ($this->debug) {
1272
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1273
+		}
1274
+
1275
+		$o = array_pop($this->stack);
1276
+		if ($o === null) {
1277
+			throw new CompilationException($this, 'Syntax malformation, a block of unknown type was closed but was not opened.');
1278
+		}
1279
+		if ($o['custom']) {
1280
+			$class = $o['class'];
1281
+		} else {
1282
+			$class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($o['type']);
1283
+		}
1284
+
1285
+		$this->curBlock = &$this->stack[count($this->stack) - 1];
1286
+
1287
+		return call_user_func(array($class, 'postProcessing'), $this, $o['params'], '', '', $o['buffer']);
1288
+	}
1289
+
1290
+	/**
1291
+	 * Returns the compiled parameters (for example a variable's compiled parameter will be "$this->scope['key']") out
1292
+	 * of the given parameter array.
1293
+	 *
1294
+	 * @param array $params parameter array
1295
+	 *
1296
+	 * @return array filtered parameters
1297
+	 */
1298
+	public function getCompiledParams(array $params)
1299
+	{
1300
+		foreach ($params as $k => $p) {
1301
+			if (is_array($p)) {
1302
+				$params[$k] = $p[0];
1303
+			}
1304
+		}
1305
+
1306
+		return $params;
1307
+	}
1308
+
1309
+	/**
1310
+	 * Returns the real parameters (for example a variable's real parameter will be its key, etc) out of the given
1311
+	 * parameter array.
1312
+	 *
1313
+	 * @param array $params parameter array
1314
+	 *
1315
+	 * @return array filtered parameters
1316
+	 */
1317
+	public function getRealParams(array $params)
1318
+	{
1319
+		foreach ($params as $k => $p) {
1320
+			if (is_array($p)) {
1321
+				$params[$k] = $p[1];
1322
+			}
1323
+		}
1324
+
1325
+		return $params;
1326
+	}
1327
+
1328
+	/**
1329
+	 * Returns the token of each parameter out of the given parameter array.
1330
+	 *
1331
+	 * @param array $params parameter array
1332
+	 *
1333
+	 * @return array tokens
1334
+	 */
1335
+	public function getParamTokens(array $params)
1336
+	{
1337
+		foreach ($params as $k => $p) {
1338
+			if (is_array($p)) {
1339
+				$params[$k] = isset($p[2]) ? $p[2] : 0;
1340
+			}
1341
+		}
1342
+
1343
+		return $params;
1344
+	}
1345
+
1346
+	/**
1347
+	 * Entry point of the parser, it redirects calls to other parse* functions.
1348
+	 *
1349
+	 * @param string $in            the string within which we must parse something
1350
+	 * @param int    $from          the starting offset of the parsed area
1351
+	 * @param int    $to            the ending offset of the parsed area
1352
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
1353
+	 *                              default
1354
+	 * @param string $curBlock      the current parser-block being processed
1355
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
1356
+	 *                              or null by default
1357
+	 *
1358
+	 * @return string parsed values
1359
+	 * @throws CompilationException
1360
+	 */
1361
+	protected function parse($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1362
+	{
1363
+		if ($this->debug) {
1364
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1365
+		}
1366
+
1367
+		if ($to === null) {
1368
+			$to = strlen($in);
1369
+		}
1370
+		$first = substr($in, $from, 1);
1371
+
1372
+		if ($first === false) {
1373
+			throw new CompilationException($this, 'Unexpected EOF, a template tag was not closed');
1374
+		}
1375
+
1376
+		while ($first === ' ' || $first === "\n" || $first === "\t" || $first === "\r") {
1377
+			if ($curBlock === 'root' && substr($in, $from, strlen($this->rd)) === $this->rd) {
1378
+				// end template tag
1379
+				$pointer += strlen($this->rd);
1380
+				if ($this->debug) {
1381
+					echo 'TEMPLATE PARSING ENDED' . "\n";
1382
+				}
1383
+
1384
+				return false;
1385
+			}
1386
+			++ $from;
1387
+			if ($pointer !== null) {
1388
+				++ $pointer;
1389
+			}
1390
+			if ($from >= $to) {
1391
+				if (is_array($parsingParams)) {
1392
+					return $parsingParams;
1393
+				} else {
1394
+					return '';
1395
+				}
1396
+			}
1397
+			$first = $in[$from];
1398
+		}
1399
+
1400
+		$substr = substr($in, $from, $to - $from);
1401
+
1402
+		if ($this->debug) {
1403
+			echo 'PARSE CALL : PARSING "' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . '" @ ' . $from . ':' . $to . ' in ' . $curBlock . ' : pointer=' . $pointer . "\n";
1404
+		}
1405
+		$parsed = '';
1406
+
1407
+		if ($curBlock === 'root' && $first === '*') {
1408
+			$src      = $this->getTemplateSource();
1409
+			$startpos = $this->getPointer() - strlen($this->ld);
1410
+			if (substr($src, $startpos, strlen($this->ld)) === $this->ld) {
1411
+				if ($startpos > 0) {
1412
+					do {
1413
+						$char = substr($src, -- $startpos, 1);
1414
+						if ($char == "\n") {
1415
+							++ $startpos;
1416
+							$whitespaceStart = true;
1417
+							break;
1418
+						}
1419
+					}
1420
+					while ($startpos > 0 && ($char == ' ' || $char == "\t"));
1421
+				}
1422
+
1423
+				if (!isset($whitespaceStart)) {
1424
+					$startpos = $this->getPointer();
1425
+				} else {
1426
+					$pointer -= $this->getPointer() - $startpos;
1427
+				}
1428
+
1429
+				if ($this->allowNestedComments && strpos($src, $this->ld . '*', $this->getPointer()) !== false) {
1430
+					$comOpen  = $this->ld . '*';
1431
+					$comClose = '*' . $this->rd;
1432
+					$level    = 1;
1433
+					$ptr      = $this->getPointer();
1434
+
1435
+					while ($level > 0 && $ptr < strlen($src)) {
1436
+						$open  = strpos($src, $comOpen, $ptr);
1437
+						$close = strpos($src, $comClose, $ptr);
1438
+
1439
+						if ($open !== false && $close !== false) {
1440
+							if ($open < $close) {
1441
+								$ptr = $open + strlen($comOpen);
1442
+								++ $level;
1443
+							} else {
1444
+								$ptr = $close + strlen($comClose);
1445
+								-- $level;
1446
+							}
1447
+						} elseif ($open !== false) {
1448
+							$ptr = $open + strlen($comOpen);
1449
+							++ $level;
1450
+						} elseif ($close !== false) {
1451
+							$ptr = $close + strlen($comClose);
1452
+							-- $level;
1453
+						} else {
1454
+							$ptr = strlen($src);
1455
+						}
1456
+					}
1457
+					$endpos = $ptr - strlen('*' . $this->rd);
1458
+				} else {
1459
+					$endpos = strpos($src, '*' . $this->rd, $startpos);
1460
+					if ($endpos == false) {
1461
+						throw new CompilationException($this, 'Un-ended comment');
1462
+					}
1463
+				}
1464
+				$pointer += $endpos - $startpos + strlen('*' . $this->rd);
1465
+				if (isset($whitespaceStart) && preg_match('#^[\t ]*\r?\n#', substr($src, $endpos + strlen('*' . $this->rd)), $m)) {
1466
+					$pointer += strlen($m[0]);
1467
+					$this->curBlock['buffer'] = substr($this->curBlock['buffer'], 0, strlen($this->curBlock['buffer']) - ($this->getPointer() - $startpos - strlen($this->ld)));
1468
+				}
1469
+
1470
+				return false;
1471
+			}
1472
+		}
1473
+
1474
+		if ($first === '$') {
1475
+			// var
1476
+			$out    = $this->parseVar($in, $from, $to, $parsingParams, $curBlock, $pointer);
1477
+			$parsed = 'var';
1478
+		} elseif ($first === '%' && preg_match('#^%[a-z_\\\\]#i', $substr)) {
1479
+			// Short constant
1480
+			$out = $this->parseConst($in, $from, $to, $parsingParams, $curBlock, $pointer);
1481
+		} elseif (($first === '"' || $first === "'") && !(is_array($parsingParams) && preg_match('#^([\'"])[a-z0-9_]+\1\s*=>?(?:\s+|[^=])#i', $substr))) {
1482
+			// string
1483
+			$out = $this->parseString($in, $from, $to, $parsingParams, $curBlock, $pointer);
1484
+		} elseif (preg_match('/^\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?(' . (is_array($parsingParams) || $curBlock != 'root' ? '' : '\s+[^(]|') . '\s*\(|\s*' . $this->rdr . '|\s*;)/i', $substr)) {
1485
+			// func
1486
+			$out    = $this->parseFunction($in, $from, $to, $parsingParams, $curBlock, $pointer);
1487
+			$parsed = 'func';
1488
+		} elseif ($first === ';') {
1489
+			// instruction end
1490
+			if ($this->debug) {
1491
+				echo 'END OF INSTRUCTION' . "\n";
1492
+			}
1493
+			if ($pointer !== null) {
1494
+				++ $pointer;
1495
+			}
1496
+
1497
+			return $this->parse($in, $from + 1, $to, false, 'root', $pointer);
1498
+		} elseif ($curBlock === 'root' && preg_match('#^/([a-z_][a-z0-9_]*)?#i', $substr, $match)) {
1499
+			// close block
1500
+			if (!empty($match[1]) && $match[1] == 'else') {
1501
+				throw new CompilationException($this, 'Else blocks must not be closed explicitly, they are automatically closed when their parent block is closed');
1502
+			}
1503
+			if (!empty($match[1]) && $match[1] == 'elseif') {
1504
+				throw new CompilationException($this, 'Elseif blocks must not be closed explicitly, they are automatically closed when their parent block is closed or a new else/elseif block is declared after them');
1505
+			}
1506
+			if ($pointer !== null) {
1507
+				$pointer += strlen($match[0]);
1508
+			}
1509
+			if (empty($match[1])) {
1510
+				if ($this->curBlock['type'] == 'else' || $this->curBlock['type'] == 'elseif') {
1511
+					$pointer -= strlen($match[0]);
1512
+				}
1513
+				if ($this->debug) {
1514
+					echo 'TOP BLOCK CLOSED' . "\n";
1515
+				}
1516
+
1517
+				return $this->removeTopBlock();
1518
+			} else {
1519
+				if ($this->debug) {
1520
+					echo 'BLOCK OF TYPE ' . $match[1] . ' CLOSED' . "\n";
1521
+				}
1522
+
1523
+				return $this->removeBlock($match[1]);
1524
+			}
1525
+		} elseif ($curBlock === 'root' && substr($substr, 0, strlen($this->rd)) === $this->rd) {
1526
+			// end template tag
1527
+			if ($this->debug) {
1528
+				echo 'TAG PARSING ENDED' . "\n";
1529
+			}
1530
+			$pointer += strlen($this->rd);
1531
+
1532
+			return false;
1533
+		} elseif (is_array($parsingParams) && preg_match('#^(([\'"]?)[a-z0-9_]+\2\s*=' . ($curBlock === 'array' ? '>?' : '') . ')(?:\s+|[^=]).*#i', $substr, $match)) {
1534
+			// named parameter
1535
+			if ($this->debug) {
1536
+				echo 'NAMED PARAM FOUND' . "\n";
1537
+			}
1538
+			$len = strlen($match[1]);
1539
+			while (substr($in, $from + $len, 1) === ' ') {
1540
+				++ $len;
1541
+			}
1542
+			if ($pointer !== null) {
1543
+				$pointer += $len;
1544
+			}
1545
+
1546
+			$output = array(
1547
+				trim($match[1], " \t\r\n=>'\""),
1548
+				$this->parse($in, $from + $len, $to, false, 'namedparam', $pointer)
1549
+			);
1550
+
1551
+			$parsingParams[] = $output;
1552
+
1553
+			return $parsingParams;
1554
+		} elseif (preg_match('#^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*::\$[a-z0-9_]+)#i', $substr, $match)) {
1555
+			// static member access
1556
+			$parsed = 'var';
1557
+			if (is_array($parsingParams)) {
1558
+				$parsingParams[] = array($match[1], $match[1]);
1559
+				$out             = $parsingParams;
1560
+			} else {
1561
+				$out = $match[1];
1562
+			}
1563
+			$pointer += strlen($match[1]);
1564
+		} elseif ($substr !== '' && (is_array($parsingParams) || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'expression')) {
1565
+			// unquoted string, bool or number
1566
+			$out = $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1567
+		} else {
1568
+			// parse error
1569
+			throw new CompilationException($this, 'Parse error in "' . substr($in, $from, $to - $from) . '"');
1570
+		}
1571
+
1572
+		if (empty($out)) {
1573
+			return '';
1574
+		}
1575
+
1576
+		$substr = substr($in, $pointer, $to - $pointer);
1577
+
1578
+		// var parsed, check if any var-extension applies
1579
+		if ($parsed === 'var') {
1580
+			if (preg_match('#^\s*([/%+*-])\s*([a-z0-9]|\$)#i', $substr, $match)) {
1581
+				if ($this->debug) {
1582
+					echo 'PARSING POST-VAR EXPRESSION ' . $substr . "\n";
1583
+				}
1584
+				// parse expressions
1585
+				$pointer += strlen($match[0]) - 1;
1586
+				if (is_array($parsingParams)) {
1587
+					if ($match[2] == '$') {
1588
+						$expr = $this->parseVar($in, $pointer, $to, array(), $curBlock, $pointer);
1589
+					} else {
1590
+						$expr = $this->parse($in, $pointer, $to, array(), 'expression', $pointer);
1591
+					}
1592
+					$out[count($out) - 1][0] .= $match[1] . $expr[0][0];
1593
+					$out[count($out) - 1][1] .= $match[1] . $expr[0][1];
1594
+				} else {
1595
+					if ($match[2] == '$') {
1596
+						$expr = $this->parseVar($in, $pointer, $to, false, $curBlock, $pointer);
1597
+					} else {
1598
+						$expr = $this->parse($in, $pointer, $to, false, 'expression', $pointer);
1599
+					}
1600
+					if (is_array($out) && is_array($expr)) {
1601
+						$out[0] .= $match[1] . $expr[0];
1602
+						$out[1] .= $match[1] . $expr[1];
1603
+					} elseif (is_array($out)) {
1604
+						$out[0] .= $match[1] . $expr;
1605
+						$out[1] .= $match[1] . $expr;
1606
+					} elseif (is_array($expr)) {
1607
+						$out .= $match[1] . $expr[0];
1608
+					} else {
1609
+						$out .= $match[1] . $expr;
1610
+					}
1611
+				}
1612
+			} elseif ($curBlock === 'root' && preg_match('#^(\s*(?:[+/*%-.]=|=|\+\+|--)\s*)(.*)#s', $substr, $match)) {
1613
+				if ($this->debug) {
1614
+					echo 'PARSING POST-VAR ASSIGNMENT ' . $substr . "\n";
1615
+				}
1616
+				// parse assignment
1617
+				$value    = $match[2];
1618
+				$operator = trim($match[1]);
1619
+				if (substr($value, 0, 1) == '=') {
1620
+					throw new CompilationException($this, 'Unexpected "=" in <em>' . $substr . '</em>');
1621
+				}
1622
+
1623
+				if ($pointer !== null) {
1624
+					$pointer += strlen($match[1]);
1625
+				}
1626
+
1627
+				if ($operator !== '++' && $operator !== '--') {
1628
+					$parts = array();
1629
+					$ptr   = 0;
1630
+					$parts = $this->parse($value, 0, strlen($value), $parts, 'condition', $ptr);
1631
+					$pointer += $ptr;
1632
+
1633
+					// load if plugin
1634
+					try {
1635
+						$this->getPluginType('if');
1636
+					}
1637
+					catch (Exception $e) {
1638
+						throw new CompilationException($this, 'Assignments require the "if" plugin to be accessible');
1639
+					}
1640
+
1641
+					$parts  = $this->mapParams($parts, array(Core::NAMESPACE_PLUGINS_BLOCKS . 'PluginIf', 'init'), 1);
1642
+					$tokens = $this->getParamTokens($parts);
1643
+					$parts  = $this->getCompiledParams($parts);
1644
+
1645
+					$value = PluginIf::replaceKeywords($parts['*'], $tokens['*'], $this);
1646
+					$echo  = '';
1647
+				} else {
1648
+					$value = array();
1649
+					$echo  = 'echo ';
1650
+				}
1651
+
1652
+				if ($this->autoEscape) {
1653
+					$out = preg_replace('#\(is_string\(\$tmp=(.+?)\) \? htmlspecialchars\(\$tmp, ENT_QUOTES, \$this->charset\) : \$tmp\)#', '$1', $out);
1654
+				}
1655
+				$out = self::PHP_OPEN . $echo . $out . $operator . implode(' ', $value) . self::PHP_CLOSE;
1656
+			} elseif ($curBlock === 'array' && is_array($parsingParams) && preg_match('#^(\s*=>?\s*)#', $substr, $match)) {
1657
+				// parse namedparam with var as name (only for array)
1658
+				if ($this->debug) {
1659
+					echo 'VARIABLE NAMED PARAM (FOR ARRAY) FOUND' . "\n";
1660
+				}
1661
+				$len = strlen($match[1]);
1662
+				$var = $out[count($out) - 1];
1663
+				$pointer += $len;
1664
+
1665
+				$output = array($var[0], $this->parse($substr, $len, null, false, 'namedparam', $pointer));
1666
+
1667
+				$parsingParams[] = $output;
1668
+
1669
+				return $parsingParams;
1670
+			}
1671
+		}
1672
+
1673
+		if ($curBlock !== 'modifier' && ($parsed === 'func' || $parsed === 'var') && preg_match('#^(\|@?[a-z0-9_]+(:.*)?)+#i', $substr, $match)) {
1674
+			// parse modifier on funcs or vars
1675
+			$srcPointer = $pointer;
1676
+			if (is_array($parsingParams)) {
1677
+				$tmp                     = $this->replaceModifiers(
1678
+					array(
1679
+					null,
1680
+					null,
1681
+					$out[count($out) - 1][0],
1682
+					$match[0]
1683
+					), $curBlock, $pointer
1684
+				);
1685
+				$out[count($out) - 1][0] = $tmp;
1686
+				$out[count($out) - 1][1] .= substr($substr, $srcPointer, $srcPointer - $pointer);
1687
+			} else {
1688
+				$out = $this->replaceModifiers(array(null, null, $out, $match[0]), $curBlock, $pointer);
1689
+			}
1690
+		}
1691
+
1692
+		// func parsed, check if any func-extension applies
1693
+		if ($parsed === 'func' && preg_match('#^->[a-z0-9_]+(\s*\(.+|->[a-z_].*)?#is', $substr, $match)) {
1694
+			// parse method call or property read
1695
+			$ptr = 0;
1696
+
1697
+			if (is_array($parsingParams)) {
1698
+				$output = $this->parseMethodCall($out[count($out) - 1][1], $match[0], $curBlock, $ptr);
1699
+
1700
+				$out[count($out) - 1][0] = $output;
1701
+				$out[count($out) - 1][1] .= substr($match[0], 0, $ptr);
1702
+			} else {
1703
+				$out = $this->parseMethodCall($out, $match[0], $curBlock, $ptr);
1704
+			}
1705
+
1706
+			$pointer += $ptr;
1707
+		}
1708
+
1709
+		if ($curBlock === 'root' && substr($out, 0, strlen(self::PHP_OPEN)) !== self::PHP_OPEN) {
1710
+			return self::PHP_OPEN . 'echo ' . $out . ';' . self::PHP_CLOSE;
1711
+		} else {
1712
+			return $out;
1713
+		}
1714
+	}
1715
+
1716
+	/**
1717
+	 * Parses a function call.
1718
+	 *
1719
+	 * @param string $in            the string within which we must parse something
1720
+	 * @param int    $from          the starting offset of the parsed area
1721
+	 * @param int    $to            the ending offset of the parsed area
1722
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
1723
+	 *                              default
1724
+	 * @param string $curBlock      the current parser-block being processed
1725
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
1726
+	 *                              or null by default
1727
+	 *
1728
+	 * @return string parsed values
1729
+	 * @throws CompilationException
1730
+	 * @throws Exception
1731
+	 * @throws SecurityException
1732
+	 */
1733
+	protected function parseFunction($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1734
+	{
1735
+		$output = '';
1736
+		$cmdstr = substr($in, $from, $to - $from);
1737
+		preg_match('/^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?)(\s*' . $this->rdr . '|\s*;)?/i', $cmdstr, $match);
1738
+
1739
+		if (empty($match[1])) {
1740
+			throw new CompilationException($this, 'Parse error, invalid function name : ' . substr($cmdstr, 0, 15));
1741
+		}
1742
+
1743
+		$func = $match[1];
1744
+
1745
+		if (!empty($match[2])) {
1746
+			$cmdstr = $match[1];
1747
+		}
1748
+
1749
+		if ($this->debug) {
1750
+			echo 'FUNC FOUND (' . $func . ')' . "\n";
1751
+		}
1752
+
1753
+		$paramsep = '';
1754
+
1755
+		if (is_array($parsingParams) || $curBlock != 'root') {
1756
+			$paramspos = strpos($cmdstr, '(');
1757
+			$paramsep  = ')';
1758
+		} elseif (preg_match_all('#^\s*[\\\\:a-z0-9_]+(\s*\(|\s+[^(])#i', $cmdstr, $match, PREG_OFFSET_CAPTURE)) {
1759
+			$paramspos = $match[1][0][1];
1760
+			$paramsep  = substr($match[1][0][0], - 1) === '(' ? ')' : '';
1761
+			if ($paramsep === ')') {
1762
+				$paramspos += strlen($match[1][0][0]) - 1;
1763
+				if (substr($cmdstr, 0, 2) === 'if' || substr($cmdstr, 0, 6) === 'elseif') {
1764
+					$paramsep = '';
1765
+					if (strlen($match[1][0][0]) > 1) {
1766
+						-- $paramspos;
1767
+					}
1768
+				}
1769
+			}
1770
+		} else {
1771
+			$paramspos = false;
1772
+		}
1773
+
1774
+		$state = 0;
1775
+
1776
+		if ($paramspos === false) {
1777
+			$params = array();
1778
+
1779
+			if ($curBlock !== 'root') {
1780
+				return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1781
+			}
1782
+		} else {
1783
+			if ($curBlock === 'condition') {
1784
+				// load if plugin
1785
+				$this->getPluginType('if');
1786
+
1787
+				if (PluginIf::replaceKeywords(array($func), array(self::T_UNQUOTED_STRING), $this) !== array($func)) {
1788
+					return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1789
+				}
1790
+			}
1791
+			$whitespace = strlen(substr($cmdstr, strlen($func), $paramspos - strlen($func)));
1792
+			$paramstr   = substr($cmdstr, $paramspos + 1);
1793
+			if (substr($paramstr, - 1, 1) === $paramsep) {
1794
+				$paramstr = substr($paramstr, 0, - 1);
1795
+			}
1796
+
1797
+			if (strlen($paramstr) === 0) {
1798
+				$params   = array();
1799
+				$paramstr = '';
1800
+			} else {
1801
+				$ptr    = 0;
1802
+				$params = array();
1803
+				if ($func === 'empty') {
1804
+					$params = $this->parseVar($paramstr, $ptr, strlen($paramstr), $params, 'root', $ptr);
1805
+				} else {
1806
+					while ($ptr < strlen($paramstr)) {
1807
+						while (true) {
1808
+							if ($ptr >= strlen($paramstr)) {
1809
+								break 2;
1810
+							}
1811
+
1812
+							if ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === ')') {
1813
+								if ($this->debug) {
1814
+									echo 'PARAM PARSING ENDED, ")" FOUND, POINTER AT ' . $ptr . "\n";
1815
+								}
1816
+								break 2;
1817
+							} elseif ($paramstr[$ptr] === ';') {
1818
+								++ $ptr;
1819
+								if ($this->debug) {
1820
+									echo 'PARAM PARSING ENDED, ";" FOUND, POINTER AT ' . $ptr . "\n";
1821
+								}
1822
+								break 2;
1823
+							} elseif ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === '/') {
1824
+								if ($this->debug) {
1825
+									echo 'PARAM PARSING ENDED, "/" FOUND, POINTER AT ' . $ptr . "\n";
1826
+								}
1827
+								break 2;
1828
+							} elseif (substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
1829
+								if ($this->debug) {
1830
+									echo 'PARAM PARSING ENDED, RIGHT DELIMITER FOUND, POINTER AT ' . $ptr . "\n";
1831
+								}
1832
+								break 2;
1833
+							}
1834
+
1835
+							if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === ',' || $paramstr[$ptr] === "\r" || $paramstr[$ptr] === "\n" || $paramstr[$ptr] === "\t") {
1836
+								++ $ptr;
1837
+							} else {
1838
+								break;
1839
+							}
1840
+						}
1841
+
1842
+						if ($this->debug) {
1843
+							echo 'FUNC START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
1844
+						}
1845
+
1846
+						if ($func === 'if' || $func === 'elseif' || $func === 'tif') {
1847
+							$params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'condition', $ptr);
1848
+						} elseif ($func === 'array') {
1849
+							$params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'array', $ptr);
1850
+						} else {
1851
+							$params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'function', $ptr);
1852
+						}
1853
+
1854
+						if ($this->debug) {
1855
+							echo 'PARAM PARSED, POINTER AT ' . $ptr . ' (' . substr($paramstr, $ptr - 1, 3) . ')' . "\n";
1856
+						}
1857
+					}
1858
+				}
1859
+				$paramstr = substr($paramstr, 0, $ptr);
1860
+				$state    = 0;
1861
+				foreach ($params as $k => $p) {
1862
+					if (is_array($p) && is_array($p[1])) {
1863
+						$state |= 2;
1864
+					} else {
1865
+						if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m) && $func !== 'array') {
1866
+							$params[$k] = array($m[2], array('true', 'true'));
1867
+						} else {
1868
+							if ($state & 2 && $func !== 'array') {
1869
+								throw new CompilationException($this, 'You can not use an unnamed parameter after a named one');
1870
+							}
1871
+							$state |= 1;
1872
+						}
1873
+					}
1874
+				}
1875
+			}
1876
+		}
1877
+
1878
+		if ($pointer !== null) {
1879
+			$pointer += (isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func) + (isset($whitespace) ? $whitespace : 0);
1880
+			if ($this->debug) {
1881
+				echo 'FUNC ADDS ' . ((isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func)) . ' TO POINTER' . "\n";
1882
+			}
1883
+		}
1884
+
1885
+		if ($curBlock === 'method' || $func === 'do' || strstr($func, '::') !== false) {
1886
+			// handle static method calls with security policy
1887
+			if (strstr($func, '::') !== false && $this->securityPolicy !== null && $this->securityPolicy->isMethodAllowed(explode('::', strtolower($func))) !== true) {
1888
+				throw new SecurityException('Call to a disallowed php function : ' . $func);
1889
+			}
1890
+			$pluginType = Core::NATIVE_PLUGIN;
1891
+		} else {
1892
+			$pluginType = $this->getPluginType($func);
1893
+		}
1894
+
1895
+		// Blocks plugin
1896
+		if ($pluginType & Core::BLOCK_PLUGIN) {
1897
+			if ($curBlock !== 'root' || is_array($parsingParams)) {
1898
+				throw new CompilationException($this, 'Block plugins can not be used as other plugin\'s arguments');
1899
+			}
1900
+			if ($pluginType & Core::CUSTOM_PLUGIN) {
1901
+				return $this->addCustomBlock($func, $params, $state);
1902
+			} else {
1903
+				return $this->addBlock($func, $params, $state);
1904
+			}
1905
+		} elseif ($pluginType & Core::SMARTY_BLOCK) {
1906
+			if ($curBlock !== 'root' || is_array($parsingParams)) {
1907
+				throw new CompilationException($this, 'Block plugins can not be used as other plugin\'s arguments');
1908
+			}
1909
+
1910
+			if ($state & 2) {
1911
+				array_unshift($params, array('__functype', array($pluginType, $pluginType)));
1912
+				array_unshift($params, array('__funcname', array($func, $func)));
1913
+			} else {
1914
+				array_unshift($params, array($pluginType, $pluginType));
1915
+				array_unshift($params, array($func, $func));
1916
+			}
1917
+
1918
+			return $this->addBlock('smartyinterface', $params, $state);
1919
+		}
1920
+
1921
+		// Native & Smarty plugins
1922
+		if ($pluginType & Core::NATIVE_PLUGIN || $pluginType & Core::SMARTY_FUNCTION || $pluginType & Core::SMARTY_BLOCK) {
1923
+			$params = $this->mapParams($params, null, $state);
1924
+		} // PHP class plugin
1925
+		elseif ($pluginType & Core::CLASS_PLUGIN) {
1926
+			if ($pluginType & Core::CUSTOM_PLUGIN) {
1927
+				$params = $this->mapParams(
1928
+					$params, array(
1929
+					$this->customPlugins[$func]['class'],
1930
+					$this->customPlugins[$func]['function']
1931
+				), $state);
1932
+			} else {
1933
+				if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
1934
+					$params = $this->mapParams($params, array(
1935
+						'Plugin' . Core::toCamelCase($func),
1936
+						($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1937
+					), $state);
1938
+				} elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !== false) {
1939
+					$params = $this->mapParams($params, array(
1940
+						Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func),
1941
+						($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1942
+					), $state);
1943
+				} else {
1944
+					$params = $this->mapParams($params, array(
1945
+						Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
1946
+						($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1947
+					), $state);
1948
+				}
1949
+			}
1950
+		} // PHP function plugin
1951
+		elseif ($pluginType & Core::FUNC_PLUGIN) {
1952
+			if ($pluginType & Core::CUSTOM_PLUGIN) {
1953
+				$params = $this->mapParams($params, $this->customPlugins[$func]['callback'], $state);
1954
+			} else {
1955
+				// Custom plugin
1956
+				if (function_exists('Plugin' . Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ?
1957
+						'Compile' : '')) !== false) {
1958
+					$params = $this->mapParams($params, 'Plugin' . Core::toCamelCase($func) . (($pluginType &
1959
+							Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1960
+				} // Builtin helper plugin
1961
+				elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . (
1962
+					($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '')) !== false) {
1963
+					$params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase
1964
+						($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1965
+				} // Builtin function plugin
1966
+				else {
1967
+					$params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase
1968
+						($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1969
+				}
1970
+			}
1971
+		} // Smarty modifier
1972
+		elseif ($pluginType & Core::SMARTY_MODIFIER) {
1973
+			$output = 'smarty_modifier_' . $func . '(' . implode(', ', $params) . ')';
1974
+		} // Proxy plugin
1975
+		elseif ($pluginType & Core::PROXY_PLUGIN) {
1976
+			$params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state);
1977
+		} // Template plugin
1978
+		elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
1979
+			// transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values))
1980
+			$map = array();
1981
+			foreach ($this->templatePlugins[$func]['params'] as $param => $defValue) {
1982
+				if ($param == 'rest') {
1983
+					$param = '*';
1984
+				}
1985
+				$hasDefault = $defValue !== null;
1986
+				if ($defValue === 'null') {
1987
+					$defValue = null;
1988
+				} elseif ($defValue === 'false') {
1989
+					$defValue = false;
1990
+				} elseif ($defValue === 'true') {
1991
+					$defValue = true;
1992
+				} elseif (preg_match('#^([\'"]).*?\1$#', $defValue)) {
1993
+					$defValue = substr($defValue, 1, - 1);
1994
+				}
1995
+				$map[] = array($param, $hasDefault, $defValue);
1996
+			}
1997
+
1998
+			$params = $this->mapParams($params, null, $state, $map);
1999
+		}
2000
+
2001
+		// only keep php-syntax-safe values for non-block plugins
2002
+		$tokens = array();
2003
+		foreach ($params as $k => $p) {
2004
+			$tokens[$k] = isset($p[2]) ? $p[2] : 0;
2005
+			$params[$k] = $p[0];
2006
+		}
2007
+
2008
+		// Native plugin
2009
+		if ($pluginType & Core::NATIVE_PLUGIN) {
2010
+			if ($func === 'do') {
2011
+				$output = '';
2012
+				if (isset($params['*'])) {
2013
+					$output = implode(';', $params['*']) . ';';
2014
+				}
2015
+
2016
+				if (is_array($parsingParams) || $curBlock !== 'root') {
2017
+					throw new CompilationException($this, 'Do can not be used inside another function or block');
2018
+				}
2019
+
2020
+				return self::PHP_OPEN . $output . self::PHP_CLOSE;
2021
+			} else {
2022
+				if (isset($params['*'])) {
2023
+					$output = $func . '(' . implode(', ', $params['*']) . ')';
2024
+				} else {
2025
+					$output = $func . '()';
2026
+				}
2027
+			}
2028
+		} // Block class OR Function class
2029
+		elseif ($pluginType & Core::CLASS_PLUGIN || ($pluginType & Core::FUNC_PLUGIN && $pluginType & Core::CLASS_PLUGIN)) {
2030
+			if ($pluginType & Core::COMPILABLE_PLUGIN) {
2031
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
2032
+					$callback = $this->customPlugins[$func]['callback'];
2033
+					if (!is_array($callback)) {
2034
+						if (!method_exists($callback, 'compile')) {
2035
+							throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
2036
+						}
2037
+						if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
2038
+							$funcCompiler = array($callback, 'compile');
2039
+						} else {
2040
+							$funcCompiler = array(new $callback(), 'compile');
2041
+						}
2042
+					} else {
2043
+						$funcCompiler = $callback;
2044
+					}
2045
+				} else {
2046
+					if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2047
+						$funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
2048
+					} elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !== false) {
2049
+						$funcCompiler = array(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func), 'compile');
2050
+					} else {
2051
+						$funcCompiler = array(
2052
+							Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
2053
+							'compile'
2054
+						);
2055
+					}
2056
+					array_unshift($params, $this);
2057
+				}
2058
+				// @TODO: Is it a real fix ?
2059
+				if ($func === 'tif') {
2060
+					$params[] = $tokens;
2061
+				}
2062
+				$output = call_user_func_array($funcCompiler, $params);
2063
+			} else {
2064
+				$params = self::implode_r($params);
2065
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
2066
+					$callback = $this->customPlugins[$func]['callback'];
2067
+					if (!is_array($callback)) {
2068
+						if (!method_exists($callback, 'process')) {
2069
+							throw new Exception('Custom plugin ' . $func . ' must implement the "process" method to be usable, or you should provide a full callback to the method to use');
2070
+						}
2071
+						if (($ref = new ReflectionMethod($callback, 'process')) && $ref->isStatic()) {
2072
+							$output = 'call_user_func(array(\'' . $callback . '\', \'process\'), ' . $params . ')';
2073
+						} else {
2074
+							$output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback . '\'), \'process\'), ' . $params . ')';
2075
+						}
2076
+					} elseif (is_object($callback[0])) {
2077
+						$output = 'call_user_func(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), ' . $params . ')';
2078
+					} elseif (($ref = new ReflectionMethod($callback[0], $callback[1])) && $ref->isStatic()) {
2079
+						$output = 'call_user_func(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), ' . $params . ')';
2080
+					} else {
2081
+						$output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback[0] . '\'), \'' . $callback[1] . '\'), ' . $params . ')';
2082
+					}
2083
+					if (empty($params)) {
2084
+						$output = substr($output, 0, - 3) . ')';
2085
+					}
2086
+				} else {
2087
+					if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2088
+						$output = '$this->classCall(\'Plugin' . $func . '\', array(' . $params . '))';
2089
+					} elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !== false) {
2090
+						$output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\', 
2091 2091
                         array(' . $params . '))';
2092
-                    } else {
2093
-                        $output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
2094
-                    }
2095
-                }
2096
-            }
2097
-        } // Function plugin only (cannot be a class)
2098
-        elseif ($pluginType & Core::FUNC_PLUGIN) {
2099
-            if ($pluginType & Core::COMPILABLE_PLUGIN) {
2100
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
2101
-                    $funcCompiler = $this->customPlugins[$func]['callback'];
2102
-                } else {
2103
-                    // Custom plugin
2104
-                    if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2105
-                        $funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
2106
-                    } // Builtin helper plugin
2107
-                    elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2108
-                        $funcCompiler = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) .
2109
-                            'Compile';
2110
-                    } // Builtin function plugin
2111
-                    else {
2112
-                        $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
2113
-                            'Compile';
2114
-                    }
2115
-                }
2116
-                array_unshift($params, $this);
2117
-                // @TODO: Is it a real fix ?
2118
-                if ($func === 'tif') {
2119
-                    $params[] = $tokens;
2120
-                }
2121
-                $output = call_user_func_array($funcCompiler, $params);
2122
-            } else {
2123
-                array_unshift($params, '$this');
2124
-                $params = self::implode_r($params);
2125
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
2126
-                    $callback = $this->customPlugins[$func]['callback'];
2127
-                    if ($callback instanceof Closure) {
2128
-                        $output = 'call_user_func($this->getCustomPlugin(\'' . $func . '\'), ' . $params . ')';
2129
-                    } else {
2130
-                        $output = 'call_user_func(\'' . $callback . '\', ' . $params . ')';
2131
-                    }
2132
-                } else {
2133
-                    // Custom plugin
2134
-                    if (function_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2135
-                        $output = 'Plugin' . Core::toCamelCase($func) . '(' . $params .
2136
-                            ')';
2137
-                    } // Builtin helper plugin
2138
-                    elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !==
2139
-                        false) {
2140
-                        $output = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . '(' .
2141
-                            $params . ')';
2142
-                    } // Builtin function plugin
2143
-                    else {
2144
-                        $output = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '(' .
2145
-                            $params . ')';
2146
-                    }
2147
-                }
2148
-            }
2149
-        } // Proxy plugin
2150
-        elseif ($pluginType & Core::PROXY_PLUGIN) {
2151
-            $output = call_user_func(array($this->getDwoo()->getPluginProxy(), 'getCode'), $func, $params);
2152
-        } // Smarty function (@deprecated)
2153
-        elseif ($pluginType & Core::SMARTY_FUNCTION) {
2154
-            $params = '';
2155
-            if (isset($params['*'])) {
2156
-                $params = self::implode_r($params['*'], true);
2157
-            }
2158
-
2159
-            if ($pluginType & Core::CUSTOM_PLUGIN) {
2160
-                $callback = $this->customPlugins[$func]['callback'];
2161
-                if (is_array($callback)) {
2162
-                    if (is_object($callback[0])) {
2163
-                        $output = 'call_user_func_array(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2164
-                    } else {
2165
-                        $output = 'call_user_func_array(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2166
-                    }
2167
-                } else {
2168
-                    $output = $callback . '(array(' . $params . '), $this)';
2169
-                }
2170
-            } else {
2171
-                $output = 'smarty_function_' . $func . '(array(' . $params . '), $this)';
2172
-            }
2173
-        } // Template plugin
2174
-        elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
2175
-            array_unshift($params, '$this');
2176
-            $params                                 = self::implode_r($params);
2177
-            $output                                 = 'Plugin' . Core::toCamelCase($func) .
2178
-                $this->templatePlugins[$func]['uuid'] . '(' . $params . ')';
2179
-            $this->templatePlugins[$func]['called'] = true;
2180
-        }
2181
-
2182
-        if (is_array($parsingParams)) {
2183
-            $parsingParams[] = array($output, $output);
2184
-
2185
-            return $parsingParams;
2186
-        } elseif ($curBlock === 'namedparam') {
2187
-            return array($output, $output);
2188
-        }
2189
-
2190
-        return $output;
2191
-    }
2192
-
2193
-    /**
2194
-     * Parses a string.
2195
-     *
2196
-     * @param string $in            the string within which we must parse something
2197
-     * @param int    $from          the starting offset of the parsed area
2198
-     * @param int    $to            the ending offset of the parsed area
2199
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2200
-     *                              default
2201
-     * @param string $curBlock      the current parser-block being processed
2202
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2203
-     *                              or null by default
2204
-     *
2205
-     * @return string parsed values
2206
-     * @throws CompilationException
2207
-     */
2208
-    protected function parseString($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2209
-    {
2210
-        $substr = substr($in, $from, $to - $from);
2211
-        $first  = $substr[0];
2212
-
2213
-        if ($this->debug) {
2214
-            echo 'STRING FOUND (in ' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . ')' . "\n";
2215
-        }
2216
-        $strend = false;
2217
-        $o      = $from + 1;
2218
-        while ($strend === false) {
2219
-            $strend = strpos($in, $first, $o);
2220
-            if ($strend === false) {
2221
-                throw new CompilationException($this, 'Unfinished string, started with ' . substr($in, $from, $to - $from));
2222
-            }
2223
-            if (substr($in, $strend - 1, 1) === '\\') {
2224
-                $o      = $strend + 1;
2225
-                $strend = false;
2226
-            }
2227
-        }
2228
-        if ($this->debug) {
2229
-            echo 'STRING DELIMITED: ' . substr($in, $from, $strend + 1 - $from) . "\n";
2230
-        }
2231
-
2232
-        $srcOutput = substr($in, $from, $strend + 1 - $from);
2233
-
2234
-        if ($pointer !== null) {
2235
-            $pointer += strlen($srcOutput);
2236
-        }
2237
-
2238
-        $output = $this->replaceStringVars($srcOutput, $first);
2239
-
2240
-        // handle modifiers
2241
-        if ($curBlock !== 'modifier' && preg_match('#^((?:\|(?:@?[a-z0-9_]+(?::.*)*))+)#i', substr($substr, $strend + 1 - $from), $match)) {
2242
-            $modstr = $match[1];
2243
-
2244
-            if ($curBlock === 'root' && substr($modstr, - 1) === '}') {
2245
-                $modstr = substr($modstr, 0, - 1);
2246
-            }
2247
-            $modstr = str_replace('\\' . $first, $first, $modstr);
2248
-            $ptr    = 0;
2249
-            $output = $this->replaceModifiers(array(null, null, $output, $modstr), 'string', $ptr);
2250
-
2251
-            $strend += $ptr;
2252
-            if ($pointer !== null) {
2253
-                $pointer += $ptr;
2254
-            }
2255
-            $srcOutput .= substr($substr, $strend + 1 - $from, $ptr);
2256
-        }
2257
-
2258
-        if (is_array($parsingParams)) {
2259
-            $parsingParams[] = array($output, substr($srcOutput, 1, - 1));
2260
-
2261
-            return $parsingParams;
2262
-        } elseif ($curBlock === 'namedparam') {
2263
-            return array($output, substr($srcOutput, 1, - 1));
2264
-        } else {
2265
-            return $output;
2266
-        }
2267
-    }
2268
-
2269
-    /**
2270
-     * Parses a constant.
2271
-     *
2272
-     * @param string $in            the string within which we must parse something
2273
-     * @param int    $from          the starting offset of the parsed area
2274
-     * @param int    $to            the ending offset of the parsed area
2275
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2276
-     *                              default
2277
-     * @param string $curBlock      the current parser-block being processed
2278
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2279
-     *                              or null by default
2280
-     *
2281
-     * @return string parsed values
2282
-     * @throws CompilationException
2283
-     */
2284
-    protected function parseConst($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2285
-    {
2286
-        $substr = substr($in, $from, $to - $from);
2287
-
2288
-        if ($this->debug) {
2289
-            echo 'CONST FOUND : ' . $substr . "\n";
2290
-        }
2291
-
2292
-        if (!preg_match('#^%([\\\\a-z0-9_:]+)#i', $substr, $m)) {
2293
-            throw new CompilationException($this, 'Invalid constant');
2294
-        }
2295
-
2296
-        if ($pointer !== null) {
2297
-            $pointer += strlen($m[0]);
2298
-        }
2299
-
2300
-        $output = $this->parseConstKey($m[1], $curBlock);
2301
-
2302
-        if (is_array($parsingParams)) {
2303
-            $parsingParams[] = array($output, $m[1]);
2304
-
2305
-            return $parsingParams;
2306
-        } elseif ($curBlock === 'namedparam') {
2307
-            return array($output, $m[1]);
2308
-        } else {
2309
-            return $output;
2310
-        }
2311
-    }
2312
-
2313
-    /**
2314
-     * Parses a constant.
2315
-     *
2316
-     * @param string $key      the constant to parse
2317
-     * @param string $curBlock the current parser-block being processed
2318
-     *
2319
-     * @return string parsed constant
2320
-     */
2321
-    protected function parseConstKey($key, $curBlock)
2322
-    {
2323
-        if ($this->securityPolicy !== null && $this->securityPolicy->getConstantHandling() === SecurityPolicy::CONST_DISALLOW) {
2324
-            return 'null';
2325
-        }
2326
-
2327
-        if ($curBlock !== 'root') {
2328
-            $output = '(defined("' . $key . '") ? ' . $key . ' : null)';
2329
-        } else {
2330
-            $output = $key;
2331
-        }
2332
-
2333
-        return $output;
2334
-    }
2335
-
2336
-    /**
2337
-     * Parses a variable.
2338
-     *
2339
-     * @param string $in            the string within which we must parse something
2340
-     * @param int    $from          the starting offset of the parsed area
2341
-     * @param int    $to            the ending offset of the parsed area
2342
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2343
-     *                              default
2344
-     * @param string $curBlock      the current parser-block being processed
2345
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2346
-     *                              or null by default
2347
-     *
2348
-     * @return string parsed values
2349
-     * @throws CompilationException
2350
-     */
2351
-    protected function parseVar($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2352
-    {
2353
-        $substr = substr($in, $from, $to - $from);
2354
-
2355
-        // var key
2356
-        $varRegex = '(\\$?\\.?[a-z0-9\\\\_:]*(?:(?:(?:\\.|->)(?:[a-z0-9\\\\_:]+|(?R))|\\[(?:[a-z0-9\\\\_:]+|(?R)|(["\'])[^\\2]*?\\2)\\]))*)';
2357
-        // method call
2358
-        $methodCall = ($curBlock === 'root' || $curBlock === 'function' || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'variable' || $curBlock === 'expression' || $curBlock === 'delimited_string' ? '(\(.*)?' : '()');
2359
-        // simple math expressions
2360
-        $simpleMathExpressions = ($curBlock === 'root' || $curBlock === 'function' || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'variable' || $curBlock === 'delimited_string' ? '((?:(?:[+\/*%=-])(?:(?<!=)=?-?[$%][a-z0-9\\\\.[\]>_:-]+(?:\([^)]*\))?|(?<!=)=?-?[0-9\.,]*|[+-]))*)' : '()');
2361
-        // modifiers
2362
-        $modifiers = $curBlock !== 'modifier' ? '((?:\|(?:@?[a-z0-9\\\\_]+(?:(?::("|\').*?\5|:[^`]*))*))+)?' : '(())';
2363
-
2364
-        $regex = '#';
2365
-        $regex .= $varRegex;
2366
-        $regex .= $methodCall;
2367
-        $regex .= $simpleMathExpressions;
2368
-        $regex .= $modifiers;
2369
-        $regex .= '#i';
2370
-
2371
-        if (preg_match($regex, $substr, $match)) {
2372
-            $key = substr($match[1], 1);
2373
-
2374
-            $matchedLength = strlen($match[0]);
2375
-            $hasModifiers  = !empty($match[5]);
2376
-            $hasExpression = !empty($match[4]);
2377
-            $hasMethodCall = !empty($match[3]);
2378
-
2379
-            if (substr($key, - 1) == '.') {
2380
-                $key = substr($key, 0, - 1);
2381
-                -- $matchedLength;
2382
-            }
2383
-
2384
-            if ($hasMethodCall) {
2385
-                $matchedLength -= strlen($match[3]) + strlen(substr($match[1], strrpos($match[1], '->')));
2386
-                $key        = substr($match[1], 1, strrpos($match[1], '->') - 1);
2387
-                $methodCall = substr($match[1], strrpos($match[1], '->')) . $match[3];
2388
-            }
2389
-
2390
-            if ($hasModifiers) {
2391
-                $matchedLength -= strlen($match[5]);
2392
-            }
2393
-
2394
-            if ($pointer !== null) {
2395
-                $pointer += $matchedLength;
2396
-            }
2397
-
2398
-            // replace useless brackets by dot accessed vars and strip enclosing quotes if present
2399
-            $key = preg_replace('#\[(["\']?)([^$%\[.>-]+)\1\]#', '.$2', $key);
2400
-
2401
-            if ($this->debug) {
2402
-                if ($hasMethodCall) {
2403
-                    echo 'METHOD CALL FOUND : $' . $key . substr($methodCall, 0, 30) . "\n";
2404
-                } else {
2405
-                    echo 'VAR FOUND : $' . $key . "\n";
2406
-                }
2407
-            }
2408
-
2409
-            $key = str_replace('"', '\\"', $key);
2410
-
2411
-            $cnt = substr_count($key, '$');
2412
-            if ($cnt > 0) {
2413
-                $uid           = 0;
2414
-                $parsed        = array($uid => '');
2415
-                $current       = &$parsed;
2416
-                $curTxt        = &$parsed[$uid ++];
2417
-                $tree          = array();
2418
-                $chars         = str_split($key, 1);
2419
-                $inSplittedVar = false;
2420
-                $bracketCount  = 0;
2421
-
2422
-                while (($char = array_shift($chars)) !== null) {
2423
-                    if ($char === '[') {
2424
-                        if (count($tree) > 0) {
2425
-                            ++ $bracketCount;
2426
-                        } else {
2427
-                            $tree[]        = &$current;
2428
-                            $current[$uid] = array($uid + 1 => '');
2429
-                            $current       = &$current[$uid ++];
2430
-                            $curTxt        = &$current[$uid ++];
2431
-                            continue;
2432
-                        }
2433
-                    } elseif ($char === ']') {
2434
-                        if ($bracketCount > 0) {
2435
-                            -- $bracketCount;
2436
-                        } else {
2437
-                            $current = &$tree[count($tree) - 1];
2438
-                            array_pop($tree);
2439
-                            if (current($chars) !== '[' && current($chars) !== false && current($chars) !== ']') {
2440
-                                $current[$uid] = '';
2441
-                                $curTxt        = &$current[$uid ++];
2442
-                            }
2443
-                            continue;
2444
-                        }
2445
-                    } elseif ($char === '$') {
2446
-                        if (count($tree) == 0) {
2447
-                            $curTxt        = &$current[$uid ++];
2448
-                            $inSplittedVar = true;
2449
-                        }
2450
-                    } elseif (($char === '.' || $char === '-') && count($tree) == 0 && $inSplittedVar) {
2451
-                        $curTxt        = &$current[$uid ++];
2452
-                        $inSplittedVar = false;
2453
-                    }
2454
-
2455
-                    $curTxt .= $char;
2456
-                }
2457
-                unset($uid, $current, $curTxt, $tree, $chars);
2458
-
2459
-                if ($this->debug) {
2460
-                    echo 'RECURSIVE VAR REPLACEMENT : ' . $key . "\n";
2461
-                }
2462
-
2463
-                $key = $this->flattenVarTree($parsed);
2464
-
2465
-                if ($this->debug) {
2466
-                    echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2467
-                }
2468
-
2469
-                $output = preg_replace('#(^""\.|""\.|\.""$|(\()""\.|\.""(\)))#', '$2$3', '$this->readVar("' . $key . '")');
2470
-            } else {
2471
-                $output = $this->parseVarKey($key, $hasModifiers ? 'modifier' : $curBlock);
2472
-            }
2473
-
2474
-
2475
-            // methods
2476
-            if ($hasMethodCall) {
2477
-                $ptr = 0;
2478
-
2479
-                $output = $this->parseMethodCall($output, $methodCall, $curBlock, $ptr);
2480
-
2481
-                if ($pointer !== null) {
2482
-                    $pointer += $ptr;
2483
-                }
2484
-                $matchedLength += $ptr;
2485
-            }
2486
-
2487
-            if ($hasExpression) {
2488
-                // expressions
2489
-                preg_match_all('#(?:([+/*%=-])(=?-?[%$][a-z0-9\\\\.[\]>_:-]+(?:\([^)]*\))?|=?-?[0-9.,]+|\1))#i', $match[4], $expMatch);
2490
-                foreach ($expMatch[1] as $k => $operator) {
2491
-                    if (substr($expMatch[2][$k], 0, 1) === '=') {
2492
-                        $assign = true;
2493
-                        if ($operator === '=') {
2494
-                            throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, can not use "==" in expressions');
2495
-                        }
2496
-                        if ($curBlock !== 'root') {
2497
-                            throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, assignments can only be used in top level expressions like {$foo+=3} or {$foo="bar"}');
2498
-                        }
2499
-                        $operator .= '=';
2500
-                        $expMatch[2][$k] = substr($expMatch[2][$k], 1);
2501
-                    }
2502
-
2503
-                    if (substr($expMatch[2][$k], 0, 1) === '-' && strlen($expMatch[2][$k]) > 1) {
2504
-                        $operator .= '-';
2505
-                        $expMatch[2][$k] = substr($expMatch[2][$k], 1);
2506
-                    }
2507
-                    if (($operator === '+' || $operator === '-') && $expMatch[2][$k] === $operator) {
2508
-                        $output = '(' . $output . $operator . $operator . ')';
2509
-                        break;
2510
-                    } elseif (substr($expMatch[2][$k], 0, 1) === '$') {
2511
-                        $output = '(' . $output . ' ' . $operator . ' ' . $this->parseVar($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2512
-                    } elseif (substr($expMatch[2][$k], 0, 1) === '%') {
2513
-                        $output = '(' . $output . ' ' . $operator . ' ' . $this->parseConst($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2514
-                    } elseif (!empty($expMatch[2][$k])) {
2515
-                        $output = '(' . $output . ' ' . $operator . ' ' . str_replace(',', '.', $expMatch[2][$k]) . ')';
2516
-                    } else {
2517
-                        throw new CompilationException($this, 'Unfinished expression <em>' . $substr . '</em>, missing var or number after math operator');
2518
-                    }
2519
-                }
2520
-            }
2521
-
2522
-            if ($this->autoEscape === true && $curBlock !== 'condition') {
2523
-                $output = '(is_string($tmp=' . $output . ') ? htmlspecialchars($tmp, ENT_QUOTES, $this->charset) : $tmp)';
2524
-            }
2525
-
2526
-            // handle modifiers
2527
-            if ($curBlock !== 'modifier' && $hasModifiers) {
2528
-                $ptr    = 0;
2529
-                $output = $this->replaceModifiers(array(null, null, $output, $match[5]), 'var', $ptr);
2530
-                if ($pointer !== null) {
2531
-                    $pointer += $ptr;
2532
-                }
2533
-                $matchedLength += $ptr;
2534
-            }
2535
-
2536
-            if (is_array($parsingParams)) {
2537
-                $parsingParams[] = array($output, $key);
2538
-
2539
-                return $parsingParams;
2540
-            } elseif ($curBlock === 'namedparam') {
2541
-                return array($output, $key);
2542
-            } elseif ($curBlock === 'string' || $curBlock === 'delimited_string') {
2543
-                return array($matchedLength, $output);
2544
-            } elseif ($curBlock === 'expression' || $curBlock === 'variable') {
2545
-                return $output;
2546
-            } elseif (isset($assign)) {
2547
-                return self::PHP_OPEN . $output . ';' . self::PHP_CLOSE;
2548
-            } else {
2549
-                return $output;
2550
-            }
2551
-        } else {
2552
-            if ($curBlock === 'string' || $curBlock === 'delimited_string') {
2553
-                return array(0, '');
2554
-            } else {
2555
-                throw new CompilationException($this, 'Invalid variable name <em>' . $substr . '</em>');
2556
-            }
2557
-        }
2558
-    }
2559
-
2560
-    /**
2561
-     * Parses any number of chained method calls/property reads.
2562
-     *
2563
-     * @param string $output     the variable or whatever upon which the method are called
2564
-     * @param string $methodCall method call source, starting at "->"
2565
-     * @param string $curBlock   the current parser-block being processed
2566
-     * @param int    $pointer    a reference to a pointer that will be increased by the amount of characters parsed
2567
-     *
2568
-     * @return string parsed call(s)/read(s)
2569
-     */
2570
-    protected function parseMethodCall($output, $methodCall, $curBlock, &$pointer)
2571
-    {
2572
-        $ptr = 0;
2573
-        $len = strlen($methodCall);
2574
-
2575
-        while ($ptr < $len) {
2576
-            if (strpos($methodCall, '->', $ptr) === $ptr) {
2577
-                $ptr += 2;
2578
-            }
2579
-
2580
-            if (in_array(
2581
-                $methodCall[$ptr], array(
2582
-                    ';',
2583
-                    ',',
2584
-                    '/',
2585
-                    ' ',
2586
-                    "\t",
2587
-                    "\r",
2588
-                    "\n",
2589
-                    ')',
2590
-                    '+',
2591
-                    '*',
2592
-                    '%',
2593
-                    '=',
2594
-                    '-',
2595
-                    '|'
2596
-                )
2597
-            ) || substr($methodCall, $ptr, strlen($this->rd)) === $this->rd
2598
-            ) {
2599
-                // break char found
2600
-                break;
2601
-            }
2602
-
2603
-            if (!preg_match('/^([a-z0-9_]+)(\(.*?\))?/i', substr($methodCall, $ptr), $methMatch)) {
2604
-                break;
2605
-            }
2606
-
2607
-            if (empty($methMatch[2])) {
2608
-                // property
2609
-                if ($curBlock === 'root') {
2610
-                    $output .= '->' . $methMatch[1];
2611
-                } else {
2612
-                    $output = '(($tmp = ' . $output . ') ? $tmp->' . $methMatch[1] . ' : null)';
2613
-                }
2614
-                $ptr += strlen($methMatch[1]);
2615
-            } else {
2616
-                // method
2617
-                if (substr($methMatch[2], 0, 2) === '()') {
2618
-                    $parsedCall = $methMatch[1] . '()';
2619
-                    $ptr += strlen($methMatch[1]) + 2;
2620
-                } else {
2621
-                    $parsedCall = $this->parseFunction($methodCall, $ptr, strlen($methodCall), false, 'method', $ptr);
2622
-                }
2623
-                if ($this->securityPolicy !== null) {
2624
-                    $argPos = strpos($parsedCall, '(');
2625
-                    $method = strtolower(substr($parsedCall, 0, $argPos));
2626
-                    $args   = substr($parsedCall, $argPos);
2627
-                    if ($curBlock === 'root') {
2628
-                        $output = '$this->getSecurityPolicy()->callMethod($this, ' . $output . ', ' . var_export($method, true) . ', array' . $args . ')';
2629
-                    } else {
2630
-                        $output = '(($tmp = ' . $output . ') ? $this->getSecurityPolicy()->callMethod($this, $tmp, ' . var_export($method, true) . ', array' . $args . ') : null)';
2631
-                    }
2632
-                } else {
2633
-                    if ($curBlock === 'root') {
2634
-                        $output .= '->' . $parsedCall;
2635
-                    } else {
2636
-                        $output = '(($tmp = ' . $output . ') ? $tmp->' . $parsedCall . ' : null)';
2637
-                    }
2638
-                }
2639
-            }
2640
-        }
2641
-
2642
-        $pointer += $ptr;
2643
-
2644
-        return $output;
2645
-    }
2646
-
2647
-    /**
2648
-     * Parses a constant variable (a variable that doesn't contain another variable) and preprocesses it to save
2649
-     * runtime processing time.
2650
-     *
2651
-     * @param string $key      the variable to parse
2652
-     * @param string $curBlock the current parser-block being processed
2653
-     *
2654
-     * @return string parsed variable
2655
-     */
2656
-    protected function parseVarKey($key, $curBlock)
2657
-    {
2658
-        if ($key === '') {
2659
-            return '$this->scope';
2660
-        }
2661
-        if (substr($key, 0, 1) === '.') {
2662
-            $key = 'dwoo' . $key;
2663
-        }
2664
-        if (preg_match('#dwoo\.(get|post|server|cookies|session|env|request)((?:\.[a-z0-9_-]+)+)#i', $key, $m)) {
2665
-            $global = strtoupper($m[1]);
2666
-            if ($global === 'COOKIES') {
2667
-                $global = 'COOKIE';
2668
-            }
2669
-            $key = '$_' . $global;
2670
-            foreach (explode('.', ltrim($m[2], '.')) as $part) {
2671
-                $key .= '[' . var_export($part, true) . ']';
2672
-            }
2673
-            if ($curBlock === 'root') {
2674
-                $output = $key;
2675
-            } else {
2676
-                $output = '(isset(' . $key . ')?' . $key . ':null)';
2677
-            }
2678
-        } elseif (preg_match('#dwoo\\.const\\.([a-z0-9\\\\_:]+)#i', $key, $m)) {
2679
-            return $this->parseConstKey($m[1], $curBlock);
2680
-        } elseif ($this->scope !== null) {
2681
-            if (strstr($key, '.') === false && strstr($key, '[') === false && strstr($key, '->') === false) {
2682
-                if ($key === 'dwoo') {
2683
-                    $output = '$this->globals';
2684
-                } elseif ($key === '_root' || $key === '__') {
2685
-                    $output = '$this->data';
2686
-                } elseif ($key === '_parent' || $key === '_') {
2687
-                    $output = '$this->readParentVar(1)';
2688
-                } elseif ($key === '_key') {
2689
-                    $output = '$tmp_key';
2690
-                } else {
2691
-                    if ($curBlock === 'root') {
2692
-                        $output = '$this->scope["' . $key . '"]';
2693
-                    } else {
2694
-                        $output = '(isset($this->scope["' . $key . '"]) ? $this->scope["' . $key . '"] : null)';
2695
-                    }
2696
-                }
2697
-            } else {
2698
-                preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+|(\\\?[\'"])[^\3]*?\3)\]?#i', $key, $m);
2699
-
2700
-                $i = $m[2][0];
2701
-                if ($i === '_parent' || $i === '_') {
2702
-                    $parentCnt = 0;
2703
-
2704
-                    while (true) {
2705
-                        ++ $parentCnt;
2706
-                        array_shift($m[2]);
2707
-                        array_shift($m[1]);
2708
-                        if (current($m[2]) === '_parent') {
2709
-                            continue;
2710
-                        }
2711
-                        break;
2712
-                    }
2713
-
2714
-                    $output = '$this->readParentVar(' . $parentCnt . ')';
2715
-                } else {
2716
-                    if ($i === 'dwoo') {
2717
-                        $output = '$this->globals';
2718
-                        array_shift($m[2]);
2719
-                        array_shift($m[1]);
2720
-                    } elseif ($i === '_root' || $i === '__') {
2721
-                        $output = '$this->data';
2722
-                        array_shift($m[2]);
2723
-                        array_shift($m[1]);
2724
-                    } elseif ($i === '_key') {
2725
-                        $output = '$tmp_key';
2726
-                    } else {
2727
-                        $output = '$this->scope';
2728
-                    }
2729
-
2730
-                    while (count($m[1]) && $m[1][0] !== '->') {
2731
-                        $m[2][0] = preg_replace('/(^\\\([\'"])|\\\([\'"])$)/x', '$2$3', $m[2][0]);
2732
-                        if (substr($m[2][0], 0, 1) == '"' || substr($m[2][0], 0, 1) == "'") {
2733
-                            $output .= '[' . $m[2][0] . ']';
2734
-                        } else {
2735
-                            $output .= '["' . $m[2][0] . '"]';
2736
-                        }
2737
-                        array_shift($m[2]);
2738
-                        array_shift($m[1]);
2739
-                    }
2740
-
2741
-                    if ($curBlock !== 'root') {
2742
-                        $output = '(isset(' . $output . ') ? ' . $output . ':null)';
2743
-                    }
2744
-                }
2745
-
2746
-                if (count($m[2])) {
2747
-                    unset($m[0]);
2748
-                    $output = '$this->readVarInto(' . str_replace("\n", '', var_export($m, true)) . ', ' . $output . ', ' . ($curBlock == 'root' ? 'false' : 'true') . ')';
2749
-                }
2750
-            }
2751
-        } else {
2752
-            preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+)\]?#i', $key, $m);
2753
-            unset($m[0]);
2754
-            $output = '$this->readVar(' . str_replace("\n", '', var_export($m, true)) . ')';
2755
-        }
2756
-
2757
-        return $output;
2758
-    }
2759
-
2760
-    /**
2761
-     * Flattens a variable tree, this helps in parsing very complex variables such as $var.foo[$foo.bar->baz].baz,
2762
-     * it computes the contents of the brackets first and works out from there.
2763
-     *
2764
-     * @param array $tree     the variable tree parsed by he parseVar() method that must be flattened
2765
-     * @param bool  $recursed leave that to false by default, it is only for internal use
2766
-     *
2767
-     * @return string flattened tree
2768
-     */
2769
-    protected function flattenVarTree(array $tree, $recursed = false)
2770
-    {
2771
-        $out = $recursed ? '".$this->readVarInto(' : '';
2772
-        foreach ($tree as $bit) {
2773
-            if (is_array($bit)) {
2774
-                $out .= '.' . $this->flattenVarTree($bit, false);
2775
-            } else {
2776
-                $key = str_replace('"', '\\"', $bit);
2777
-
2778
-                if (substr($key, 0, 1) === '$') {
2779
-                    $out .= '".' . $this->parseVar($key, 0, strlen($key), false, 'variable') . '."';
2780
-                } else {
2781
-                    $cnt = substr_count($key, '$');
2782
-
2783
-                    if ($this->debug) {
2784
-                        echo 'PARSING SUBVARS IN : ' . $key . "\n";
2785
-                    }
2786
-                    if ($cnt > 0) {
2787
-                        while (-- $cnt >= 0) {
2788
-                            if (isset($last)) {
2789
-                                $last = strrpos($key, '$', - (strlen($key) - $last + 1));
2790
-                            } else {
2791
-                                $last = strrpos($key, '$');
2792
-                            }
2793
-                            preg_match('#\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', substr($key, $last), $submatch);
2794
-
2795
-                            $len = strlen($submatch[0]);
2796
-                            $key = substr_replace(
2797
-                                $key, preg_replace_callback(
2798
-                                    '#(\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*)' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', array(
2799
-                                        $this,
2800
-                                        'replaceVarKeyHelper'
2801
-                                    ), substr($key, $last, $len)
2802
-                                ), $last, $len
2803
-                            );
2804
-                            if ($this->debug) {
2805
-                                echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2806
-                            }
2807
-                        }
2808
-                        unset($last);
2809
-
2810
-                        $out .= $key;
2811
-                    } else {
2812
-                        $out .= $key;
2813
-                    }
2814
-                }
2815
-            }
2816
-        }
2817
-        $out .= $recursed ? ', true)."' : '';
2818
-
2819
-        return $out;
2820
-    }
2821
-
2822
-    /**
2823
-     * Helper function that parses a variable.
2824
-     *
2825
-     * @param array $match the matched variable, array(1=>"string match")
2826
-     *
2827
-     * @return string parsed variable
2828
-     */
2829
-    protected function replaceVarKeyHelper($match)
2830
-    {
2831
-        return '".' . $this->parseVar($match[0], 0, strlen($match[0]), false, 'variable') . '."';
2832
-    }
2833
-
2834
-    /**
2835
-     * Parses various constants, operators or non-quoted strings.
2836
-     *
2837
-     * @param string $in            the string within which we must parse something
2838
-     * @param int    $from          the starting offset of the parsed area
2839
-     * @param int    $to            the ending offset of the parsed area
2840
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2841
-     *                              default
2842
-     * @param string $curBlock      the current parser-block being processed
2843
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2844
-     *                              or null by default
2845
-     *
2846
-     * @return string parsed values
2847
-     * @throws Exception
2848
-     */
2849
-    protected function parseOthers($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2850
-    {
2851
-        $substr = substr($in, $from, $to - $from);
2852
-
2853
-        $end = strlen($substr);
2854
-
2855
-        if ($curBlock === 'condition') {
2856
-            $breakChars = array(
2857
-                '(',
2858
-                ')',
2859
-                ' ',
2860
-                '||',
2861
-                '&&',
2862
-                '|',
2863
-                '&',
2864
-                '>=',
2865
-                '<=',
2866
-                '===',
2867
-                '==',
2868
-                '=',
2869
-                '!==',
2870
-                '!=',
2871
-                '<<',
2872
-                '<',
2873
-                '>>',
2874
-                '>',
2875
-                '^',
2876
-                '~',
2877
-                ',',
2878
-                '+',
2879
-                '-',
2880
-                '*',
2881
-                '/',
2882
-                '%',
2883
-                '!',
2884
-                '?',
2885
-                ':',
2886
-                $this->rd,
2887
-                ';'
2888
-            );
2889
-        } elseif ($curBlock === 'modifier') {
2890
-            $breakChars = array(' ', ',', ')', ':', '|', "\r", "\n", "\t", ';', $this->rd);
2891
-        } elseif ($curBlock === 'expression') {
2892
-            $breakChars = array('/', '%', '+', '-', '*', ' ', ',', ')', "\r", "\n", "\t", ';', $this->rd);
2893
-        } else {
2894
-            $breakChars = array(' ', ',', ')', "\r", "\n", "\t", ';', $this->rd);
2895
-        }
2896
-
2897
-        $breaker = false;
2898
-        foreach ($breakChars as $k => $char) {
2899
-            $test = strpos($substr, $char);
2900
-            if ($test !== false && $test < $end) {
2901
-                $end     = $test;
2902
-                $breaker = $k;
2903
-            }
2904
-        }
2905
-
2906
-        if ($curBlock === 'condition') {
2907
-            if ($end === 0 && $breaker !== false) {
2908
-                $end = strlen($breakChars[$breaker]);
2909
-            }
2910
-        }
2911
-
2912
-        if ($end !== false) {
2913
-            $substr = substr($substr, 0, $end);
2914
-        }
2915
-
2916
-        if ($pointer !== null) {
2917
-            $pointer += strlen($substr);
2918
-        }
2919
-
2920
-        $src    = $substr;
2921
-        $substr = trim($substr);
2922
-
2923
-        if (strtolower($substr) === 'false' || strtolower($substr) === 'no' || strtolower($substr) === 'off') {
2924
-            if ($this->debug) {
2925
-                echo 'BOOLEAN(FALSE) PARSED' . "\n";
2926
-            }
2927
-            $substr = 'false';
2928
-            $type   = self::T_BOOL;
2929
-        } elseif (strtolower($substr) === 'true' || strtolower($substr) === 'yes' || strtolower($substr) === 'on') {
2930
-            if ($this->debug) {
2931
-                echo 'BOOLEAN(TRUE) PARSED' . "\n";
2932
-            }
2933
-            $substr = 'true';
2934
-            $type   = self::T_BOOL;
2935
-        } elseif ($substr === 'null' || $substr === 'NULL') {
2936
-            if ($this->debug) {
2937
-                echo 'NULL PARSED' . "\n";
2938
-            }
2939
-            $substr = 'null';
2940
-            $type   = self::T_NULL;
2941
-        } elseif (is_numeric($substr)) {
2942
-            $substr = (float)$substr;
2943
-            if ((int)$substr == $substr) {
2944
-                $substr = (int)$substr;
2945
-            }
2946
-            $type = self::T_NUMERIC;
2947
-            if ($this->debug) {
2948
-                echo 'NUMBER (' . $substr . ') PARSED' . "\n";
2949
-            }
2950
-        } elseif (preg_match('{^-?(\d+|\d*(\.\d+))\s*([/*%+-]\s*-?(\d+|\d*(\.\d+)))+$}', $substr)) {
2951
-            if ($this->debug) {
2952
-                echo 'SIMPLE MATH PARSED . "\n"';
2953
-            }
2954
-            $type   = self::T_MATH;
2955
-            $substr = '(' . $substr . ')';
2956
-        } elseif ($curBlock === 'condition' && array_search($substr, $breakChars, true) !== false) {
2957
-            if ($this->debug) {
2958
-                echo 'BREAKCHAR (' . $substr . ') PARSED' . "\n";
2959
-            }
2960
-            $type = self::T_BREAKCHAR;
2961
-            //$substr = '"'.$substr.'"';
2962
-        } else {
2963
-            $substr = $this->replaceStringVars('\'' . str_replace('\'', '\\\'', $substr) . '\'', '\'', $curBlock);
2964
-            $type   = self::T_UNQUOTED_STRING;
2965
-            if ($this->debug) {
2966
-                echo 'BLABBER (' . $substr . ') CASTED AS STRING' . "\n";
2967
-            }
2968
-        }
2969
-
2970
-        if (is_array($parsingParams)) {
2971
-            $parsingParams[] = array($substr, $src, $type);
2972
-
2973
-            return $parsingParams;
2974
-        } elseif ($curBlock === 'namedparam') {
2975
-            return array($substr, $src, $type);
2976
-        } elseif ($curBlock === 'expression') {
2977
-            return $substr;
2978
-        } else {
2979
-            throw new Exception('Something went wrong');
2980
-        }
2981
-    }
2982
-
2983
-    /**
2984
-     * Replaces variables within a parsed string.
2985
-     *
2986
-     * @param string $string   the parsed string
2987
-     * @param string $first    the first character parsed in the string, which is the string delimiter (' or ")
2988
-     * @param string $curBlock the current parser-block being processed
2989
-     *
2990
-     * @return string the original string with variables replaced
2991
-     */
2992
-    protected function replaceStringVars($string, $first, $curBlock = '')
2993
-    {
2994
-        $pos = 0;
2995
-        if ($this->debug) {
2996
-            echo 'STRING VAR REPLACEMENT : ' . $string . "\n";
2997
-        }
2998
-        // replace vars
2999
-        while (($pos = strpos($string, '$', $pos)) !== false) {
3000
-            $prev = substr($string, $pos - 1, 1);
3001
-            if ($prev === '\\') {
3002
-                ++ $pos;
3003
-                continue;
3004
-            }
3005
-
3006
-            $var = $this->parse($string, $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3007
-            $len = $var[0];
3008
-            $var = $this->parse(str_replace('\\' . $first, $first, $string), $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3009
-
3010
-            if ($prev === '`' && substr($string, $pos + $len, 1) === '`') {
3011
-                $string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos - 1, $len + 2);
3012
-            } else {
3013
-                $string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos, $len);
3014
-            }
3015
-            $pos += strlen($var[1]) + 2;
3016
-            if ($this->debug) {
3017
-                echo 'STRING VAR REPLACEMENT DONE : ' . $string . "\n";
3018
-            }
3019
-        }
3020
-
3021
-        // handle modifiers
3022
-        // TODO Obsolete?
3023
-        $string = preg_replace_callback(
3024
-            '#("|\')\.(.+?)\.\1((?:\|(?:@?[a-z0-9_]+(?:(?::("|\').+?\4|:[^`]*))*))+)#i', array(
3025
-            $this,
3026
-            'replaceModifiers'
3027
-            ), $string
3028
-        );
3029
-
3030
-        // replace escaped dollar operators by unescaped ones if required
3031
-        if ($first === "'") {
3032
-            $string = str_replace('\\$', '$', $string);
3033
-        }
3034
-
3035
-        return $string;
3036
-    }
3037
-
3038
-    /**
3039
-     * Replaces the modifiers applied to a string or a variable.
3040
-     *
3041
-     * @param array  $m        the regex matches that must be array(1=>"double or single quotes enclosing a string,
3042
-     *                         when applicable", 2=>"the string or var", 3=>"the modifiers matched")
3043
-     * @param string $curBlock the current parser-block being processed
3044
-     * @param null   $pointer
3045
-     *
3046
-     * @return string the input enclosed with various function calls according to the modifiers found
3047
-     * @throws CompilationException
3048
-     * @throws Exception
3049
-     */
3050
-    protected function replaceModifiers(array $m, $curBlock = null, &$pointer = null)
3051
-    {
3052
-        if ($this->debug) {
3053
-            echo 'PARSING MODIFIERS : ' . $m[3] . "\n";
3054
-        }
3055
-
3056
-        if ($pointer !== null) {
3057
-            $pointer += strlen($m[3]);
3058
-        }
3059
-        // remove first pipe
3060
-        $cmdstrsrc = substr($m[3], 1);
3061
-        // remove last quote if present
3062
-        if (substr($cmdstrsrc, - 1, 1) === $m[1]) {
3063
-            $cmdstrsrc = substr($cmdstrsrc, 0, - 1);
3064
-            $add       = $m[1];
3065
-        }
3066
-
3067
-        $output = $m[2];
3068
-
3069
-        $continue = true;
3070
-        while (strlen($cmdstrsrc) > 0 && $continue) {
3071
-            if ($cmdstrsrc[0] === '|') {
3072
-                $cmdstrsrc = substr($cmdstrsrc, 1);
3073
-                continue;
3074
-            }
3075
-            if ($cmdstrsrc[0] === ' ' || $cmdstrsrc[0] === ';' || substr($cmdstrsrc, 0, strlen($this->rd)) === $this->rd) {
3076
-                if ($this->debug) {
3077
-                    echo 'MODIFIER PARSING ENDED, RIGHT DELIMITER or ";" FOUND' . "\n";
3078
-                }
3079
-                $continue = false;
3080
-                if ($pointer !== null) {
3081
-                    $pointer -= strlen($cmdstrsrc);
3082
-                }
3083
-                break;
3084
-            }
3085
-            $cmdstr   = $cmdstrsrc;
3086
-            $paramsep = ':';
3087
-            if (!preg_match('/^(@{0,2}[a-z_][a-z0-9_]*)(:)?/i', $cmdstr, $match)) {
3088
-                throw new CompilationException($this, 'Invalid modifier name, started with : ' . substr($cmdstr, 0, 10));
3089
-            }
3090
-            $paramspos = !empty($match[2]) ? strlen($match[1]) : false;
3091
-            $func      = $match[1];
3092
-
3093
-            $state = 0;
3094
-            if ($paramspos === false) {
3095
-                $cmdstrsrc = substr($cmdstrsrc, strlen($func));
3096
-                $params    = array();
3097
-                if ($this->debug) {
3098
-                    echo 'MODIFIER (' . $func . ') CALLED WITH NO PARAMS' . "\n";
3099
-                }
3100
-            } else {
3101
-                $paramstr = substr($cmdstr, $paramspos + 1);
3102
-                if (substr($paramstr, - 1, 1) === $paramsep) {
3103
-                    $paramstr = substr($paramstr, 0, - 1);
3104
-                }
3105
-
3106
-                $ptr    = 0;
3107
-                $params = array();
3108
-                while ($ptr < strlen($paramstr)) {
3109
-                    if ($this->debug) {
3110
-                        echo 'MODIFIER (' . $func . ') START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
3111
-                    }
3112
-                    if ($this->debug) {
3113
-                        echo $paramstr . '--' . $ptr . '--' . strlen($paramstr) . '--modifier' . "\n";
3114
-                    }
3115
-                    $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'modifier', $ptr);
3116
-                    if ($this->debug) {
3117
-                        echo 'PARAM PARSED, POINTER AT ' . $ptr . "\n";
3118
-                    }
3119
-
3120
-                    if ($ptr >= strlen($paramstr)) {
3121
-                        if ($this->debug) {
3122
-                            echo 'PARAM PARSING ENDED, PARAM STRING CONSUMED' . "\n";
3123
-                        }
3124
-                        break;
3125
-                    }
3126
-
3127
-                    if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === '|' || $paramstr[$ptr] === ';' || substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
3128
-                        if ($this->debug) {
3129
-                            echo 'PARAM PARSING ENDED, " ", "|", RIGHT DELIMITER or ";" FOUND, POINTER AT ' . $ptr . "\n";
3130
-                        }
3131
-                        if ($paramstr[$ptr] !== '|') {
3132
-                            $continue = false;
3133
-                            if ($pointer !== null) {
3134
-                                $pointer -= strlen($paramstr) - $ptr;
3135
-                            }
3136
-                        }
3137
-                        ++ $ptr;
3138
-                        break;
3139
-                    }
3140
-                    if ($ptr < strlen($paramstr) && $paramstr[$ptr] === ':') {
3141
-                        ++ $ptr;
3142
-                    }
3143
-                }
3144
-                $cmdstrsrc = substr($cmdstrsrc, strlen($func) + 1 + $ptr);
3145
-                foreach ($params as $k => $p) {
3146
-                    if (is_array($p) && is_array($p[1])) {
3147
-                        $state |= 2;
3148
-                    } else {
3149
-                        if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m)) {
3150
-                            $params[$k] = array($m[2], array('true', 'true'));
3151
-                        } else {
3152
-                            if ($state & 2) {
3153
-                                throw new CompilationException($this, 'You can not use an unnamed parameter after a named one');
3154
-                            }
3155
-                            $state |= 1;
3156
-                        }
3157
-                    }
3158
-                }
3159
-            }
3160
-
3161
-            // check if we must use array_map with this plugin or not
3162
-            $mapped = false;
3163
-            if (substr($func, 0, 1) === '@') {
3164
-                $func   = substr($func, 1);
3165
-                $mapped = true;
3166
-            }
3167
-
3168
-            $pluginType = $this->getPluginType($func);
3169
-
3170
-            if ($state & 2) {
3171
-                array_unshift($params, array('value', is_array($output) ? $output : array($output, $output)));
3172
-            } else {
3173
-                array_unshift($params, is_array($output) ? $output : array($output, $output));
3174
-            }
3175
-
3176
-            if ($pluginType & Core::NATIVE_PLUGIN) {
3177
-                $params = $this->mapParams($params, null, $state);
3178
-
3179
-                $params = $params['*'][0];
3180
-
3181
-                $params = self::implode_r($params);
3182
-
3183
-                if ($mapped) {
3184
-                    $output = '$this->arrayMap(\'' . $func . '\', array(' . $params . '))';
3185
-                } else {
3186
-                    $output = $func . '(' . $params . ')';
3187
-                }
3188
-            } elseif ($pluginType & Core::PROXY_PLUGIN) {
3189
-                $params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state);
3190
-                foreach ($params as &$p) {
3191
-                    $p = $p[0];
3192
-                }
3193
-                $output = call_user_func(array($this->getDwoo()->getPluginProxy(), 'getCode'), $func, $params);
3194
-            } elseif ($pluginType & Core::SMARTY_MODIFIER) {
3195
-                $params = $this->mapParams($params, null, $state);
3196
-                $params = $params['*'][0];
3197
-
3198
-                $params = self::implode_r($params);
3199
-
3200
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
3201
-                    $callback = $this->customPlugins[$func]['callback'];
3202
-                    if (is_array($callback)) {
3203
-                        if (is_object($callback[0])) {
3204
-                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(' . $params . '))';
3205
-                        } else {
3206
-                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3207
-                        }
3208
-                    } elseif ($mapped) {
3209
-                        $output = '$this->arrayMap(\'' . $callback . '\', array(' . $params . '))';
3210
-                    } else {
3211
-                        $output = $callback . '(' . $params . ')';
3212
-                    }
3213
-                } elseif ($mapped) {
3214
-                    $output = '$this->arrayMap(\'smarty_modifier_' . $func . '\', array(' . $params . '))';
3215
-                } else {
3216
-                    $output = 'smarty_modifier_' . $func . '(' . $params . ')';
3217
-                }
3218
-            } else {
3219
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
3220
-                    $callback   = $this->customPlugins[$func]['callback'];
3221
-                    $pluginName = $callback;
3222
-                } else {
3223
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false || function_exists('Plugin' .
3224
-                            Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''))
3225
-                        !== false) {
3226
-                        $pluginName = 'Plugin' . Core::toCamelCase($func);
3227
-                    } else {
3228
-                        $pluginName = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func);
3229
-                    }
3230
-                    if ($pluginType & Core::CLASS_PLUGIN) {
3231
-                        $callback = array($pluginName, ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process');
3232
-                    } else {
3233
-                        $callback = $pluginName . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '');
3234
-                    }
3235
-                }
3236
-                $params = $this->mapParams($params, $callback, $state);
3237
-
3238
-                foreach ($params as &$p) {
3239
-                    $p = $p[0];
3240
-                }
3241
-
3242
-                // Only for PHP function, who is not a PHP class
3243
-                if ($pluginType & Core::FUNC_PLUGIN && !($pluginType & Core::CLASS_PLUGIN)) {
3244
-                    if ($pluginType & Core::COMPILABLE_PLUGIN) {
3245
-                        if ($mapped) {
3246
-                            throw new CompilationException($this, 'The @ operator can not be used on compiled plugins.');
3247
-                        }
3248
-                        if ($pluginType & Core::CUSTOM_PLUGIN) {
3249
-                            $funcCompiler = $this->customPlugins[$func]['callback'];
3250
-                        } else {
3251
-                            if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
3252
-                                $funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
3253
-                            } else {
3254
-                                $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
3255
-                                    'Compile';
3256
-                            }
3257
-                        }
3258
-                        array_unshift($params, $this);
3259
-                        $output = call_user_func_array($funcCompiler, $params);
3260
-                    } else {
3261
-                        array_unshift($params, '$this');
3262
-
3263
-                        $params = self::implode_r($params);
3264
-                        if ($mapped) {
3265
-                            $output = '$this->arrayMap(\'' . $pluginName . '\', array(' . $params . '))';
3266
-                        } else {
3267
-                            $output = $pluginName . '(' . $params . ')';
3268
-                        }
3269
-                    }
3270
-                } else {
3271
-                    if ($pluginType & Core::COMPILABLE_PLUGIN) {
3272
-                        if ($mapped) {
3273
-                            throw new CompilationException($this, 'The @ operator can not be used on compiled plugins.');
3274
-                        }
3275
-                        if ($pluginType & Core::CUSTOM_PLUGIN) {
3276
-                            $callback = $this->customPlugins[$func]['callback'];
3277
-                            if (!is_array($callback)) {
3278
-                                if (!method_exists($callback, 'compile')) {
3279
-                                    throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
3280
-                                }
3281
-                                if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
3282
-                                    $funcCompiler = array($callback, 'compile');
3283
-                                } else {
3284
-                                    $funcCompiler = array(new $callback(), 'compile');
3285
-                                }
3286
-                            } else {
3287
-                                $funcCompiler = $callback;
3288
-                            }
3289
-                        } else {
3290
-                            if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3291
-                                $funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
3292
-                            } else {
3293
-                                $funcCompiler = array(
3294
-                                    Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
3295
-                                    'compile'
3296
-                                );
3297
-                            }
3298
-                            array_unshift($params, $this);
3299
-                        }
3300
-                        $output = call_user_func_array($funcCompiler, $params);
3301
-                    } else {
3302
-                        $params = self::implode_r($params);
3303
-
3304
-                        if ($pluginType & Core::CUSTOM_PLUGIN) {
3305
-                            if (is_object($callback[0])) {
3306
-                                $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(' . $params . '))';
3307
-                            } else {
3308
-                                $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3309
-                            }
3310
-                        } elseif ($mapped) {
3311
-                            $output = '$this->arrayMap(array($this->getObjectPlugin(\''.
3312
-                                Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '\'), 
2092
+					} else {
2093
+						$output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
2094
+					}
2095
+				}
2096
+			}
2097
+		} // Function plugin only (cannot be a class)
2098
+		elseif ($pluginType & Core::FUNC_PLUGIN) {
2099
+			if ($pluginType & Core::COMPILABLE_PLUGIN) {
2100
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
2101
+					$funcCompiler = $this->customPlugins[$func]['callback'];
2102
+				} else {
2103
+					// Custom plugin
2104
+					if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2105
+						$funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
2106
+					} // Builtin helper plugin
2107
+					elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2108
+						$funcCompiler = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) .
2109
+							'Compile';
2110
+					} // Builtin function plugin
2111
+					else {
2112
+						$funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
2113
+							'Compile';
2114
+					}
2115
+				}
2116
+				array_unshift($params, $this);
2117
+				// @TODO: Is it a real fix ?
2118
+				if ($func === 'tif') {
2119
+					$params[] = $tokens;
2120
+				}
2121
+				$output = call_user_func_array($funcCompiler, $params);
2122
+			} else {
2123
+				array_unshift($params, '$this');
2124
+				$params = self::implode_r($params);
2125
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
2126
+					$callback = $this->customPlugins[$func]['callback'];
2127
+					if ($callback instanceof Closure) {
2128
+						$output = 'call_user_func($this->getCustomPlugin(\'' . $func . '\'), ' . $params . ')';
2129
+					} else {
2130
+						$output = 'call_user_func(\'' . $callback . '\', ' . $params . ')';
2131
+					}
2132
+				} else {
2133
+					// Custom plugin
2134
+					if (function_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2135
+						$output = 'Plugin' . Core::toCamelCase($func) . '(' . $params .
2136
+							')';
2137
+					} // Builtin helper plugin
2138
+					elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !==
2139
+						false) {
2140
+						$output = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . '(' .
2141
+							$params . ')';
2142
+					} // Builtin function plugin
2143
+					else {
2144
+						$output = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '(' .
2145
+							$params . ')';
2146
+					}
2147
+				}
2148
+			}
2149
+		} // Proxy plugin
2150
+		elseif ($pluginType & Core::PROXY_PLUGIN) {
2151
+			$output = call_user_func(array($this->getDwoo()->getPluginProxy(), 'getCode'), $func, $params);
2152
+		} // Smarty function (@deprecated)
2153
+		elseif ($pluginType & Core::SMARTY_FUNCTION) {
2154
+			$params = '';
2155
+			if (isset($params['*'])) {
2156
+				$params = self::implode_r($params['*'], true);
2157
+			}
2158
+
2159
+			if ($pluginType & Core::CUSTOM_PLUGIN) {
2160
+				$callback = $this->customPlugins[$func]['callback'];
2161
+				if (is_array($callback)) {
2162
+					if (is_object($callback[0])) {
2163
+						$output = 'call_user_func_array(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2164
+					} else {
2165
+						$output = 'call_user_func_array(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2166
+					}
2167
+				} else {
2168
+					$output = $callback . '(array(' . $params . '), $this)';
2169
+				}
2170
+			} else {
2171
+				$output = 'smarty_function_' . $func . '(array(' . $params . '), $this)';
2172
+			}
2173
+		} // Template plugin
2174
+		elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
2175
+			array_unshift($params, '$this');
2176
+			$params                                 = self::implode_r($params);
2177
+			$output                                 = 'Plugin' . Core::toCamelCase($func) .
2178
+				$this->templatePlugins[$func]['uuid'] . '(' . $params . ')';
2179
+			$this->templatePlugins[$func]['called'] = true;
2180
+		}
2181
+
2182
+		if (is_array($parsingParams)) {
2183
+			$parsingParams[] = array($output, $output);
2184
+
2185
+			return $parsingParams;
2186
+		} elseif ($curBlock === 'namedparam') {
2187
+			return array($output, $output);
2188
+		}
2189
+
2190
+		return $output;
2191
+	}
2192
+
2193
+	/**
2194
+	 * Parses a string.
2195
+	 *
2196
+	 * @param string $in            the string within which we must parse something
2197
+	 * @param int    $from          the starting offset of the parsed area
2198
+	 * @param int    $to            the ending offset of the parsed area
2199
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2200
+	 *                              default
2201
+	 * @param string $curBlock      the current parser-block being processed
2202
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2203
+	 *                              or null by default
2204
+	 *
2205
+	 * @return string parsed values
2206
+	 * @throws CompilationException
2207
+	 */
2208
+	protected function parseString($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2209
+	{
2210
+		$substr = substr($in, $from, $to - $from);
2211
+		$first  = $substr[0];
2212
+
2213
+		if ($this->debug) {
2214
+			echo 'STRING FOUND (in ' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . ')' . "\n";
2215
+		}
2216
+		$strend = false;
2217
+		$o      = $from + 1;
2218
+		while ($strend === false) {
2219
+			$strend = strpos($in, $first, $o);
2220
+			if ($strend === false) {
2221
+				throw new CompilationException($this, 'Unfinished string, started with ' . substr($in, $from, $to - $from));
2222
+			}
2223
+			if (substr($in, $strend - 1, 1) === '\\') {
2224
+				$o      = $strend + 1;
2225
+				$strend = false;
2226
+			}
2227
+		}
2228
+		if ($this->debug) {
2229
+			echo 'STRING DELIMITED: ' . substr($in, $from, $strend + 1 - $from) . "\n";
2230
+		}
2231
+
2232
+		$srcOutput = substr($in, $from, $strend + 1 - $from);
2233
+
2234
+		if ($pointer !== null) {
2235
+			$pointer += strlen($srcOutput);
2236
+		}
2237
+
2238
+		$output = $this->replaceStringVars($srcOutput, $first);
2239
+
2240
+		// handle modifiers
2241
+		if ($curBlock !== 'modifier' && preg_match('#^((?:\|(?:@?[a-z0-9_]+(?::.*)*))+)#i', substr($substr, $strend + 1 - $from), $match)) {
2242
+			$modstr = $match[1];
2243
+
2244
+			if ($curBlock === 'root' && substr($modstr, - 1) === '}') {
2245
+				$modstr = substr($modstr, 0, - 1);
2246
+			}
2247
+			$modstr = str_replace('\\' . $first, $first, $modstr);
2248
+			$ptr    = 0;
2249
+			$output = $this->replaceModifiers(array(null, null, $output, $modstr), 'string', $ptr);
2250
+
2251
+			$strend += $ptr;
2252
+			if ($pointer !== null) {
2253
+				$pointer += $ptr;
2254
+			}
2255
+			$srcOutput .= substr($substr, $strend + 1 - $from, $ptr);
2256
+		}
2257
+
2258
+		if (is_array($parsingParams)) {
2259
+			$parsingParams[] = array($output, substr($srcOutput, 1, - 1));
2260
+
2261
+			return $parsingParams;
2262
+		} elseif ($curBlock === 'namedparam') {
2263
+			return array($output, substr($srcOutput, 1, - 1));
2264
+		} else {
2265
+			return $output;
2266
+		}
2267
+	}
2268
+
2269
+	/**
2270
+	 * Parses a constant.
2271
+	 *
2272
+	 * @param string $in            the string within which we must parse something
2273
+	 * @param int    $from          the starting offset of the parsed area
2274
+	 * @param int    $to            the ending offset of the parsed area
2275
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2276
+	 *                              default
2277
+	 * @param string $curBlock      the current parser-block being processed
2278
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2279
+	 *                              or null by default
2280
+	 *
2281
+	 * @return string parsed values
2282
+	 * @throws CompilationException
2283
+	 */
2284
+	protected function parseConst($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2285
+	{
2286
+		$substr = substr($in, $from, $to - $from);
2287
+
2288
+		if ($this->debug) {
2289
+			echo 'CONST FOUND : ' . $substr . "\n";
2290
+		}
2291
+
2292
+		if (!preg_match('#^%([\\\\a-z0-9_:]+)#i', $substr, $m)) {
2293
+			throw new CompilationException($this, 'Invalid constant');
2294
+		}
2295
+
2296
+		if ($pointer !== null) {
2297
+			$pointer += strlen($m[0]);
2298
+		}
2299
+
2300
+		$output = $this->parseConstKey($m[1], $curBlock);
2301
+
2302
+		if (is_array($parsingParams)) {
2303
+			$parsingParams[] = array($output, $m[1]);
2304
+
2305
+			return $parsingParams;
2306
+		} elseif ($curBlock === 'namedparam') {
2307
+			return array($output, $m[1]);
2308
+		} else {
2309
+			return $output;
2310
+		}
2311
+	}
2312
+
2313
+	/**
2314
+	 * Parses a constant.
2315
+	 *
2316
+	 * @param string $key      the constant to parse
2317
+	 * @param string $curBlock the current parser-block being processed
2318
+	 *
2319
+	 * @return string parsed constant
2320
+	 */
2321
+	protected function parseConstKey($key, $curBlock)
2322
+	{
2323
+		if ($this->securityPolicy !== null && $this->securityPolicy->getConstantHandling() === SecurityPolicy::CONST_DISALLOW) {
2324
+			return 'null';
2325
+		}
2326
+
2327
+		if ($curBlock !== 'root') {
2328
+			$output = '(defined("' . $key . '") ? ' . $key . ' : null)';
2329
+		} else {
2330
+			$output = $key;
2331
+		}
2332
+
2333
+		return $output;
2334
+	}
2335
+
2336
+	/**
2337
+	 * Parses a variable.
2338
+	 *
2339
+	 * @param string $in            the string within which we must parse something
2340
+	 * @param int    $from          the starting offset of the parsed area
2341
+	 * @param int    $to            the ending offset of the parsed area
2342
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2343
+	 *                              default
2344
+	 * @param string $curBlock      the current parser-block being processed
2345
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2346
+	 *                              or null by default
2347
+	 *
2348
+	 * @return string parsed values
2349
+	 * @throws CompilationException
2350
+	 */
2351
+	protected function parseVar($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2352
+	{
2353
+		$substr = substr($in, $from, $to - $from);
2354
+
2355
+		// var key
2356
+		$varRegex = '(\\$?\\.?[a-z0-9\\\\_:]*(?:(?:(?:\\.|->)(?:[a-z0-9\\\\_:]+|(?R))|\\[(?:[a-z0-9\\\\_:]+|(?R)|(["\'])[^\\2]*?\\2)\\]))*)';
2357
+		// method call
2358
+		$methodCall = ($curBlock === 'root' || $curBlock === 'function' || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'variable' || $curBlock === 'expression' || $curBlock === 'delimited_string' ? '(\(.*)?' : '()');
2359
+		// simple math expressions
2360
+		$simpleMathExpressions = ($curBlock === 'root' || $curBlock === 'function' || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'variable' || $curBlock === 'delimited_string' ? '((?:(?:[+\/*%=-])(?:(?<!=)=?-?[$%][a-z0-9\\\\.[\]>_:-]+(?:\([^)]*\))?|(?<!=)=?-?[0-9\.,]*|[+-]))*)' : '()');
2361
+		// modifiers
2362
+		$modifiers = $curBlock !== 'modifier' ? '((?:\|(?:@?[a-z0-9\\\\_]+(?:(?::("|\').*?\5|:[^`]*))*))+)?' : '(())';
2363
+
2364
+		$regex = '#';
2365
+		$regex .= $varRegex;
2366
+		$regex .= $methodCall;
2367
+		$regex .= $simpleMathExpressions;
2368
+		$regex .= $modifiers;
2369
+		$regex .= '#i';
2370
+
2371
+		if (preg_match($regex, $substr, $match)) {
2372
+			$key = substr($match[1], 1);
2373
+
2374
+			$matchedLength = strlen($match[0]);
2375
+			$hasModifiers  = !empty($match[5]);
2376
+			$hasExpression = !empty($match[4]);
2377
+			$hasMethodCall = !empty($match[3]);
2378
+
2379
+			if (substr($key, - 1) == '.') {
2380
+				$key = substr($key, 0, - 1);
2381
+				-- $matchedLength;
2382
+			}
2383
+
2384
+			if ($hasMethodCall) {
2385
+				$matchedLength -= strlen($match[3]) + strlen(substr($match[1], strrpos($match[1], '->')));
2386
+				$key        = substr($match[1], 1, strrpos($match[1], '->') - 1);
2387
+				$methodCall = substr($match[1], strrpos($match[1], '->')) . $match[3];
2388
+			}
2389
+
2390
+			if ($hasModifiers) {
2391
+				$matchedLength -= strlen($match[5]);
2392
+			}
2393
+
2394
+			if ($pointer !== null) {
2395
+				$pointer += $matchedLength;
2396
+			}
2397
+
2398
+			// replace useless brackets by dot accessed vars and strip enclosing quotes if present
2399
+			$key = preg_replace('#\[(["\']?)([^$%\[.>-]+)\1\]#', '.$2', $key);
2400
+
2401
+			if ($this->debug) {
2402
+				if ($hasMethodCall) {
2403
+					echo 'METHOD CALL FOUND : $' . $key . substr($methodCall, 0, 30) . "\n";
2404
+				} else {
2405
+					echo 'VAR FOUND : $' . $key . "\n";
2406
+				}
2407
+			}
2408
+
2409
+			$key = str_replace('"', '\\"', $key);
2410
+
2411
+			$cnt = substr_count($key, '$');
2412
+			if ($cnt > 0) {
2413
+				$uid           = 0;
2414
+				$parsed        = array($uid => '');
2415
+				$current       = &$parsed;
2416
+				$curTxt        = &$parsed[$uid ++];
2417
+				$tree          = array();
2418
+				$chars         = str_split($key, 1);
2419
+				$inSplittedVar = false;
2420
+				$bracketCount  = 0;
2421
+
2422
+				while (($char = array_shift($chars)) !== null) {
2423
+					if ($char === '[') {
2424
+						if (count($tree) > 0) {
2425
+							++ $bracketCount;
2426
+						} else {
2427
+							$tree[]        = &$current;
2428
+							$current[$uid] = array($uid + 1 => '');
2429
+							$current       = &$current[$uid ++];
2430
+							$curTxt        = &$current[$uid ++];
2431
+							continue;
2432
+						}
2433
+					} elseif ($char === ']') {
2434
+						if ($bracketCount > 0) {
2435
+							-- $bracketCount;
2436
+						} else {
2437
+							$current = &$tree[count($tree) - 1];
2438
+							array_pop($tree);
2439
+							if (current($chars) !== '[' && current($chars) !== false && current($chars) !== ']') {
2440
+								$current[$uid] = '';
2441
+								$curTxt        = &$current[$uid ++];
2442
+							}
2443
+							continue;
2444
+						}
2445
+					} elseif ($char === '$') {
2446
+						if (count($tree) == 0) {
2447
+							$curTxt        = &$current[$uid ++];
2448
+							$inSplittedVar = true;
2449
+						}
2450
+					} elseif (($char === '.' || $char === '-') && count($tree) == 0 && $inSplittedVar) {
2451
+						$curTxt        = &$current[$uid ++];
2452
+						$inSplittedVar = false;
2453
+					}
2454
+
2455
+					$curTxt .= $char;
2456
+				}
2457
+				unset($uid, $current, $curTxt, $tree, $chars);
2458
+
2459
+				if ($this->debug) {
2460
+					echo 'RECURSIVE VAR REPLACEMENT : ' . $key . "\n";
2461
+				}
2462
+
2463
+				$key = $this->flattenVarTree($parsed);
2464
+
2465
+				if ($this->debug) {
2466
+					echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2467
+				}
2468
+
2469
+				$output = preg_replace('#(^""\.|""\.|\.""$|(\()""\.|\.""(\)))#', '$2$3', '$this->readVar("' . $key . '")');
2470
+			} else {
2471
+				$output = $this->parseVarKey($key, $hasModifiers ? 'modifier' : $curBlock);
2472
+			}
2473
+
2474
+
2475
+			// methods
2476
+			if ($hasMethodCall) {
2477
+				$ptr = 0;
2478
+
2479
+				$output = $this->parseMethodCall($output, $methodCall, $curBlock, $ptr);
2480
+
2481
+				if ($pointer !== null) {
2482
+					$pointer += $ptr;
2483
+				}
2484
+				$matchedLength += $ptr;
2485
+			}
2486
+
2487
+			if ($hasExpression) {
2488
+				// expressions
2489
+				preg_match_all('#(?:([+/*%=-])(=?-?[%$][a-z0-9\\\\.[\]>_:-]+(?:\([^)]*\))?|=?-?[0-9.,]+|\1))#i', $match[4], $expMatch);
2490
+				foreach ($expMatch[1] as $k => $operator) {
2491
+					if (substr($expMatch[2][$k], 0, 1) === '=') {
2492
+						$assign = true;
2493
+						if ($operator === '=') {
2494
+							throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, can not use "==" in expressions');
2495
+						}
2496
+						if ($curBlock !== 'root') {
2497
+							throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, assignments can only be used in top level expressions like {$foo+=3} or {$foo="bar"}');
2498
+						}
2499
+						$operator .= '=';
2500
+						$expMatch[2][$k] = substr($expMatch[2][$k], 1);
2501
+					}
2502
+
2503
+					if (substr($expMatch[2][$k], 0, 1) === '-' && strlen($expMatch[2][$k]) > 1) {
2504
+						$operator .= '-';
2505
+						$expMatch[2][$k] = substr($expMatch[2][$k], 1);
2506
+					}
2507
+					if (($operator === '+' || $operator === '-') && $expMatch[2][$k] === $operator) {
2508
+						$output = '(' . $output . $operator . $operator . ')';
2509
+						break;
2510
+					} elseif (substr($expMatch[2][$k], 0, 1) === '$') {
2511
+						$output = '(' . $output . ' ' . $operator . ' ' . $this->parseVar($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2512
+					} elseif (substr($expMatch[2][$k], 0, 1) === '%') {
2513
+						$output = '(' . $output . ' ' . $operator . ' ' . $this->parseConst($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2514
+					} elseif (!empty($expMatch[2][$k])) {
2515
+						$output = '(' . $output . ' ' . $operator . ' ' . str_replace(',', '.', $expMatch[2][$k]) . ')';
2516
+					} else {
2517
+						throw new CompilationException($this, 'Unfinished expression <em>' . $substr . '</em>, missing var or number after math operator');
2518
+					}
2519
+				}
2520
+			}
2521
+
2522
+			if ($this->autoEscape === true && $curBlock !== 'condition') {
2523
+				$output = '(is_string($tmp=' . $output . ') ? htmlspecialchars($tmp, ENT_QUOTES, $this->charset) : $tmp)';
2524
+			}
2525
+
2526
+			// handle modifiers
2527
+			if ($curBlock !== 'modifier' && $hasModifiers) {
2528
+				$ptr    = 0;
2529
+				$output = $this->replaceModifiers(array(null, null, $output, $match[5]), 'var', $ptr);
2530
+				if ($pointer !== null) {
2531
+					$pointer += $ptr;
2532
+				}
2533
+				$matchedLength += $ptr;
2534
+			}
2535
+
2536
+			if (is_array($parsingParams)) {
2537
+				$parsingParams[] = array($output, $key);
2538
+
2539
+				return $parsingParams;
2540
+			} elseif ($curBlock === 'namedparam') {
2541
+				return array($output, $key);
2542
+			} elseif ($curBlock === 'string' || $curBlock === 'delimited_string') {
2543
+				return array($matchedLength, $output);
2544
+			} elseif ($curBlock === 'expression' || $curBlock === 'variable') {
2545
+				return $output;
2546
+			} elseif (isset($assign)) {
2547
+				return self::PHP_OPEN . $output . ';' . self::PHP_CLOSE;
2548
+			} else {
2549
+				return $output;
2550
+			}
2551
+		} else {
2552
+			if ($curBlock === 'string' || $curBlock === 'delimited_string') {
2553
+				return array(0, '');
2554
+			} else {
2555
+				throw new CompilationException($this, 'Invalid variable name <em>' . $substr . '</em>');
2556
+			}
2557
+		}
2558
+	}
2559
+
2560
+	/**
2561
+	 * Parses any number of chained method calls/property reads.
2562
+	 *
2563
+	 * @param string $output     the variable or whatever upon which the method are called
2564
+	 * @param string $methodCall method call source, starting at "->"
2565
+	 * @param string $curBlock   the current parser-block being processed
2566
+	 * @param int    $pointer    a reference to a pointer that will be increased by the amount of characters parsed
2567
+	 *
2568
+	 * @return string parsed call(s)/read(s)
2569
+	 */
2570
+	protected function parseMethodCall($output, $methodCall, $curBlock, &$pointer)
2571
+	{
2572
+		$ptr = 0;
2573
+		$len = strlen($methodCall);
2574
+
2575
+		while ($ptr < $len) {
2576
+			if (strpos($methodCall, '->', $ptr) === $ptr) {
2577
+				$ptr += 2;
2578
+			}
2579
+
2580
+			if (in_array(
2581
+				$methodCall[$ptr], array(
2582
+					';',
2583
+					',',
2584
+					'/',
2585
+					' ',
2586
+					"\t",
2587
+					"\r",
2588
+					"\n",
2589
+					')',
2590
+					'+',
2591
+					'*',
2592
+					'%',
2593
+					'=',
2594
+					'-',
2595
+					'|'
2596
+				)
2597
+			) || substr($methodCall, $ptr, strlen($this->rd)) === $this->rd
2598
+			) {
2599
+				// break char found
2600
+				break;
2601
+			}
2602
+
2603
+			if (!preg_match('/^([a-z0-9_]+)(\(.*?\))?/i', substr($methodCall, $ptr), $methMatch)) {
2604
+				break;
2605
+			}
2606
+
2607
+			if (empty($methMatch[2])) {
2608
+				// property
2609
+				if ($curBlock === 'root') {
2610
+					$output .= '->' . $methMatch[1];
2611
+				} else {
2612
+					$output = '(($tmp = ' . $output . ') ? $tmp->' . $methMatch[1] . ' : null)';
2613
+				}
2614
+				$ptr += strlen($methMatch[1]);
2615
+			} else {
2616
+				// method
2617
+				if (substr($methMatch[2], 0, 2) === '()') {
2618
+					$parsedCall = $methMatch[1] . '()';
2619
+					$ptr += strlen($methMatch[1]) + 2;
2620
+				} else {
2621
+					$parsedCall = $this->parseFunction($methodCall, $ptr, strlen($methodCall), false, 'method', $ptr);
2622
+				}
2623
+				if ($this->securityPolicy !== null) {
2624
+					$argPos = strpos($parsedCall, '(');
2625
+					$method = strtolower(substr($parsedCall, 0, $argPos));
2626
+					$args   = substr($parsedCall, $argPos);
2627
+					if ($curBlock === 'root') {
2628
+						$output = '$this->getSecurityPolicy()->callMethod($this, ' . $output . ', ' . var_export($method, true) . ', array' . $args . ')';
2629
+					} else {
2630
+						$output = '(($tmp = ' . $output . ') ? $this->getSecurityPolicy()->callMethod($this, $tmp, ' . var_export($method, true) . ', array' . $args . ') : null)';
2631
+					}
2632
+				} else {
2633
+					if ($curBlock === 'root') {
2634
+						$output .= '->' . $parsedCall;
2635
+					} else {
2636
+						$output = '(($tmp = ' . $output . ') ? $tmp->' . $parsedCall . ' : null)';
2637
+					}
2638
+				}
2639
+			}
2640
+		}
2641
+
2642
+		$pointer += $ptr;
2643
+
2644
+		return $output;
2645
+	}
2646
+
2647
+	/**
2648
+	 * Parses a constant variable (a variable that doesn't contain another variable) and preprocesses it to save
2649
+	 * runtime processing time.
2650
+	 *
2651
+	 * @param string $key      the variable to parse
2652
+	 * @param string $curBlock the current parser-block being processed
2653
+	 *
2654
+	 * @return string parsed variable
2655
+	 */
2656
+	protected function parseVarKey($key, $curBlock)
2657
+	{
2658
+		if ($key === '') {
2659
+			return '$this->scope';
2660
+		}
2661
+		if (substr($key, 0, 1) === '.') {
2662
+			$key = 'dwoo' . $key;
2663
+		}
2664
+		if (preg_match('#dwoo\.(get|post|server|cookies|session|env|request)((?:\.[a-z0-9_-]+)+)#i', $key, $m)) {
2665
+			$global = strtoupper($m[1]);
2666
+			if ($global === 'COOKIES') {
2667
+				$global = 'COOKIE';
2668
+			}
2669
+			$key = '$_' . $global;
2670
+			foreach (explode('.', ltrim($m[2], '.')) as $part) {
2671
+				$key .= '[' . var_export($part, true) . ']';
2672
+			}
2673
+			if ($curBlock === 'root') {
2674
+				$output = $key;
2675
+			} else {
2676
+				$output = '(isset(' . $key . ')?' . $key . ':null)';
2677
+			}
2678
+		} elseif (preg_match('#dwoo\\.const\\.([a-z0-9\\\\_:]+)#i', $key, $m)) {
2679
+			return $this->parseConstKey($m[1], $curBlock);
2680
+		} elseif ($this->scope !== null) {
2681
+			if (strstr($key, '.') === false && strstr($key, '[') === false && strstr($key, '->') === false) {
2682
+				if ($key === 'dwoo') {
2683
+					$output = '$this->globals';
2684
+				} elseif ($key === '_root' || $key === '__') {
2685
+					$output = '$this->data';
2686
+				} elseif ($key === '_parent' || $key === '_') {
2687
+					$output = '$this->readParentVar(1)';
2688
+				} elseif ($key === '_key') {
2689
+					$output = '$tmp_key';
2690
+				} else {
2691
+					if ($curBlock === 'root') {
2692
+						$output = '$this->scope["' . $key . '"]';
2693
+					} else {
2694
+						$output = '(isset($this->scope["' . $key . '"]) ? $this->scope["' . $key . '"] : null)';
2695
+					}
2696
+				}
2697
+			} else {
2698
+				preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+|(\\\?[\'"])[^\3]*?\3)\]?#i', $key, $m);
2699
+
2700
+				$i = $m[2][0];
2701
+				if ($i === '_parent' || $i === '_') {
2702
+					$parentCnt = 0;
2703
+
2704
+					while (true) {
2705
+						++ $parentCnt;
2706
+						array_shift($m[2]);
2707
+						array_shift($m[1]);
2708
+						if (current($m[2]) === '_parent') {
2709
+							continue;
2710
+						}
2711
+						break;
2712
+					}
2713
+
2714
+					$output = '$this->readParentVar(' . $parentCnt . ')';
2715
+				} else {
2716
+					if ($i === 'dwoo') {
2717
+						$output = '$this->globals';
2718
+						array_shift($m[2]);
2719
+						array_shift($m[1]);
2720
+					} elseif ($i === '_root' || $i === '__') {
2721
+						$output = '$this->data';
2722
+						array_shift($m[2]);
2723
+						array_shift($m[1]);
2724
+					} elseif ($i === '_key') {
2725
+						$output = '$tmp_key';
2726
+					} else {
2727
+						$output = '$this->scope';
2728
+					}
2729
+
2730
+					while (count($m[1]) && $m[1][0] !== '->') {
2731
+						$m[2][0] = preg_replace('/(^\\\([\'"])|\\\([\'"])$)/x', '$2$3', $m[2][0]);
2732
+						if (substr($m[2][0], 0, 1) == '"' || substr($m[2][0], 0, 1) == "'") {
2733
+							$output .= '[' . $m[2][0] . ']';
2734
+						} else {
2735
+							$output .= '["' . $m[2][0] . '"]';
2736
+						}
2737
+						array_shift($m[2]);
2738
+						array_shift($m[1]);
2739
+					}
2740
+
2741
+					if ($curBlock !== 'root') {
2742
+						$output = '(isset(' . $output . ') ? ' . $output . ':null)';
2743
+					}
2744
+				}
2745
+
2746
+				if (count($m[2])) {
2747
+					unset($m[0]);
2748
+					$output = '$this->readVarInto(' . str_replace("\n", '', var_export($m, true)) . ', ' . $output . ', ' . ($curBlock == 'root' ? 'false' : 'true') . ')';
2749
+				}
2750
+			}
2751
+		} else {
2752
+			preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+)\]?#i', $key, $m);
2753
+			unset($m[0]);
2754
+			$output = '$this->readVar(' . str_replace("\n", '', var_export($m, true)) . ')';
2755
+		}
2756
+
2757
+		return $output;
2758
+	}
2759
+
2760
+	/**
2761
+	 * Flattens a variable tree, this helps in parsing very complex variables such as $var.foo[$foo.bar->baz].baz,
2762
+	 * it computes the contents of the brackets first and works out from there.
2763
+	 *
2764
+	 * @param array $tree     the variable tree parsed by he parseVar() method that must be flattened
2765
+	 * @param bool  $recursed leave that to false by default, it is only for internal use
2766
+	 *
2767
+	 * @return string flattened tree
2768
+	 */
2769
+	protected function flattenVarTree(array $tree, $recursed = false)
2770
+	{
2771
+		$out = $recursed ? '".$this->readVarInto(' : '';
2772
+		foreach ($tree as $bit) {
2773
+			if (is_array($bit)) {
2774
+				$out .= '.' . $this->flattenVarTree($bit, false);
2775
+			} else {
2776
+				$key = str_replace('"', '\\"', $bit);
2777
+
2778
+				if (substr($key, 0, 1) === '$') {
2779
+					$out .= '".' . $this->parseVar($key, 0, strlen($key), false, 'variable') . '."';
2780
+				} else {
2781
+					$cnt = substr_count($key, '$');
2782
+
2783
+					if ($this->debug) {
2784
+						echo 'PARSING SUBVARS IN : ' . $key . "\n";
2785
+					}
2786
+					if ($cnt > 0) {
2787
+						while (-- $cnt >= 0) {
2788
+							if (isset($last)) {
2789
+								$last = strrpos($key, '$', - (strlen($key) - $last + 1));
2790
+							} else {
2791
+								$last = strrpos($key, '$');
2792
+							}
2793
+							preg_match('#\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', substr($key, $last), $submatch);
2794
+
2795
+							$len = strlen($submatch[0]);
2796
+							$key = substr_replace(
2797
+								$key, preg_replace_callback(
2798
+									'#(\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*)' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', array(
2799
+										$this,
2800
+										'replaceVarKeyHelper'
2801
+									), substr($key, $last, $len)
2802
+								), $last, $len
2803
+							);
2804
+							if ($this->debug) {
2805
+								echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2806
+							}
2807
+						}
2808
+						unset($last);
2809
+
2810
+						$out .= $key;
2811
+					} else {
2812
+						$out .= $key;
2813
+					}
2814
+				}
2815
+			}
2816
+		}
2817
+		$out .= $recursed ? ', true)."' : '';
2818
+
2819
+		return $out;
2820
+	}
2821
+
2822
+	/**
2823
+	 * Helper function that parses a variable.
2824
+	 *
2825
+	 * @param array $match the matched variable, array(1=>"string match")
2826
+	 *
2827
+	 * @return string parsed variable
2828
+	 */
2829
+	protected function replaceVarKeyHelper($match)
2830
+	{
2831
+		return '".' . $this->parseVar($match[0], 0, strlen($match[0]), false, 'variable') . '."';
2832
+	}
2833
+
2834
+	/**
2835
+	 * Parses various constants, operators or non-quoted strings.
2836
+	 *
2837
+	 * @param string $in            the string within which we must parse something
2838
+	 * @param int    $from          the starting offset of the parsed area
2839
+	 * @param int    $to            the ending offset of the parsed area
2840
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2841
+	 *                              default
2842
+	 * @param string $curBlock      the current parser-block being processed
2843
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2844
+	 *                              or null by default
2845
+	 *
2846
+	 * @return string parsed values
2847
+	 * @throws Exception
2848
+	 */
2849
+	protected function parseOthers($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2850
+	{
2851
+		$substr = substr($in, $from, $to - $from);
2852
+
2853
+		$end = strlen($substr);
2854
+
2855
+		if ($curBlock === 'condition') {
2856
+			$breakChars = array(
2857
+				'(',
2858
+				')',
2859
+				' ',
2860
+				'||',
2861
+				'&&',
2862
+				'|',
2863
+				'&',
2864
+				'>=',
2865
+				'<=',
2866
+				'===',
2867
+				'==',
2868
+				'=',
2869
+				'!==',
2870
+				'!=',
2871
+				'<<',
2872
+				'<',
2873
+				'>>',
2874
+				'>',
2875
+				'^',
2876
+				'~',
2877
+				',',
2878
+				'+',
2879
+				'-',
2880
+				'*',
2881
+				'/',
2882
+				'%',
2883
+				'!',
2884
+				'?',
2885
+				':',
2886
+				$this->rd,
2887
+				';'
2888
+			);
2889
+		} elseif ($curBlock === 'modifier') {
2890
+			$breakChars = array(' ', ',', ')', ':', '|', "\r", "\n", "\t", ';', $this->rd);
2891
+		} elseif ($curBlock === 'expression') {
2892
+			$breakChars = array('/', '%', '+', '-', '*', ' ', ',', ')', "\r", "\n", "\t", ';', $this->rd);
2893
+		} else {
2894
+			$breakChars = array(' ', ',', ')', "\r", "\n", "\t", ';', $this->rd);
2895
+		}
2896
+
2897
+		$breaker = false;
2898
+		foreach ($breakChars as $k => $char) {
2899
+			$test = strpos($substr, $char);
2900
+			if ($test !== false && $test < $end) {
2901
+				$end     = $test;
2902
+				$breaker = $k;
2903
+			}
2904
+		}
2905
+
2906
+		if ($curBlock === 'condition') {
2907
+			if ($end === 0 && $breaker !== false) {
2908
+				$end = strlen($breakChars[$breaker]);
2909
+			}
2910
+		}
2911
+
2912
+		if ($end !== false) {
2913
+			$substr = substr($substr, 0, $end);
2914
+		}
2915
+
2916
+		if ($pointer !== null) {
2917
+			$pointer += strlen($substr);
2918
+		}
2919
+
2920
+		$src    = $substr;
2921
+		$substr = trim($substr);
2922
+
2923
+		if (strtolower($substr) === 'false' || strtolower($substr) === 'no' || strtolower($substr) === 'off') {
2924
+			if ($this->debug) {
2925
+				echo 'BOOLEAN(FALSE) PARSED' . "\n";
2926
+			}
2927
+			$substr = 'false';
2928
+			$type   = self::T_BOOL;
2929
+		} elseif (strtolower($substr) === 'true' || strtolower($substr) === 'yes' || strtolower($substr) === 'on') {
2930
+			if ($this->debug) {
2931
+				echo 'BOOLEAN(TRUE) PARSED' . "\n";
2932
+			}
2933
+			$substr = 'true';
2934
+			$type   = self::T_BOOL;
2935
+		} elseif ($substr === 'null' || $substr === 'NULL') {
2936
+			if ($this->debug) {
2937
+				echo 'NULL PARSED' . "\n";
2938
+			}
2939
+			$substr = 'null';
2940
+			$type   = self::T_NULL;
2941
+		} elseif (is_numeric($substr)) {
2942
+			$substr = (float)$substr;
2943
+			if ((int)$substr == $substr) {
2944
+				$substr = (int)$substr;
2945
+			}
2946
+			$type = self::T_NUMERIC;
2947
+			if ($this->debug) {
2948
+				echo 'NUMBER (' . $substr . ') PARSED' . "\n";
2949
+			}
2950
+		} elseif (preg_match('{^-?(\d+|\d*(\.\d+))\s*([/*%+-]\s*-?(\d+|\d*(\.\d+)))+$}', $substr)) {
2951
+			if ($this->debug) {
2952
+				echo 'SIMPLE MATH PARSED . "\n"';
2953
+			}
2954
+			$type   = self::T_MATH;
2955
+			$substr = '(' . $substr . ')';
2956
+		} elseif ($curBlock === 'condition' && array_search($substr, $breakChars, true) !== false) {
2957
+			if ($this->debug) {
2958
+				echo 'BREAKCHAR (' . $substr . ') PARSED' . "\n";
2959
+			}
2960
+			$type = self::T_BREAKCHAR;
2961
+			//$substr = '"'.$substr.'"';
2962
+		} else {
2963
+			$substr = $this->replaceStringVars('\'' . str_replace('\'', '\\\'', $substr) . '\'', '\'', $curBlock);
2964
+			$type   = self::T_UNQUOTED_STRING;
2965
+			if ($this->debug) {
2966
+				echo 'BLABBER (' . $substr . ') CASTED AS STRING' . "\n";
2967
+			}
2968
+		}
2969
+
2970
+		if (is_array($parsingParams)) {
2971
+			$parsingParams[] = array($substr, $src, $type);
2972
+
2973
+			return $parsingParams;
2974
+		} elseif ($curBlock === 'namedparam') {
2975
+			return array($substr, $src, $type);
2976
+		} elseif ($curBlock === 'expression') {
2977
+			return $substr;
2978
+		} else {
2979
+			throw new Exception('Something went wrong');
2980
+		}
2981
+	}
2982
+
2983
+	/**
2984
+	 * Replaces variables within a parsed string.
2985
+	 *
2986
+	 * @param string $string   the parsed string
2987
+	 * @param string $first    the first character parsed in the string, which is the string delimiter (' or ")
2988
+	 * @param string $curBlock the current parser-block being processed
2989
+	 *
2990
+	 * @return string the original string with variables replaced
2991
+	 */
2992
+	protected function replaceStringVars($string, $first, $curBlock = '')
2993
+	{
2994
+		$pos = 0;
2995
+		if ($this->debug) {
2996
+			echo 'STRING VAR REPLACEMENT : ' . $string . "\n";
2997
+		}
2998
+		// replace vars
2999
+		while (($pos = strpos($string, '$', $pos)) !== false) {
3000
+			$prev = substr($string, $pos - 1, 1);
3001
+			if ($prev === '\\') {
3002
+				++ $pos;
3003
+				continue;
3004
+			}
3005
+
3006
+			$var = $this->parse($string, $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3007
+			$len = $var[0];
3008
+			$var = $this->parse(str_replace('\\' . $first, $first, $string), $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3009
+
3010
+			if ($prev === '`' && substr($string, $pos + $len, 1) === '`') {
3011
+				$string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos - 1, $len + 2);
3012
+			} else {
3013
+				$string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos, $len);
3014
+			}
3015
+			$pos += strlen($var[1]) + 2;
3016
+			if ($this->debug) {
3017
+				echo 'STRING VAR REPLACEMENT DONE : ' . $string . "\n";
3018
+			}
3019
+		}
3020
+
3021
+		// handle modifiers
3022
+		// TODO Obsolete?
3023
+		$string = preg_replace_callback(
3024
+			'#("|\')\.(.+?)\.\1((?:\|(?:@?[a-z0-9_]+(?:(?::("|\').+?\4|:[^`]*))*))+)#i', array(
3025
+			$this,
3026
+			'replaceModifiers'
3027
+			), $string
3028
+		);
3029
+
3030
+		// replace escaped dollar operators by unescaped ones if required
3031
+		if ($first === "'") {
3032
+			$string = str_replace('\\$', '$', $string);
3033
+		}
3034
+
3035
+		return $string;
3036
+	}
3037
+
3038
+	/**
3039
+	 * Replaces the modifiers applied to a string or a variable.
3040
+	 *
3041
+	 * @param array  $m        the regex matches that must be array(1=>"double or single quotes enclosing a string,
3042
+	 *                         when applicable", 2=>"the string or var", 3=>"the modifiers matched")
3043
+	 * @param string $curBlock the current parser-block being processed
3044
+	 * @param null   $pointer
3045
+	 *
3046
+	 * @return string the input enclosed with various function calls according to the modifiers found
3047
+	 * @throws CompilationException
3048
+	 * @throws Exception
3049
+	 */
3050
+	protected function replaceModifiers(array $m, $curBlock = null, &$pointer = null)
3051
+	{
3052
+		if ($this->debug) {
3053
+			echo 'PARSING MODIFIERS : ' . $m[3] . "\n";
3054
+		}
3055
+
3056
+		if ($pointer !== null) {
3057
+			$pointer += strlen($m[3]);
3058
+		}
3059
+		// remove first pipe
3060
+		$cmdstrsrc = substr($m[3], 1);
3061
+		// remove last quote if present
3062
+		if (substr($cmdstrsrc, - 1, 1) === $m[1]) {
3063
+			$cmdstrsrc = substr($cmdstrsrc, 0, - 1);
3064
+			$add       = $m[1];
3065
+		}
3066
+
3067
+		$output = $m[2];
3068
+
3069
+		$continue = true;
3070
+		while (strlen($cmdstrsrc) > 0 && $continue) {
3071
+			if ($cmdstrsrc[0] === '|') {
3072
+				$cmdstrsrc = substr($cmdstrsrc, 1);
3073
+				continue;
3074
+			}
3075
+			if ($cmdstrsrc[0] === ' ' || $cmdstrsrc[0] === ';' || substr($cmdstrsrc, 0, strlen($this->rd)) === $this->rd) {
3076
+				if ($this->debug) {
3077
+					echo 'MODIFIER PARSING ENDED, RIGHT DELIMITER or ";" FOUND' . "\n";
3078
+				}
3079
+				$continue = false;
3080
+				if ($pointer !== null) {
3081
+					$pointer -= strlen($cmdstrsrc);
3082
+				}
3083
+				break;
3084
+			}
3085
+			$cmdstr   = $cmdstrsrc;
3086
+			$paramsep = ':';
3087
+			if (!preg_match('/^(@{0,2}[a-z_][a-z0-9_]*)(:)?/i', $cmdstr, $match)) {
3088
+				throw new CompilationException($this, 'Invalid modifier name, started with : ' . substr($cmdstr, 0, 10));
3089
+			}
3090
+			$paramspos = !empty($match[2]) ? strlen($match[1]) : false;
3091
+			$func      = $match[1];
3092
+
3093
+			$state = 0;
3094
+			if ($paramspos === false) {
3095
+				$cmdstrsrc = substr($cmdstrsrc, strlen($func));
3096
+				$params    = array();
3097
+				if ($this->debug) {
3098
+					echo 'MODIFIER (' . $func . ') CALLED WITH NO PARAMS' . "\n";
3099
+				}
3100
+			} else {
3101
+				$paramstr = substr($cmdstr, $paramspos + 1);
3102
+				if (substr($paramstr, - 1, 1) === $paramsep) {
3103
+					$paramstr = substr($paramstr, 0, - 1);
3104
+				}
3105
+
3106
+				$ptr    = 0;
3107
+				$params = array();
3108
+				while ($ptr < strlen($paramstr)) {
3109
+					if ($this->debug) {
3110
+						echo 'MODIFIER (' . $func . ') START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
3111
+					}
3112
+					if ($this->debug) {
3113
+						echo $paramstr . '--' . $ptr . '--' . strlen($paramstr) . '--modifier' . "\n";
3114
+					}
3115
+					$params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'modifier', $ptr);
3116
+					if ($this->debug) {
3117
+						echo 'PARAM PARSED, POINTER AT ' . $ptr . "\n";
3118
+					}
3119
+
3120
+					if ($ptr >= strlen($paramstr)) {
3121
+						if ($this->debug) {
3122
+							echo 'PARAM PARSING ENDED, PARAM STRING CONSUMED' . "\n";
3123
+						}
3124
+						break;
3125
+					}
3126
+
3127
+					if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === '|' || $paramstr[$ptr] === ';' || substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
3128
+						if ($this->debug) {
3129
+							echo 'PARAM PARSING ENDED, " ", "|", RIGHT DELIMITER or ";" FOUND, POINTER AT ' . $ptr . "\n";
3130
+						}
3131
+						if ($paramstr[$ptr] !== '|') {
3132
+							$continue = false;
3133
+							if ($pointer !== null) {
3134
+								$pointer -= strlen($paramstr) - $ptr;
3135
+							}
3136
+						}
3137
+						++ $ptr;
3138
+						break;
3139
+					}
3140
+					if ($ptr < strlen($paramstr) && $paramstr[$ptr] === ':') {
3141
+						++ $ptr;
3142
+					}
3143
+				}
3144
+				$cmdstrsrc = substr($cmdstrsrc, strlen($func) + 1 + $ptr);
3145
+				foreach ($params as $k => $p) {
3146
+					if (is_array($p) && is_array($p[1])) {
3147
+						$state |= 2;
3148
+					} else {
3149
+						if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m)) {
3150
+							$params[$k] = array($m[2], array('true', 'true'));
3151
+						} else {
3152
+							if ($state & 2) {
3153
+								throw new CompilationException($this, 'You can not use an unnamed parameter after a named one');
3154
+							}
3155
+							$state |= 1;
3156
+						}
3157
+					}
3158
+				}
3159
+			}
3160
+
3161
+			// check if we must use array_map with this plugin or not
3162
+			$mapped = false;
3163
+			if (substr($func, 0, 1) === '@') {
3164
+				$func   = substr($func, 1);
3165
+				$mapped = true;
3166
+			}
3167
+
3168
+			$pluginType = $this->getPluginType($func);
3169
+
3170
+			if ($state & 2) {
3171
+				array_unshift($params, array('value', is_array($output) ? $output : array($output, $output)));
3172
+			} else {
3173
+				array_unshift($params, is_array($output) ? $output : array($output, $output));
3174
+			}
3175
+
3176
+			if ($pluginType & Core::NATIVE_PLUGIN) {
3177
+				$params = $this->mapParams($params, null, $state);
3178
+
3179
+				$params = $params['*'][0];
3180
+
3181
+				$params = self::implode_r($params);
3182
+
3183
+				if ($mapped) {
3184
+					$output = '$this->arrayMap(\'' . $func . '\', array(' . $params . '))';
3185
+				} else {
3186
+					$output = $func . '(' . $params . ')';
3187
+				}
3188
+			} elseif ($pluginType & Core::PROXY_PLUGIN) {
3189
+				$params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state);
3190
+				foreach ($params as &$p) {
3191
+					$p = $p[0];
3192
+				}
3193
+				$output = call_user_func(array($this->getDwoo()->getPluginProxy(), 'getCode'), $func, $params);
3194
+			} elseif ($pluginType & Core::SMARTY_MODIFIER) {
3195
+				$params = $this->mapParams($params, null, $state);
3196
+				$params = $params['*'][0];
3197
+
3198
+				$params = self::implode_r($params);
3199
+
3200
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
3201
+					$callback = $this->customPlugins[$func]['callback'];
3202
+					if (is_array($callback)) {
3203
+						if (is_object($callback[0])) {
3204
+							$output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(' . $params . '))';
3205
+						} else {
3206
+							$output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3207
+						}
3208
+					} elseif ($mapped) {
3209
+						$output = '$this->arrayMap(\'' . $callback . '\', array(' . $params . '))';
3210
+					} else {
3211
+						$output = $callback . '(' . $params . ')';
3212
+					}
3213
+				} elseif ($mapped) {
3214
+					$output = '$this->arrayMap(\'smarty_modifier_' . $func . '\', array(' . $params . '))';
3215
+				} else {
3216
+					$output = 'smarty_modifier_' . $func . '(' . $params . ')';
3217
+				}
3218
+			} else {
3219
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
3220
+					$callback   = $this->customPlugins[$func]['callback'];
3221
+					$pluginName = $callback;
3222
+				} else {
3223
+					if (class_exists('Plugin' . Core::toCamelCase($func)) !== false || function_exists('Plugin' .
3224
+							Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''))
3225
+						!== false) {
3226
+						$pluginName = 'Plugin' . Core::toCamelCase($func);
3227
+					} else {
3228
+						$pluginName = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func);
3229
+					}
3230
+					if ($pluginType & Core::CLASS_PLUGIN) {
3231
+						$callback = array($pluginName, ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process');
3232
+					} else {
3233
+						$callback = $pluginName . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '');
3234
+					}
3235
+				}
3236
+				$params = $this->mapParams($params, $callback, $state);
3237
+
3238
+				foreach ($params as &$p) {
3239
+					$p = $p[0];
3240
+				}
3241
+
3242
+				// Only for PHP function, who is not a PHP class
3243
+				if ($pluginType & Core::FUNC_PLUGIN && !($pluginType & Core::CLASS_PLUGIN)) {
3244
+					if ($pluginType & Core::COMPILABLE_PLUGIN) {
3245
+						if ($mapped) {
3246
+							throw new CompilationException($this, 'The @ operator can not be used on compiled plugins.');
3247
+						}
3248
+						if ($pluginType & Core::CUSTOM_PLUGIN) {
3249
+							$funcCompiler = $this->customPlugins[$func]['callback'];
3250
+						} else {
3251
+							if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
3252
+								$funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
3253
+							} else {
3254
+								$funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
3255
+									'Compile';
3256
+							}
3257
+						}
3258
+						array_unshift($params, $this);
3259
+						$output = call_user_func_array($funcCompiler, $params);
3260
+					} else {
3261
+						array_unshift($params, '$this');
3262
+
3263
+						$params = self::implode_r($params);
3264
+						if ($mapped) {
3265
+							$output = '$this->arrayMap(\'' . $pluginName . '\', array(' . $params . '))';
3266
+						} else {
3267
+							$output = $pluginName . '(' . $params . ')';
3268
+						}
3269
+					}
3270
+				} else {
3271
+					if ($pluginType & Core::COMPILABLE_PLUGIN) {
3272
+						if ($mapped) {
3273
+							throw new CompilationException($this, 'The @ operator can not be used on compiled plugins.');
3274
+						}
3275
+						if ($pluginType & Core::CUSTOM_PLUGIN) {
3276
+							$callback = $this->customPlugins[$func]['callback'];
3277
+							if (!is_array($callback)) {
3278
+								if (!method_exists($callback, 'compile')) {
3279
+									throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
3280
+								}
3281
+								if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
3282
+									$funcCompiler = array($callback, 'compile');
3283
+								} else {
3284
+									$funcCompiler = array(new $callback(), 'compile');
3285
+								}
3286
+							} else {
3287
+								$funcCompiler = $callback;
3288
+							}
3289
+						} else {
3290
+							if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3291
+								$funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
3292
+							} else {
3293
+								$funcCompiler = array(
3294
+									Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
3295
+									'compile'
3296
+								);
3297
+							}
3298
+							array_unshift($params, $this);
3299
+						}
3300
+						$output = call_user_func_array($funcCompiler, $params);
3301
+					} else {
3302
+						$params = self::implode_r($params);
3303
+
3304
+						if ($pluginType & Core::CUSTOM_PLUGIN) {
3305
+							if (is_object($callback[0])) {
3306
+								$output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(' . $params . '))';
3307
+							} else {
3308
+								$output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3309
+							}
3310
+						} elseif ($mapped) {
3311
+							$output = '$this->arrayMap(array($this->getObjectPlugin(\''.
3312
+								Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '\'), 
3313 3313
                             \'process\'), array(' . $params . '))';
3314
-                        } else {
3315
-                            if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3316
-                                $output = '$this->classCall(\'Plugin' . Core::toCamelCase($func) . '\', array(' . $params . '))';
3317
-                            } elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($func)) !== false) {
3318
-                                $output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . $func . '\', array(' . $params . '))';
3319
-                            } elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !== false) {
3320
-                                $output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\', array(' . $params . '))';
3321
-                            } else {
3322
-                                $output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
3323
-                            }
3324
-                        }
3325
-                    }
3326
-                }
3327
-            }
3328
-        }
3329
-
3330
-        if ($curBlock === 'namedparam') {
3331
-            return array($output, $output);
3332
-        } elseif ($curBlock === 'var' || $m[1] === null) {
3333
-            return $output;
3334
-        } elseif ($curBlock === 'string' || $curBlock === 'root') {
3335
-            return $m[1] . '.' . $output . '.' . $m[1] . (isset($add) ? $add : null);
3336
-        }
3337
-
3338
-        return '';
3339
-    }
3340
-
3341
-    /**
3342
-     * Recursively implodes an array in a similar manner as var_export() does but with some tweaks
3343
-     * to handle pre-compiled values and the fact that we do not need to enclose everything with
3344
-     * "array" and do not require top-level keys to be displayed.
3345
-     *
3346
-     * @param array $params        the array to implode
3347
-     * @param bool  $recursiveCall if set to true, the function outputs key names for the top level
3348
-     *
3349
-     * @return string the imploded array
3350
-     */
3351
-    public static function implode_r(array $params, $recursiveCall = false)
3352
-    {
3353
-        $out = '';
3354
-        foreach ($params as $k => $p) {
3355
-            if (is_array($p)) {
3356
-                $out2 = 'array(';
3357
-                foreach ($p as $k2 => $v) {
3358
-                    $out2 .= var_export($k2, true) . ' => ' . (is_array($v) ? 'array(' . self::implode_r($v, true) . ')' : $v) . ', ';
3359
-                }
3360
-                $p = rtrim($out2, ', ') . ')';
3361
-            }
3362
-            if ($recursiveCall) {
3363
-                $out .= var_export($k, true) . ' => ' . $p . ', ';
3364
-            } else {
3365
-                $out .= $p . ', ';
3366
-            }
3367
-        }
3368
-
3369
-        return rtrim($out, ', ');
3370
-    }
3371
-
3372
-    /**
3373
-     * Returns the plugin type of a plugin and adds it to the used plugins array if required.
3374
-     *
3375
-     * @param string $name plugin name, as found in the template
3376
-     *
3377
-     * @return int type as a multi bit flag composed of the Dwoo plugin types constants
3378
-     * @throws Exception
3379
-     * @throws SecurityException
3380
-     * @throws Exception
3381
-     */
3382
-    protected function getPluginType($name)
3383
-    {
3384
-        $pluginType = - 1;
3385
-
3386
-        if (($this->securityPolicy === null && (function_exists($name) || strtolower($name) === 'isset' || strtolower($name) === 'empty')) || ($this->securityPolicy !== null && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) !== false)) {
3387
-            $phpFunc = true;
3388
-        } elseif ($this->securityPolicy !== null && function_exists($name) && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) === false) {
3389
-            throw new SecurityException('Call to a disallowed php function : ' . $name);
3390
-        }
3391
-
3392
-        while ($pluginType <= 0) {
3393
-            // Template plugin compilable
3394
-            if (isset($this->templatePlugins[$name])) {
3395
-                $pluginType = Core::TEMPLATE_PLUGIN | Core::COMPILABLE_PLUGIN;
3396
-            } // Custom plugin
3397
-            elseif (isset($this->customPlugins[$name])) {
3398
-                $pluginType = $this->customPlugins[$name]['type'] | Core::CUSTOM_PLUGIN;
3399
-            } // Class blocks plugin
3400
-            elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3401
-                $pluginType = Core::CLASS_PLUGIN;
3402
-                if (is_subclass_of(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3403
-                    $pluginType += Core::BLOCK_PLUGIN;
3404
-                }
3405
-                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name));
3406
-                if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3407
-                    $pluginType |= Core::COMPILABLE_PLUGIN;
3408
-                }
3409
-            } // Class functions plugin
3410
-            elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3411
-                $pluginType = Core::FUNC_PLUGIN + Core::CLASS_PLUGIN;
3412
-                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name));
3413
-                if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3414
-                    $pluginType |= Core::COMPILABLE_PLUGIN;
3415
-                }
3416
-            } // Class without namespace
3417
-            elseif (class_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3418
-                $pluginType = Core::CLASS_PLUGIN;
3419
-                $interfaces = class_implements('Plugin' . Core::toCamelCase($name));
3420
-                if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3421
-                    $pluginType |= Core::COMPILABLE_PLUGIN;
3422
-                }
3423
-            } // Function plugin (with/without namespaces)
3424
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase ($name)) !==
3425
-                false || function_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3426
-                $pluginType = Core::FUNC_PLUGIN;
3427
-            } // Function plugin compile (with/without namespaces)
3428
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name) .
3429
-                    'Compile') !== false || function_exists('Plugin' . Core::toCamelCase($name) . 'Compile') !==
3430
-                false) {
3431
-                $pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3432
-            } // Helper plugin class compile
3433
-            elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3434
-                $pluginType = Core::CLASS_PLUGIN | Core::COMPILABLE_PLUGIN;
3435
-            } // Helper plugin function compile
3436
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name) . 'Compile') !== false) {
3437
-                $pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3438
-            } // Smarty modifier
3439
-            elseif (function_exists('smarty_modifier_' . $name) !== false) {
3440
-                $pluginType = Core::SMARTY_MODIFIER;
3441
-            } // Smarty function
3442
-            elseif (function_exists('smarty_function_' . $name) !== false) {
3443
-                $pluginType = Core::SMARTY_FUNCTION;
3444
-            } // Smarty block
3445
-            elseif (function_exists('smarty_block_' . $name) !== false) {
3446
-                $pluginType = Core::SMARTY_BLOCK;
3447
-            } // Everything else
3448
-            else {
3449
-                if ($pluginType === - 1) {
3450
-                    try {
3451
-                        $this->getDwoo()->getLoader()->loadPlugin('Plugin' . Core::toCamelCase($name));
3452
-                    }
3453
-                    catch (Exception $e) {
3454
-                        if (isset($phpFunc)) {
3455
-                            $pluginType = Core::NATIVE_PLUGIN;
3456
-                        } elseif (is_object($this->getDwoo()->getPluginProxy()) && $this->getDwoo()->getPluginProxy()->handles($name)) {
3457
-                            $pluginType = Core::PROXY_PLUGIN;
3458
-                            break;
3459
-                        } else {
3460
-                            throw $e;
3461
-                        }
3462
-                    }
3463
-                } else {
3464
-                    throw new Exception('Plugin "' . $name . '" could not be found, type:' . $pluginType);
3465
-                }
3466
-                ++ $pluginType;
3467
-            }
3468
-        }
3469
-
3470
-        if (($pluginType & Core::COMPILABLE_PLUGIN) === 0 && ($pluginType & Core::NATIVE_PLUGIN) === 0 && ($pluginType & Core::PROXY_PLUGIN) === 0) {
3471
-            $this->addUsedPlugin(Core::toCamelCase($name), $pluginType);
3472
-        }
3473
-
3474
-        return $pluginType;
3475
-    }
3476
-
3477
-    /**
3478
-     * Allows a plugin to load another one at compile time, this will also mark
3479
-     * it as used by this template so it will be loaded at runtime (which can be
3480
-     * useful for compiled plugins that rely on another plugin when their compiled
3481
-     * code runs).
3482
-     *
3483
-     * @param string $name the plugin name
3484
-     *
3485
-     * @return void
3486
-     */
3487
-    public function loadPlugin($name)
3488
-    {
3489
-        $this->getPluginType($name);
3490
-    }
3491
-
3492
-    /**
3493
-     * Runs htmlentities over the matched <?php ?> blocks when the security policy enforces that.
3494
-     *
3495
-     * @param array $match matched php block
3496
-     *
3497
-     * @return string the htmlentities-converted string
3498
-     */
3499
-    protected function phpTagEncodingHelper($match)
3500
-    {
3501
-        return htmlspecialchars($match[0]);
3502
-    }
3503
-
3504
-    /**
3505
-     * Maps the parameters received from the template onto the parameters required by the given callback.
3506
-     *
3507
-     * @param array    $params   the array of parameters
3508
-     * @param callback $callback the function or method to reflect on to find out the required parameters
3509
-     * @param int      $callType the type of call in the template, 0 = no params, 1 = php-style call, 2 = named
3510
-     *                           parameters call
3511
-     * @param array    $map      the parameter map to use, if not provided it will be built from the callback
3512
-     *
3513
-     * @return array parameters sorted in the correct order with missing optional parameters filled
3514
-     * @throws CompilationException
3515
-     */
3516
-    protected function mapParams(array $params, $callback, $callType = 2, $map = null)
3517
-    {
3518
-        if (!$map) {
3519
-            $map = $this->getParamMap($callback);
3520
-        }
3521
-
3522
-        $paramlist = array();
3523
-
3524
-        // transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values))
3525
-        $ps = array();
3526
-        foreach ($params as $p) {
3527
-            if (is_array($p[1])) {
3528
-                $ps[$p[0]] = $p[1];
3529
-            } else {
3530
-                $ps[] = $p;
3531
-            }
3532
-        }
3533
-
3534
-        // loops over the param map and assigns values from the template or default value for unset optional params
3535
-        foreach ($map as $k => $v){
3536
-            if ($v[0] === '*') {
3537
-                // "rest" array parameter, fill every remaining params in it and then break
3538
-                if (count($ps) === 0) {
3539
-                    if ($v[1] === false) {
3540
-                        throw new CompilationException(
3541
-                            $this, 'Rest argument missing for ' . str_replace(
3542
-                                array(
3543
-                                    Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3544
-                                'Compile'
3545
-                                ), '', (is_array($callback) ? $callback[0] : $callback)
3546
-                            )
3547
-                        );
3548
-                    } else {
3549
-                        break;
3550
-                    }
3551
-                }
3552
-                $tmp  = array();
3553
-                $tmp2 = array();
3554
-                $tmp3 = array();
3555
-                foreach ($ps as $i => $p) {
3556
-                    $tmp[$i]  = $p[0];
3557
-                    $tmp2[$i] = $p[1];
3558
-                    $tmp3[$i] = isset($p[2]) ? $p[2] : 0;
3559
-                    unset($ps[$i]);
3560
-                }
3561
-                $paramlist[$v[0]] = array($tmp, $tmp2, $tmp3);
3562
-                unset($tmp, $tmp2, $i, $p);
3563
-                break;
3564
-            } elseif (isset($ps[$v[0]])) {
3565
-                // parameter is defined as named param
3566
-                $paramlist[$v[0]] = $ps[$v[0]];
3567
-                unset($ps[$v[0]]);
3568
-            } elseif (isset($ps[$k])) {
3569
-                // parameter is defined as ordered param
3570
-                $paramlist[$v[0]] = $ps[$k];
3571
-                unset($ps[$k]);
3572
-            } elseif ($v[1] === false) {
3573
-                // parameter is not defined and not optional, throw error
3574
-                if (is_array($callback)) {
3575
-                    if (is_object($callback[0])) {
3576
-                        $name = get_class($callback[0]) . '::' . $callback[1];
3577
-                    } else {
3578
-                        $name = $callback[0];
3579
-                    }
3580
-                } else {
3581
-                    $name = $callback;
3582
-                }
3583
-
3584
-                throw new CompilationException(
3585
-                    $this, 'Argument ' . $k . '/' . $v[0] . ' missing for ' . str_replace(
3586
-                        array(
3587
-                            Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3588
-                        'Compile'
3589
-                        ), '', $name
3590
-                    )
3591
-                );
3592
-            } elseif ($v[2] === null) {
3593
-                // enforce lowercased null if default value is null (php outputs NULL with var export)
3594
-                $paramlist[$v[0]] = array('null', null, self::T_NULL);
3595
-            } else {
3596
-                // outputs default value with var_export
3597
-                $paramlist[$v[0]] = array(var_export($v[2], true), $v[2]);
3598
-            }
3599
-        }
3600
-
3601
-        if (count($ps)) {
3602
-            foreach ($ps as $i => $p) {
3603
-                array_push($paramlist, $p);
3604
-            }
3605
-        }
3606
-
3607
-        return $paramlist;
3608
-    }
3609
-
3610
-    /**
3611
-     * Returns the parameter map of the given callback, it filters out entries typed as Dwoo and Compiler and turns the
3612
-     * rest parameter into a "*".
3613
-     *
3614
-     * @param callback $callback the function/method to reflect on
3615
-     *
3616
-     * @return array processed parameter map
3617
-     */
3618
-    protected function getParamMap($callback)
3619
-    {
3620
-        if (is_null($callback)) {
3621
-            return array(array('*', true));
3622
-        }
3623
-        if (is_array($callback)) {
3624
-            $ref = new ReflectionMethod($callback[0], $callback[1]);
3625
-        } else {
3626
-            $ref = new ReflectionFunction($callback);
3627
-        }
3628
-
3629
-        $out = array();
3630
-        foreach ($ref->getParameters() as $param) {
3631
-            if (($class = $param->getClass()) !== null && $class->name === 'Dwoo\Core') {
3632
-                continue;
3633
-            }
3634
-            if (($class = $param->getClass()) !== null && $class->name === 'Dwoo\Compiler') {
3635
-                continue;
3636
-            }
3637
-            if ($param->getName() === 'rest' && $param->isArray() === true) {
3638
-                $out[] = array('*', $param->isOptional(), null);
3639
-                continue;
3640
-            }
3641
-            $out[] = array(
3642
-                $param->getName(),
3643
-                $param->isOptional(),
3644
-                $param->isOptional() ? $param->getDefaultValue() : null
3645
-            );
3646
-        }
3647
-
3648
-        return $out;
3649
-    }
3650
-
3651
-    /**
3652
-     * Returns a default instance of this compiler, used by default by all Dwoo templates that do not have a
3653
-     * specific compiler assigned and when you do not override the default compiler factory function.
3654
-     *
3655
-     * @see    Core::setDefaultCompilerFactory()
3656
-     * @return Compiler
3657
-     */
3658
-    public static function compilerFactory()
3659
-    {
3660
-        if (self::$instance === null) {
3661
-            self::$instance = new self();
3662
-        }
3663
-
3664
-        return self::$instance;
3665
-    }
3314
+						} else {
3315
+							if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3316
+								$output = '$this->classCall(\'Plugin' . Core::toCamelCase($func) . '\', array(' . $params . '))';
3317
+							} elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($func)) !== false) {
3318
+								$output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . $func . '\', array(' . $params . '))';
3319
+							} elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !== false) {
3320
+								$output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\', array(' . $params . '))';
3321
+							} else {
3322
+								$output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
3323
+							}
3324
+						}
3325
+					}
3326
+				}
3327
+			}
3328
+		}
3329
+
3330
+		if ($curBlock === 'namedparam') {
3331
+			return array($output, $output);
3332
+		} elseif ($curBlock === 'var' || $m[1] === null) {
3333
+			return $output;
3334
+		} elseif ($curBlock === 'string' || $curBlock === 'root') {
3335
+			return $m[1] . '.' . $output . '.' . $m[1] . (isset($add) ? $add : null);
3336
+		}
3337
+
3338
+		return '';
3339
+	}
3340
+
3341
+	/**
3342
+	 * Recursively implodes an array in a similar manner as var_export() does but with some tweaks
3343
+	 * to handle pre-compiled values and the fact that we do not need to enclose everything with
3344
+	 * "array" and do not require top-level keys to be displayed.
3345
+	 *
3346
+	 * @param array $params        the array to implode
3347
+	 * @param bool  $recursiveCall if set to true, the function outputs key names for the top level
3348
+	 *
3349
+	 * @return string the imploded array
3350
+	 */
3351
+	public static function implode_r(array $params, $recursiveCall = false)
3352
+	{
3353
+		$out = '';
3354
+		foreach ($params as $k => $p) {
3355
+			if (is_array($p)) {
3356
+				$out2 = 'array(';
3357
+				foreach ($p as $k2 => $v) {
3358
+					$out2 .= var_export($k2, true) . ' => ' . (is_array($v) ? 'array(' . self::implode_r($v, true) . ')' : $v) . ', ';
3359
+				}
3360
+				$p = rtrim($out2, ', ') . ')';
3361
+			}
3362
+			if ($recursiveCall) {
3363
+				$out .= var_export($k, true) . ' => ' . $p . ', ';
3364
+			} else {
3365
+				$out .= $p . ', ';
3366
+			}
3367
+		}
3368
+
3369
+		return rtrim($out, ', ');
3370
+	}
3371
+
3372
+	/**
3373
+	 * Returns the plugin type of a plugin and adds it to the used plugins array if required.
3374
+	 *
3375
+	 * @param string $name plugin name, as found in the template
3376
+	 *
3377
+	 * @return int type as a multi bit flag composed of the Dwoo plugin types constants
3378
+	 * @throws Exception
3379
+	 * @throws SecurityException
3380
+	 * @throws Exception
3381
+	 */
3382
+	protected function getPluginType($name)
3383
+	{
3384
+		$pluginType = - 1;
3385
+
3386
+		if (($this->securityPolicy === null && (function_exists($name) || strtolower($name) === 'isset' || strtolower($name) === 'empty')) || ($this->securityPolicy !== null && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) !== false)) {
3387
+			$phpFunc = true;
3388
+		} elseif ($this->securityPolicy !== null && function_exists($name) && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) === false) {
3389
+			throw new SecurityException('Call to a disallowed php function : ' . $name);
3390
+		}
3391
+
3392
+		while ($pluginType <= 0) {
3393
+			// Template plugin compilable
3394
+			if (isset($this->templatePlugins[$name])) {
3395
+				$pluginType = Core::TEMPLATE_PLUGIN | Core::COMPILABLE_PLUGIN;
3396
+			} // Custom plugin
3397
+			elseif (isset($this->customPlugins[$name])) {
3398
+				$pluginType = $this->customPlugins[$name]['type'] | Core::CUSTOM_PLUGIN;
3399
+			} // Class blocks plugin
3400
+			elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3401
+				$pluginType = Core::CLASS_PLUGIN;
3402
+				if (is_subclass_of(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3403
+					$pluginType += Core::BLOCK_PLUGIN;
3404
+				}
3405
+				$interfaces = class_implements(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name));
3406
+				if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3407
+					$pluginType |= Core::COMPILABLE_PLUGIN;
3408
+				}
3409
+			} // Class functions plugin
3410
+			elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3411
+				$pluginType = Core::FUNC_PLUGIN + Core::CLASS_PLUGIN;
3412
+				$interfaces = class_implements(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name));
3413
+				if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3414
+					$pluginType |= Core::COMPILABLE_PLUGIN;
3415
+				}
3416
+			} // Class without namespace
3417
+			elseif (class_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3418
+				$pluginType = Core::CLASS_PLUGIN;
3419
+				$interfaces = class_implements('Plugin' . Core::toCamelCase($name));
3420
+				if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3421
+					$pluginType |= Core::COMPILABLE_PLUGIN;
3422
+				}
3423
+			} // Function plugin (with/without namespaces)
3424
+			elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase ($name)) !==
3425
+				false || function_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3426
+				$pluginType = Core::FUNC_PLUGIN;
3427
+			} // Function plugin compile (with/without namespaces)
3428
+			elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name) .
3429
+					'Compile') !== false || function_exists('Plugin' . Core::toCamelCase($name) . 'Compile') !==
3430
+				false) {
3431
+				$pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3432
+			} // Helper plugin class compile
3433
+			elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3434
+				$pluginType = Core::CLASS_PLUGIN | Core::COMPILABLE_PLUGIN;
3435
+			} // Helper plugin function compile
3436
+			elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name) . 'Compile') !== false) {
3437
+				$pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3438
+			} // Smarty modifier
3439
+			elseif (function_exists('smarty_modifier_' . $name) !== false) {
3440
+				$pluginType = Core::SMARTY_MODIFIER;
3441
+			} // Smarty function
3442
+			elseif (function_exists('smarty_function_' . $name) !== false) {
3443
+				$pluginType = Core::SMARTY_FUNCTION;
3444
+			} // Smarty block
3445
+			elseif (function_exists('smarty_block_' . $name) !== false) {
3446
+				$pluginType = Core::SMARTY_BLOCK;
3447
+			} // Everything else
3448
+			else {
3449
+				if ($pluginType === - 1) {
3450
+					try {
3451
+						$this->getDwoo()->getLoader()->loadPlugin('Plugin' . Core::toCamelCase($name));
3452
+					}
3453
+					catch (Exception $e) {
3454
+						if (isset($phpFunc)) {
3455
+							$pluginType = Core::NATIVE_PLUGIN;
3456
+						} elseif (is_object($this->getDwoo()->getPluginProxy()) && $this->getDwoo()->getPluginProxy()->handles($name)) {
3457
+							$pluginType = Core::PROXY_PLUGIN;
3458
+							break;
3459
+						} else {
3460
+							throw $e;
3461
+						}
3462
+					}
3463
+				} else {
3464
+					throw new Exception('Plugin "' . $name . '" could not be found, type:' . $pluginType);
3465
+				}
3466
+				++ $pluginType;
3467
+			}
3468
+		}
3469
+
3470
+		if (($pluginType & Core::COMPILABLE_PLUGIN) === 0 && ($pluginType & Core::NATIVE_PLUGIN) === 0 && ($pluginType & Core::PROXY_PLUGIN) === 0) {
3471
+			$this->addUsedPlugin(Core::toCamelCase($name), $pluginType);
3472
+		}
3473
+
3474
+		return $pluginType;
3475
+	}
3476
+
3477
+	/**
3478
+	 * Allows a plugin to load another one at compile time, this will also mark
3479
+	 * it as used by this template so it will be loaded at runtime (which can be
3480
+	 * useful for compiled plugins that rely on another plugin when their compiled
3481
+	 * code runs).
3482
+	 *
3483
+	 * @param string $name the plugin name
3484
+	 *
3485
+	 * @return void
3486
+	 */
3487
+	public function loadPlugin($name)
3488
+	{
3489
+		$this->getPluginType($name);
3490
+	}
3491
+
3492
+	/**
3493
+	 * Runs htmlentities over the matched <?php ?> blocks when the security policy enforces that.
3494
+	 *
3495
+	 * @param array $match matched php block
3496
+	 *
3497
+	 * @return string the htmlentities-converted string
3498
+	 */
3499
+	protected function phpTagEncodingHelper($match)
3500
+	{
3501
+		return htmlspecialchars($match[0]);
3502
+	}
3503
+
3504
+	/**
3505
+	 * Maps the parameters received from the template onto the parameters required by the given callback.
3506
+	 *
3507
+	 * @param array    $params   the array of parameters
3508
+	 * @param callback $callback the function or method to reflect on to find out the required parameters
3509
+	 * @param int      $callType the type of call in the template, 0 = no params, 1 = php-style call, 2 = named
3510
+	 *                           parameters call
3511
+	 * @param array    $map      the parameter map to use, if not provided it will be built from the callback
3512
+	 *
3513
+	 * @return array parameters sorted in the correct order with missing optional parameters filled
3514
+	 * @throws CompilationException
3515
+	 */
3516
+	protected function mapParams(array $params, $callback, $callType = 2, $map = null)
3517
+	{
3518
+		if (!$map) {
3519
+			$map = $this->getParamMap($callback);
3520
+		}
3521
+
3522
+		$paramlist = array();
3523
+
3524
+		// transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values))
3525
+		$ps = array();
3526
+		foreach ($params as $p) {
3527
+			if (is_array($p[1])) {
3528
+				$ps[$p[0]] = $p[1];
3529
+			} else {
3530
+				$ps[] = $p;
3531
+			}
3532
+		}
3533
+
3534
+		// loops over the param map and assigns values from the template or default value for unset optional params
3535
+		foreach ($map as $k => $v){
3536
+			if ($v[0] === '*') {
3537
+				// "rest" array parameter, fill every remaining params in it and then break
3538
+				if (count($ps) === 0) {
3539
+					if ($v[1] === false) {
3540
+						throw new CompilationException(
3541
+							$this, 'Rest argument missing for ' . str_replace(
3542
+								array(
3543
+									Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3544
+								'Compile'
3545
+								), '', (is_array($callback) ? $callback[0] : $callback)
3546
+							)
3547
+						);
3548
+					} else {
3549
+						break;
3550
+					}
3551
+				}
3552
+				$tmp  = array();
3553
+				$tmp2 = array();
3554
+				$tmp3 = array();
3555
+				foreach ($ps as $i => $p) {
3556
+					$tmp[$i]  = $p[0];
3557
+					$tmp2[$i] = $p[1];
3558
+					$tmp3[$i] = isset($p[2]) ? $p[2] : 0;
3559
+					unset($ps[$i]);
3560
+				}
3561
+				$paramlist[$v[0]] = array($tmp, $tmp2, $tmp3);
3562
+				unset($tmp, $tmp2, $i, $p);
3563
+				break;
3564
+			} elseif (isset($ps[$v[0]])) {
3565
+				// parameter is defined as named param
3566
+				$paramlist[$v[0]] = $ps[$v[0]];
3567
+				unset($ps[$v[0]]);
3568
+			} elseif (isset($ps[$k])) {
3569
+				// parameter is defined as ordered param
3570
+				$paramlist[$v[0]] = $ps[$k];
3571
+				unset($ps[$k]);
3572
+			} elseif ($v[1] === false) {
3573
+				// parameter is not defined and not optional, throw error
3574
+				if (is_array($callback)) {
3575
+					if (is_object($callback[0])) {
3576
+						$name = get_class($callback[0]) . '::' . $callback[1];
3577
+					} else {
3578
+						$name = $callback[0];
3579
+					}
3580
+				} else {
3581
+					$name = $callback;
3582
+				}
3583
+
3584
+				throw new CompilationException(
3585
+					$this, 'Argument ' . $k . '/' . $v[0] . ' missing for ' . str_replace(
3586
+						array(
3587
+							Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3588
+						'Compile'
3589
+						), '', $name
3590
+					)
3591
+				);
3592
+			} elseif ($v[2] === null) {
3593
+				// enforce lowercased null if default value is null (php outputs NULL with var export)
3594
+				$paramlist[$v[0]] = array('null', null, self::T_NULL);
3595
+			} else {
3596
+				// outputs default value with var_export
3597
+				$paramlist[$v[0]] = array(var_export($v[2], true), $v[2]);
3598
+			}
3599
+		}
3600
+
3601
+		if (count($ps)) {
3602
+			foreach ($ps as $i => $p) {
3603
+				array_push($paramlist, $p);
3604
+			}
3605
+		}
3606
+
3607
+		return $paramlist;
3608
+	}
3609
+
3610
+	/**
3611
+	 * Returns the parameter map of the given callback, it filters out entries typed as Dwoo and Compiler and turns the
3612
+	 * rest parameter into a "*".
3613
+	 *
3614
+	 * @param callback $callback the function/method to reflect on
3615
+	 *
3616
+	 * @return array processed parameter map
3617
+	 */
3618
+	protected function getParamMap($callback)
3619
+	{
3620
+		if (is_null($callback)) {
3621
+			return array(array('*', true));
3622
+		}
3623
+		if (is_array($callback)) {
3624
+			$ref = new ReflectionMethod($callback[0], $callback[1]);
3625
+		} else {
3626
+			$ref = new ReflectionFunction($callback);
3627
+		}
3628
+
3629
+		$out = array();
3630
+		foreach ($ref->getParameters() as $param) {
3631
+			if (($class = $param->getClass()) !== null && $class->name === 'Dwoo\Core') {
3632
+				continue;
3633
+			}
3634
+			if (($class = $param->getClass()) !== null && $class->name === 'Dwoo\Compiler') {
3635
+				continue;
3636
+			}
3637
+			if ($param->getName() === 'rest' && $param->isArray() === true) {
3638
+				$out[] = array('*', $param->isOptional(), null);
3639
+				continue;
3640
+			}
3641
+			$out[] = array(
3642
+				$param->getName(),
3643
+				$param->isOptional(),
3644
+				$param->isOptional() ? $param->getDefaultValue() : null
3645
+			);
3646
+		}
3647
+
3648
+		return $out;
3649
+	}
3650
+
3651
+	/**
3652
+	 * Returns a default instance of this compiler, used by default by all Dwoo templates that do not have a
3653
+	 * specific compiler assigned and when you do not override the default compiler factory function.
3654
+	 *
3655
+	 * @see    Core::setDefaultCompilerFactory()
3656
+	 * @return Compiler
3657
+	 */
3658
+	public static function compilerFactory()
3659
+	{
3660
+		if (self::$instance === null) {
3661
+			self::$instance = new self();
3662
+		}
3663
+
3664
+		return self::$instance;
3665
+	}
3666 3666
 }
Please login to merge, or discard this patch.
Spacing   +380 added lines, -382 removed lines patch added patch discarded remove patch
@@ -294,7 +294,7 @@  discard block
 block discarded – undo
294 294
      */
295 295
     public function setNestedCommentsHandling($allow = true)
296 296
     {
297
-        $this->allowNestedComments = (bool)$allow;
297
+        $this->allowNestedComments = (bool) $allow;
298 298
     }
299 299
 
300 300
     /**
@@ -319,7 +319,7 @@  discard block
 block discarded – undo
319 319
      */
320 320
     public function setLooseOpeningHandling($allow = false)
321 321
     {
322
-        $this->allowLooseOpenings = (bool)$allow;
322
+        $this->allowLooseOpenings = (bool) $allow;
323 323
     }
324 324
 
325 325
     /**
@@ -344,7 +344,7 @@  discard block
 block discarded – undo
344 344
      */
345 345
     public function setAutoEscape($enabled)
346 346
     {
347
-        $this->autoEscape = (bool)$enabled;
347
+        $this->autoEscape = (bool) $enabled;
348 348
     }
349 349
 
350 350
     /**
@@ -371,7 +371,7 @@  discard block
 block discarded – undo
371 371
     {
372 372
         if ($autoload) {
373 373
             $name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', Core::toCamelCase($callback));
374
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . $name;
374
+            $class = Core::NAMESPACE_PLUGINS_PROCESSORS.$name;
375 375
 
376 376
             if (class_exists($class)) {
377 377
                 $callback = array(new $class($this), 'process');
@@ -396,12 +396,12 @@  discard block
 block discarded – undo
396 396
     {
397 397
         if (($index = array_search($callback, $this->processors['pre'], true)) !== false) {
398 398
             unset($this->processors['pre'][$index]);
399
-        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
399
+        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS.str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
400 400
                     $callback),
401 401
                 $this->processors['pre'], true)) !== false) {
402 402
             unset($this->processors['pre'][$index]);
403 403
         } else {
404
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
404
+            $class = Core::NAMESPACE_PLUGINS_PROCESSORS.str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
405 405
             foreach ($this->processors['pre'] as $index => $proc) {
406 406
                 if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
407 407
                     unset($this->processors['pre'][$index]);
@@ -424,7 +424,7 @@  discard block
 block discarded – undo
424 424
     {
425 425
         if ($autoload) {
426 426
             $name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
427
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . Core::toCamelCase($name);
427
+            $class = Core::NAMESPACE_PLUGINS_PROCESSORS.Core::toCamelCase($name);
428 428
 
429 429
             if (class_exists($class)) {
430 430
                 $callback = array(new $class($this), 'process');
@@ -449,12 +449,12 @@  discard block
 block discarded – undo
449 449
     {
450 450
         if (($index = array_search($callback, $this->processors['post'], true)) !== false) {
451 451
             unset($this->processors['post'][$index]);
452
-        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
452
+        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS.str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
453 453
                     $callback),
454 454
                 $this->processors['post'], true)) !== false) {
455 455
             unset($this->processors['post'][$index]);
456 456
         } else {
457
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
457
+            $class = Core::NAMESPACE_PLUGINS_PROCESSORS.str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
458 458
             foreach ($this->processors['post'] as $index => $proc) {
459 459
                 if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
460 460
                     unset($this->processors['post'][$index]);
@@ -480,7 +480,7 @@  discard block
 block discarded – undo
480 480
                 $this->getDwoo()->getLoader()->loadPlugin($name);
481 481
             }
482 482
             catch (Exception $e) {
483
-                throw new Exception('Processor ' . $name . ' could not be found in your plugin directories, please ensure it is in a file named ' . $name . '.php in the plugin directory');
483
+                throw new Exception('Processor '.$name.' could not be found in your plugin directories, please ensure it is in a file named '.$name.'.php in the plugin directory');
484 484
             }
485 485
         }
486 486
 
@@ -666,7 +666,7 @@  discard block
 block discarded – undo
666 666
     public function setTemplateSource($newSource, $fromPointer = false)
667 667
     {
668 668
         if ($fromPointer === true) {
669
-            $this->templateSource = substr($this->templateSource, 0, $this->pointer) . $newSource;
669
+            $this->templateSource = substr($this->templateSource, 0, $this->pointer).$newSource;
670 670
         } else {
671 671
             $this->templateSource = $newSource;
672 672
         }
@@ -737,11 +737,11 @@  discard block
 block discarded – undo
737 737
 
738 738
                 if ($this->debug) {
739 739
                     echo "\n";
740
-                    echo 'COMPILER INIT' . "\n";
740
+                    echo 'COMPILER INIT'."\n";
741 741
                 }
742 742
 
743 743
                 if ($this->debug) {
744
-                    echo 'PROCESSING PREPROCESSORS (' . count($this->processors['pre']) . ')' . "\n";
744
+                    echo 'PROCESSING PREPROCESSORS ('.count($this->processors['pre']).')'."\n";
745 745
                 }
746 746
 
747 747
                 // runs preprocessors
@@ -785,23 +785,23 @@  discard block
 block discarded – undo
785 785
             if ($pos === false) {
786 786
                 $this->push(substr($tpl, $ptr), 0);
787 787
                 break;
788
-            } elseif (substr($tpl, $pos - 1, 1) === '\\' && substr($tpl, $pos - 2, 1) !== '\\') {
789
-                $this->push(substr($tpl, $ptr, $pos - $ptr - 1) . $this->ld);
790
-                $ptr = $pos + strlen($this->ld);
791
-            } elseif (preg_match('/^' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . 'literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', substr($tpl, $pos), $litOpen)) {
792
-                if (!preg_match('/' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . '\/literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', $tpl, $litClose, PREG_OFFSET_CAPTURE, $pos)) {
788
+            } elseif (substr($tpl, $pos-1, 1) === '\\' && substr($tpl, $pos-2, 1) !== '\\') {
789
+                $this->push(substr($tpl, $ptr, $pos-$ptr-1).$this->ld);
790
+                $ptr = $pos+strlen($this->ld);
791
+            } elseif (preg_match('/^'.$this->ldr.($this->allowLooseOpenings ? '\s*' : '').'literal'.($this->allowLooseOpenings ? '\s*' : '').$this->rdr.'/s', substr($tpl, $pos), $litOpen)) {
792
+                if (!preg_match('/'.$this->ldr.($this->allowLooseOpenings ? '\s*' : '').'\/literal'.($this->allowLooseOpenings ? '\s*' : '').$this->rdr.'/s', $tpl, $litClose, PREG_OFFSET_CAPTURE, $pos)) {
793 793
                     throw new CompilationException($this, 'The {literal} blocks must be closed explicitly with {/literal}');
794 794
                 }
795 795
                 $endpos = $litClose[0][1];
796
-                $this->push(substr($tpl, $ptr, $pos - $ptr) . substr($tpl, $pos + strlen($litOpen[0]), $endpos - $pos - strlen($litOpen[0])));
797
-                $ptr = $endpos + strlen($litClose[0][0]);
796
+                $this->push(substr($tpl, $ptr, $pos-$ptr).substr($tpl, $pos+strlen($litOpen[0]), $endpos-$pos-strlen($litOpen[0])));
797
+                $ptr = $endpos+strlen($litClose[0][0]);
798 798
             } else {
799
-                if (substr($tpl, $pos - 2, 1) === '\\' && substr($tpl, $pos - 1, 1) === '\\') {
800
-                    $this->push(substr($tpl, $ptr, $pos - $ptr - 1));
799
+                if (substr($tpl, $pos-2, 1) === '\\' && substr($tpl, $pos-1, 1) === '\\') {
800
+                    $this->push(substr($tpl, $ptr, $pos-$ptr-1));
801 801
                     $ptr = $pos;
802 802
                 }
803 803
 
804
-                $this->push(substr($tpl, $ptr, $pos - $ptr));
804
+                $this->push(substr($tpl, $ptr, $pos-$ptr));
805 805
                 $ptr = $pos;
806 806
 
807 807
                 $pos += strlen($this->ld);
@@ -819,7 +819,7 @@  discard block
 block discarded – undo
819 819
 
820 820
                 // check that there is an end tag present
821 821
                 if (strpos($tpl, $this->rd, $pos) === false) {
822
-                    throw new CompilationException($this, 'A template tag was not closed, started with "' . substr($tpl, $ptr, 30) . '"');
822
+                    throw new CompilationException($this, 'A template tag was not closed, started with "'.substr($tpl, $ptr, 30).'"');
823 823
                 }
824 824
 
825 825
                 $ptr += strlen($this->ld);
@@ -833,7 +833,7 @@  discard block
 block discarded – undo
833 833
                         continue 2;
834 834
                     }
835 835
 
836
-                    $len = $subptr - $ptr;
836
+                    $len = $subptr-$ptr;
837 837
                     $this->push($parsed, substr_count(substr($tpl, $ptr, $len), "\n"));
838 838
                     $ptr += $len;
839 839
 
@@ -847,7 +847,7 @@  discard block
 block discarded – undo
847 847
         $compiled .= $this->removeBlock('TopLevelBlock');
848 848
 
849 849
         if ($this->debug) {
850
-            echo 'PROCESSING POSTPROCESSORS' . "\n";
850
+            echo 'PROCESSING POSTPROCESSORS'."\n";
851 851
         }
852 852
 
853 853
         foreach ($this->processors['post'] as $postProc) {
@@ -863,7 +863,7 @@  discard block
 block discarded – undo
863 863
         unset($postProc);
864 864
 
865 865
         if ($this->debug) {
866
-            echo 'COMPILATION COMPLETE : MEM USAGE : ' . memory_get_usage() . "\n";
866
+            echo 'COMPILATION COMPLETE : MEM USAGE : '.memory_get_usage()."\n";
867 867
         }
868 868
 
869 869
         $output = "<?php\n/* template head */\n";
@@ -876,30 +876,30 @@  discard block
 block discarded – undo
876 876
 
877 877
             switch ($type) {
878 878
                 case Core::CLASS_PLUGIN:
879
-                case Core::CLASS_PLUGIN + Core::BLOCK_PLUGIN:
880
-                    if (class_exists('Plugin' . $plugin) !== false) {
881
-                        $output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
879
+                case Core::CLASS_PLUGIN+Core::BLOCK_PLUGIN:
880
+                    if (class_exists('Plugin'.$plugin) !== false) {
881
+                        $output .= "if (class_exists('"."Plugin".$plugin."')===false)".
882 882
                         "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
883 883
                     } else {
884
-                        $output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_BLOCKS . "Plugin" . $plugin . "')===false)".
884
+                        $output .= "if (class_exists('".Core::NAMESPACE_PLUGINS_BLOCKS."Plugin".$plugin."')===false)".
885 885
                         "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
886 886
                     }
887 887
                     break;
888
-                case Core::CLASS_PLUGIN + Core::FUNC_PLUGIN:
889
-                    if (class_exists('Plugin' . $plugin) !== false) {
890
-                        $output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
888
+                case Core::CLASS_PLUGIN+Core::FUNC_PLUGIN:
889
+                    if (class_exists('Plugin'.$plugin) !== false) {
890
+                        $output .= "if (class_exists('"."Plugin".$plugin."')===false)".
891 891
                             "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
892 892
                     } else {
893
-                        $output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
893
+                        $output .= "if (class_exists('".Core::NAMESPACE_PLUGINS_FUNCTIONS."Plugin".$plugin."')===false)".
894 894
                             "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
895 895
                     }
896 896
                     break;
897 897
                 case Core::FUNC_PLUGIN:
898
-                    if (function_exists('Plugin' . $plugin) !== false) {
899
-                        $output .= "if (function_exists('" . "Plugin" . $plugin . "')===false)".
898
+                    if (function_exists('Plugin'.$plugin) !== false) {
899
+                        $output .= "if (function_exists('"."Plugin".$plugin."')===false)".
900 900
                         "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
901 901
                     } else {
902
-                        $output .= "if (function_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
902
+                        $output .= "if (function_exists('".Core::NAMESPACE_PLUGINS_FUNCTIONS."Plugin".$plugin."')===false)".
903 903
                         "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
904 904
                     }
905 905
                     break;
@@ -919,7 +919,7 @@  discard block
 block discarded – undo
919 919
                     $output .= $this->getDwoo()->getPluginProxy()->getLoader($plugin);
920 920
                     break;
921 921
                 default:
922
-                    throw new CompilationException($this, 'Type error for ' . $plugin . ' with type' . $type);
922
+                    throw new CompilationException($this, 'Type error for '.$plugin.' with type'.$type);
923 923
             }
924 924
         }
925 925
 
@@ -930,30 +930,30 @@  discard block
 block discarded – undo
930 930
         }
931 931
         foreach ($this->templatePlugins as $function) {
932 932
             if (isset($function['called']) && $function['called'] === true) {
933
-                $output .= $function['body'] . PHP_EOL;
933
+                $output .= $function['body'].PHP_EOL;
934 934
             }
935 935
         }
936 936
 
937
-        $output .= $compiled . "\n?>";
937
+        $output .= $compiled."\n?>";
938 938
 
939
-        $output = preg_replace('/(?<!;|\}|\*\/|\n|\{)(\s*' . preg_quote(self::PHP_CLOSE, '/') . preg_quote(self::PHP_OPEN, '/') . ')/', ";\n", $output);
940
-        $output = str_replace(self::PHP_CLOSE . self::PHP_OPEN, "\n", $output);
939
+        $output = preg_replace('/(?<!;|\}|\*\/|\n|\{)(\s*'.preg_quote(self::PHP_CLOSE, '/').preg_quote(self::PHP_OPEN, '/').')/', ";\n", $output);
940
+        $output = str_replace(self::PHP_CLOSE.self::PHP_OPEN, "\n", $output);
941 941
 
942 942
         // handle <?xml tag at the beginning
943 943
         $output = preg_replace('#(/\* template body \*/ \?>\s*)<\?xml#is', '$1<?php echo \'<?xml\'; ?>', $output);
944 944
 
945 945
         // add another line break after PHP closing tags that have a line break following,
946 946
         // as we do not know whether it's intended, and PHP will strip it otherwise
947
-        $output = preg_replace('/(?<!"|<\?xml)\s*\?>\n/', '$0' . "\n", $output);
947
+        $output = preg_replace('/(?<!"|<\?xml)\s*\?>\n/', '$0'."\n", $output);
948 948
 
949 949
         if ($this->debug) {
950
-            echo '=============================================================================================' . "\n";
950
+            echo '============================================================================================='."\n";
951 951
             $lines = preg_split('{\r\n|\n|<br />}', $output);
952 952
             array_shift($lines);
953 953
             foreach ($lines as $i => $line) {
954
-                echo ($i + 1) . '. ' . $line . "\r\n";
954
+                echo ($i+1).'. '.$line."\r\n";
955 955
             }
956
-            echo '=============================================================================================' . "\n";
956
+            echo '============================================================================================='."\n";
957 957
         }
958 958
 
959 959
         $this->template = $this->dwoo = null;
@@ -970,13 +970,13 @@  discard block
 block discarded – undo
970 970
     protected function resolveSubTemplateDependencies($function)
971 971
     {
972 972
         if ($this->debug) {
973
-            echo 'Compiler::' . __FUNCTION__ . "\n";
973
+            echo 'Compiler::'.__FUNCTION__."\n";
974 974
         }
975 975
 
976 976
         $body = $this->templatePlugins[$function]['body'];
977 977
         foreach ($this->templatePlugins as $func => $attr) {
978
-            if ($func !== $function && !isset($attr['called']) && strpos($body, Core::NAMESPACE_PLUGINS_FUNCTIONS .
979
-            'Plugin' . Core::toCamelCase($func)) !== false) {
978
+            if ($func !== $function && !isset($attr['called']) && strpos($body, Core::NAMESPACE_PLUGINS_FUNCTIONS.
979
+            'Plugin'.Core::toCamelCase($func)) !== false) {
980 980
                 $this->templatePlugins[$func]['called'] = true;
981 981
                 $this->resolveSubTemplateDependencies($func);
982 982
             }
@@ -1000,14 +1000,14 @@  discard block
 block discarded – undo
1000 1000
 
1001 1001
         if ($this->curBlock['buffer'] === null && count($this->stack) > 1) {
1002 1002
             // buffer is not initialized yet (the block has just been created)
1003
-            $this->stack[count($this->stack) - 2]['buffer'] .= (string)$content;
1003
+            $this->stack[count($this->stack)-2]['buffer'] .= (string) $content;
1004 1004
             $this->curBlock['buffer'] = '';
1005 1005
         } else {
1006 1006
             if (!isset($this->curBlock['buffer'])) {
1007 1007
                 throw new CompilationException($this, 'The template has been closed too early, you probably have an extra block-closing tag somewhere');
1008 1008
             }
1009 1009
             // append current content to current block's buffer
1010
-            $this->curBlock['buffer'] .= (string)$content;
1010
+            $this->curBlock['buffer'] .= (string) $content;
1011 1011
         }
1012 1012
         $this->line += $lineCount;
1013 1013
     }
@@ -1077,23 +1077,23 @@  discard block
 block discarded – undo
1077 1077
     public function addBlock($type, array $params, $paramtype)
1078 1078
     {
1079 1079
         if ($this->debug) {
1080
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1080
+            echo 'Compiler::'.__FUNCTION__."\n";
1081 1081
         }
1082 1082
 
1083
-        $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type);
1083
+        $class = Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($type);
1084 1084
         if (class_exists($class) === false) {
1085 1085
             $this->getDwoo()->getLoader()->loadPlugin($type);
1086 1086
         }
1087 1087
         $params = $this->mapParams($params, array($class, 'init'), $paramtype);
1088 1088
 
1089
-        $this->stack[]  = array(
1089
+        $this->stack[] = array(
1090 1090
             'type'   => $type,
1091 1091
             'params' => $params,
1092 1092
             'custom' => false,
1093 1093
             'class'  => $class,
1094 1094
             'buffer' => null
1095 1095
         );
1096
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1096
+        $this->curBlock = &$this->stack[count($this->stack)-1];
1097 1097
 
1098 1098
         return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1099 1099
     }
@@ -1118,14 +1118,14 @@  discard block
 block discarded – undo
1118 1118
 
1119 1119
         $params = $this->mapParams($params, array($class, 'init'), $paramtype);
1120 1120
 
1121
-        $this->stack[]  = array(
1121
+        $this->stack[] = array(
1122 1122
             'type'   => $type,
1123 1123
             'params' => $params,
1124 1124
             'custom' => true,
1125 1125
             'class'  => $class,
1126 1126
             'buffer' => null
1127 1127
         );
1128
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1128
+        $this->curBlock = &$this->stack[count($this->stack)-1];
1129 1129
 
1130 1130
         return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1131 1131
     }
@@ -1140,21 +1140,21 @@  discard block
 block discarded – undo
1140 1140
     public function injectBlock($type, array $params)
1141 1141
     {
1142 1142
         if ($this->debug) {
1143
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1143
+            echo 'Compiler::'.__FUNCTION__."\n";
1144 1144
         }
1145 1145
 
1146
-        $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type);
1146
+        $class = Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($type);
1147 1147
         if (class_exists($class) === false) {
1148 1148
             $this->getDwoo()->getLoader()->loadPlugin($type);
1149 1149
         }
1150
-        $this->stack[]  = array(
1150
+        $this->stack[] = array(
1151 1151
             'type'   => $type,
1152 1152
             'params' => $params,
1153 1153
             'custom' => false,
1154 1154
             'class'  => $class,
1155 1155
             'buffer' => null
1156 1156
         );
1157
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1157
+        $this->curBlock = &$this->stack[count($this->stack)-1];
1158 1158
     }
1159 1159
 
1160 1160
     /**
@@ -1169,7 +1169,7 @@  discard block
 block discarded – undo
1169 1169
     public function removeBlock($type)
1170 1170
     {
1171 1171
         if ($this->debug) {
1172
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1172
+            echo 'Compiler::'.__FUNCTION__."\n";
1173 1173
         }
1174 1174
 
1175 1175
         $output = '';
@@ -1183,10 +1183,10 @@  discard block
 block discarded – undo
1183 1183
                 if ($top['custom']) {
1184 1184
                     $class = $top['class'];
1185 1185
                 } else {
1186
-                    $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($top['type']);
1186
+                    $class = Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($top['type']);
1187 1187
                 }
1188 1188
                 if (count($this->stack)) {
1189
-                    $this->curBlock = &$this->stack[count($this->stack) - 1];
1189
+                    $this->curBlock = &$this->stack[count($this->stack)-1];
1190 1190
                     $this->push(call_user_func(array(
1191 1191
                         $class,
1192 1192
                         'postProcessing'
@@ -1207,7 +1207,7 @@  discard block
 block discarded – undo
1207 1207
                 }
1208 1208
             }
1209 1209
 
1210
-            throw new CompilationException($this, 'Syntax malformation, a block of type "' . $type . '" was closed but was not opened');
1210
+            throw new CompilationException($this, 'Syntax malformation, a block of type "'.$type.'" was closed but was not opened');
1211 1211
             break;
1212 1212
         }
1213 1213
 
@@ -1246,7 +1246,7 @@  discard block
 block discarded – undo
1246 1246
             }
1247 1247
         }
1248 1248
 
1249
-        throw new CompilationException($this, 'A parent block of type "' . $type . '" is required and can not be found');
1249
+        throw new CompilationException($this, 'A parent block of type "'.$type.'" is required and can not be found');
1250 1250
     }
1251 1251
 
1252 1252
     /**
@@ -1269,7 +1269,7 @@  discard block
 block discarded – undo
1269 1269
     public function removeTopBlock()
1270 1270
     {
1271 1271
         if ($this->debug) {
1272
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1272
+            echo 'Compiler::'.__FUNCTION__."\n";
1273 1273
         }
1274 1274
 
1275 1275
         $o = array_pop($this->stack);
@@ -1279,10 +1279,10 @@  discard block
 block discarded – undo
1279 1279
         if ($o['custom']) {
1280 1280
             $class = $o['class'];
1281 1281
         } else {
1282
-            $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($o['type']);
1282
+            $class = Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($o['type']);
1283 1283
         }
1284 1284
 
1285
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1285
+        $this->curBlock = &$this->stack[count($this->stack)-1];
1286 1286
 
1287 1287
         return call_user_func(array($class, 'postProcessing'), $this, $o['params'], '', '', $o['buffer']);
1288 1288
     }
@@ -1361,7 +1361,7 @@  discard block
 block discarded – undo
1361 1361
     protected function parse($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1362 1362
     {
1363 1363
         if ($this->debug) {
1364
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1364
+            echo 'Compiler::'.__FUNCTION__."\n";
1365 1365
         }
1366 1366
 
1367 1367
         if ($to === null) {
@@ -1378,14 +1378,14 @@  discard block
 block discarded – undo
1378 1378
                 // end template tag
1379 1379
                 $pointer += strlen($this->rd);
1380 1380
                 if ($this->debug) {
1381
-                    echo 'TEMPLATE PARSING ENDED' . "\n";
1381
+                    echo 'TEMPLATE PARSING ENDED'."\n";
1382 1382
                 }
1383 1383
 
1384 1384
                 return false;
1385 1385
             }
1386
-            ++ $from;
1386
+            ++$from;
1387 1387
             if ($pointer !== null) {
1388
-                ++ $pointer;
1388
+                ++$pointer;
1389 1389
             }
1390 1390
             if ($from >= $to) {
1391 1391
                 if (is_array($parsingParams)) {
@@ -1397,22 +1397,22 @@  discard block
 block discarded – undo
1397 1397
             $first = $in[$from];
1398 1398
         }
1399 1399
 
1400
-        $substr = substr($in, $from, $to - $from);
1400
+        $substr = substr($in, $from, $to-$from);
1401 1401
 
1402 1402
         if ($this->debug) {
1403
-            echo 'PARSE CALL : PARSING "' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . '" @ ' . $from . ':' . $to . ' in ' . $curBlock . ' : pointer=' . $pointer . "\n";
1403
+            echo 'PARSE CALL : PARSING "'.htmlentities(substr($in, $from, min($to-$from, 50))).(($to-$from) > 50 ? '...' : '').'" @ '.$from.':'.$to.' in '.$curBlock.' : pointer='.$pointer."\n";
1404 1404
         }
1405 1405
         $parsed = '';
1406 1406
 
1407 1407
         if ($curBlock === 'root' && $first === '*') {
1408 1408
             $src      = $this->getTemplateSource();
1409
-            $startpos = $this->getPointer() - strlen($this->ld);
1409
+            $startpos = $this->getPointer()-strlen($this->ld);
1410 1410
             if (substr($src, $startpos, strlen($this->ld)) === $this->ld) {
1411 1411
                 if ($startpos > 0) {
1412 1412
                     do {
1413 1413
                         $char = substr($src, -- $startpos, 1);
1414 1414
                         if ($char == "\n") {
1415
-                            ++ $startpos;
1415
+                            ++$startpos;
1416 1416
                             $whitespaceStart = true;
1417 1417
                             break;
1418 1418
                         }
@@ -1423,12 +1423,12 @@  discard block
 block discarded – undo
1423 1423
                 if (!isset($whitespaceStart)) {
1424 1424
                     $startpos = $this->getPointer();
1425 1425
                 } else {
1426
-                    $pointer -= $this->getPointer() - $startpos;
1426
+                    $pointer -= $this->getPointer()-$startpos;
1427 1427
                 }
1428 1428
 
1429
-                if ($this->allowNestedComments && strpos($src, $this->ld . '*', $this->getPointer()) !== false) {
1430
-                    $comOpen  = $this->ld . '*';
1431
-                    $comClose = '*' . $this->rd;
1429
+                if ($this->allowNestedComments && strpos($src, $this->ld.'*', $this->getPointer()) !== false) {
1430
+                    $comOpen  = $this->ld.'*';
1431
+                    $comClose = '*'.$this->rd;
1432 1432
                     $level    = 1;
1433 1433
                     $ptr      = $this->getPointer();
1434 1434
 
@@ -1438,33 +1438,33 @@  discard block
 block discarded – undo
1438 1438
 
1439 1439
                         if ($open !== false && $close !== false) {
1440 1440
                             if ($open < $close) {
1441
-                                $ptr = $open + strlen($comOpen);
1442
-                                ++ $level;
1441
+                                $ptr = $open+strlen($comOpen);
1442
+                                ++$level;
1443 1443
                             } else {
1444
-                                $ptr = $close + strlen($comClose);
1445
-                                -- $level;
1444
+                                $ptr = $close+strlen($comClose);
1445
+                                --$level;
1446 1446
                             }
1447 1447
                         } elseif ($open !== false) {
1448
-                            $ptr = $open + strlen($comOpen);
1449
-                            ++ $level;
1448
+                            $ptr = $open+strlen($comOpen);
1449
+                            ++$level;
1450 1450
                         } elseif ($close !== false) {
1451
-                            $ptr = $close + strlen($comClose);
1452
-                            -- $level;
1451
+                            $ptr = $close+strlen($comClose);
1452
+                            --$level;
1453 1453
                         } else {
1454 1454
                             $ptr = strlen($src);
1455 1455
                         }
1456 1456
                     }
1457
-                    $endpos = $ptr - strlen('*' . $this->rd);
1457
+                    $endpos = $ptr-strlen('*'.$this->rd);
1458 1458
                 } else {
1459
-                    $endpos = strpos($src, '*' . $this->rd, $startpos);
1459
+                    $endpos = strpos($src, '*'.$this->rd, $startpos);
1460 1460
                     if ($endpos == false) {
1461 1461
                         throw new CompilationException($this, 'Un-ended comment');
1462 1462
                     }
1463 1463
                 }
1464
-                $pointer += $endpos - $startpos + strlen('*' . $this->rd);
1465
-                if (isset($whitespaceStart) && preg_match('#^[\t ]*\r?\n#', substr($src, $endpos + strlen('*' . $this->rd)), $m)) {
1464
+                $pointer += $endpos-$startpos+strlen('*'.$this->rd);
1465
+                if (isset($whitespaceStart) && preg_match('#^[\t ]*\r?\n#', substr($src, $endpos+strlen('*'.$this->rd)), $m)) {
1466 1466
                     $pointer += strlen($m[0]);
1467
-                    $this->curBlock['buffer'] = substr($this->curBlock['buffer'], 0, strlen($this->curBlock['buffer']) - ($this->getPointer() - $startpos - strlen($this->ld)));
1467
+                    $this->curBlock['buffer'] = substr($this->curBlock['buffer'], 0, strlen($this->curBlock['buffer'])-($this->getPointer()-$startpos-strlen($this->ld)));
1468 1468
                 }
1469 1469
 
1470 1470
                 return false;
@@ -1481,20 +1481,20 @@  discard block
 block discarded – undo
1481 1481
         } elseif (($first === '"' || $first === "'") && !(is_array($parsingParams) && preg_match('#^([\'"])[a-z0-9_]+\1\s*=>?(?:\s+|[^=])#i', $substr))) {
1482 1482
             // string
1483 1483
             $out = $this->parseString($in, $from, $to, $parsingParams, $curBlock, $pointer);
1484
-        } elseif (preg_match('/^\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?(' . (is_array($parsingParams) || $curBlock != 'root' ? '' : '\s+[^(]|') . '\s*\(|\s*' . $this->rdr . '|\s*;)/i', $substr)) {
1484
+        } elseif (preg_match('/^\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?('.(is_array($parsingParams) || $curBlock != 'root' ? '' : '\s+[^(]|').'\s*\(|\s*'.$this->rdr.'|\s*;)/i', $substr)) {
1485 1485
             // func
1486 1486
             $out    = $this->parseFunction($in, $from, $to, $parsingParams, $curBlock, $pointer);
1487 1487
             $parsed = 'func';
1488 1488
         } elseif ($first === ';') {
1489 1489
             // instruction end
1490 1490
             if ($this->debug) {
1491
-                echo 'END OF INSTRUCTION' . "\n";
1491
+                echo 'END OF INSTRUCTION'."\n";
1492 1492
             }
1493 1493
             if ($pointer !== null) {
1494
-                ++ $pointer;
1494
+                ++$pointer;
1495 1495
             }
1496 1496
 
1497
-            return $this->parse($in, $from + 1, $to, false, 'root', $pointer);
1497
+            return $this->parse($in, $from+1, $to, false, 'root', $pointer);
1498 1498
         } elseif ($curBlock === 'root' && preg_match('#^/([a-z_][a-z0-9_]*)?#i', $substr, $match)) {
1499 1499
             // close block
1500 1500
             if (!empty($match[1]) && $match[1] == 'else') {
@@ -1511,13 +1511,13 @@  discard block
 block discarded – undo
1511 1511
                     $pointer -= strlen($match[0]);
1512 1512
                 }
1513 1513
                 if ($this->debug) {
1514
-                    echo 'TOP BLOCK CLOSED' . "\n";
1514
+                    echo 'TOP BLOCK CLOSED'."\n";
1515 1515
                 }
1516 1516
 
1517 1517
                 return $this->removeTopBlock();
1518 1518
             } else {
1519 1519
                 if ($this->debug) {
1520
-                    echo 'BLOCK OF TYPE ' . $match[1] . ' CLOSED' . "\n";
1520
+                    echo 'BLOCK OF TYPE '.$match[1].' CLOSED'."\n";
1521 1521
                 }
1522 1522
 
1523 1523
                 return $this->removeBlock($match[1]);
@@ -1525,19 +1525,19 @@  discard block
 block discarded – undo
1525 1525
         } elseif ($curBlock === 'root' && substr($substr, 0, strlen($this->rd)) === $this->rd) {
1526 1526
             // end template tag
1527 1527
             if ($this->debug) {
1528
-                echo 'TAG PARSING ENDED' . "\n";
1528
+                echo 'TAG PARSING ENDED'."\n";
1529 1529
             }
1530 1530
             $pointer += strlen($this->rd);
1531 1531
 
1532 1532
             return false;
1533
-        } elseif (is_array($parsingParams) && preg_match('#^(([\'"]?)[a-z0-9_]+\2\s*=' . ($curBlock === 'array' ? '>?' : '') . ')(?:\s+|[^=]).*#i', $substr, $match)) {
1533
+        } elseif (is_array($parsingParams) && preg_match('#^(([\'"]?)[a-z0-9_]+\2\s*='.($curBlock === 'array' ? '>?' : '').')(?:\s+|[^=]).*#i', $substr, $match)) {
1534 1534
             // named parameter
1535 1535
             if ($this->debug) {
1536
-                echo 'NAMED PARAM FOUND' . "\n";
1536
+                echo 'NAMED PARAM FOUND'."\n";
1537 1537
             }
1538 1538
             $len = strlen($match[1]);
1539
-            while (substr($in, $from + $len, 1) === ' ') {
1540
-                ++ $len;
1539
+            while (substr($in, $from+$len, 1) === ' ') {
1540
+                ++$len;
1541 1541
             }
1542 1542
             if ($pointer !== null) {
1543 1543
                 $pointer += $len;
@@ -1545,7 +1545,7 @@  discard block
 block discarded – undo
1545 1545
 
1546 1546
             $output = array(
1547 1547
                 trim($match[1], " \t\r\n=>'\""),
1548
-                $this->parse($in, $from + $len, $to, false, 'namedparam', $pointer)
1548
+                $this->parse($in, $from+$len, $to, false, 'namedparam', $pointer)
1549 1549
             );
1550 1550
 
1551 1551
             $parsingParams[] = $output;
@@ -1566,31 +1566,31 @@  discard block
 block discarded – undo
1566 1566
             $out = $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1567 1567
         } else {
1568 1568
             // parse error
1569
-            throw new CompilationException($this, 'Parse error in "' . substr($in, $from, $to - $from) . '"');
1569
+            throw new CompilationException($this, 'Parse error in "'.substr($in, $from, $to-$from).'"');
1570 1570
         }
1571 1571
 
1572 1572
         if (empty($out)) {
1573 1573
             return '';
1574 1574
         }
1575 1575
 
1576
-        $substr = substr($in, $pointer, $to - $pointer);
1576
+        $substr = substr($in, $pointer, $to-$pointer);
1577 1577
 
1578 1578
         // var parsed, check if any var-extension applies
1579 1579
         if ($parsed === 'var') {
1580 1580
             if (preg_match('#^\s*([/%+*-])\s*([a-z0-9]|\$)#i', $substr, $match)) {
1581 1581
                 if ($this->debug) {
1582
-                    echo 'PARSING POST-VAR EXPRESSION ' . $substr . "\n";
1582
+                    echo 'PARSING POST-VAR EXPRESSION '.$substr."\n";
1583 1583
                 }
1584 1584
                 // parse expressions
1585
-                $pointer += strlen($match[0]) - 1;
1585
+                $pointer += strlen($match[0])-1;
1586 1586
                 if (is_array($parsingParams)) {
1587 1587
                     if ($match[2] == '$') {
1588 1588
                         $expr = $this->parseVar($in, $pointer, $to, array(), $curBlock, $pointer);
1589 1589
                     } else {
1590 1590
                         $expr = $this->parse($in, $pointer, $to, array(), 'expression', $pointer);
1591 1591
                     }
1592
-                    $out[count($out) - 1][0] .= $match[1] . $expr[0][0];
1593
-                    $out[count($out) - 1][1] .= $match[1] . $expr[0][1];
1592
+                    $out[count($out)-1][0] .= $match[1].$expr[0][0];
1593
+                    $out[count($out)-1][1] .= $match[1].$expr[0][1];
1594 1594
                 } else {
1595 1595
                     if ($match[2] == '$') {
1596 1596
                         $expr = $this->parseVar($in, $pointer, $to, false, $curBlock, $pointer);
@@ -1598,26 +1598,26 @@  discard block
 block discarded – undo
1598 1598
                         $expr = $this->parse($in, $pointer, $to, false, 'expression', $pointer);
1599 1599
                     }
1600 1600
                     if (is_array($out) && is_array($expr)) {
1601
-                        $out[0] .= $match[1] . $expr[0];
1602
-                        $out[1] .= $match[1] . $expr[1];
1601
+                        $out[0] .= $match[1].$expr[0];
1602
+                        $out[1] .= $match[1].$expr[1];
1603 1603
                     } elseif (is_array($out)) {
1604
-                        $out[0] .= $match[1] . $expr;
1605
-                        $out[1] .= $match[1] . $expr;
1604
+                        $out[0] .= $match[1].$expr;
1605
+                        $out[1] .= $match[1].$expr;
1606 1606
                     } elseif (is_array($expr)) {
1607
-                        $out .= $match[1] . $expr[0];
1607
+                        $out .= $match[1].$expr[0];
1608 1608
                     } else {
1609
-                        $out .= $match[1] . $expr;
1609
+                        $out .= $match[1].$expr;
1610 1610
                     }
1611 1611
                 }
1612 1612
             } elseif ($curBlock === 'root' && preg_match('#^(\s*(?:[+/*%-.]=|=|\+\+|--)\s*)(.*)#s', $substr, $match)) {
1613 1613
                 if ($this->debug) {
1614
-                    echo 'PARSING POST-VAR ASSIGNMENT ' . $substr . "\n";
1614
+                    echo 'PARSING POST-VAR ASSIGNMENT '.$substr."\n";
1615 1615
                 }
1616 1616
                 // parse assignment
1617 1617
                 $value    = $match[2];
1618 1618
                 $operator = trim($match[1]);
1619 1619
                 if (substr($value, 0, 1) == '=') {
1620
-                    throw new CompilationException($this, 'Unexpected "=" in <em>' . $substr . '</em>');
1620
+                    throw new CompilationException($this, 'Unexpected "=" in <em>'.$substr.'</em>');
1621 1621
                 }
1622 1622
 
1623 1623
                 if ($pointer !== null) {
@@ -1638,7 +1638,7 @@  discard block
 block discarded – undo
1638 1638
                         throw new CompilationException($this, 'Assignments require the "if" plugin to be accessible');
1639 1639
                     }
1640 1640
 
1641
-                    $parts  = $this->mapParams($parts, array(Core::NAMESPACE_PLUGINS_BLOCKS . 'PluginIf', 'init'), 1);
1641
+                    $parts  = $this->mapParams($parts, array(Core::NAMESPACE_PLUGINS_BLOCKS.'PluginIf', 'init'), 1);
1642 1642
                     $tokens = $this->getParamTokens($parts);
1643 1643
                     $parts  = $this->getCompiledParams($parts);
1644 1644
 
@@ -1652,14 +1652,14 @@  discard block
 block discarded – undo
1652 1652
                 if ($this->autoEscape) {
1653 1653
                     $out = preg_replace('#\(is_string\(\$tmp=(.+?)\) \? htmlspecialchars\(\$tmp, ENT_QUOTES, \$this->charset\) : \$tmp\)#', '$1', $out);
1654 1654
                 }
1655
-                $out = self::PHP_OPEN . $echo . $out . $operator . implode(' ', $value) . self::PHP_CLOSE;
1655
+                $out = self::PHP_OPEN.$echo.$out.$operator.implode(' ', $value).self::PHP_CLOSE;
1656 1656
             } elseif ($curBlock === 'array' && is_array($parsingParams) && preg_match('#^(\s*=>?\s*)#', $substr, $match)) {
1657 1657
                 // parse namedparam with var as name (only for array)
1658 1658
                 if ($this->debug) {
1659
-                    echo 'VARIABLE NAMED PARAM (FOR ARRAY) FOUND' . "\n";
1659
+                    echo 'VARIABLE NAMED PARAM (FOR ARRAY) FOUND'."\n";
1660 1660
                 }
1661 1661
                 $len = strlen($match[1]);
1662
-                $var = $out[count($out) - 1];
1662
+                $var = $out[count($out)-1];
1663 1663
                 $pointer += $len;
1664 1664
 
1665 1665
                 $output = array($var[0], $this->parse($substr, $len, null, false, 'namedparam', $pointer));
@@ -1674,16 +1674,16 @@  discard block
 block discarded – undo
1674 1674
             // parse modifier on funcs or vars
1675 1675
             $srcPointer = $pointer;
1676 1676
             if (is_array($parsingParams)) {
1677
-                $tmp                     = $this->replaceModifiers(
1677
+                $tmp = $this->replaceModifiers(
1678 1678
                     array(
1679 1679
                     null,
1680 1680
                     null,
1681
-                    $out[count($out) - 1][0],
1681
+                    $out[count($out)-1][0],
1682 1682
                     $match[0]
1683 1683
                     ), $curBlock, $pointer
1684 1684
                 );
1685
-                $out[count($out) - 1][0] = $tmp;
1686
-                $out[count($out) - 1][1] .= substr($substr, $srcPointer, $srcPointer - $pointer);
1685
+                $out[count($out)-1][0] = $tmp;
1686
+                $out[count($out)-1][1] .= substr($substr, $srcPointer, $srcPointer-$pointer);
1687 1687
             } else {
1688 1688
                 $out = $this->replaceModifiers(array(null, null, $out, $match[0]), $curBlock, $pointer);
1689 1689
             }
@@ -1695,10 +1695,10 @@  discard block
 block discarded – undo
1695 1695
             $ptr = 0;
1696 1696
 
1697 1697
             if (is_array($parsingParams)) {
1698
-                $output = $this->parseMethodCall($out[count($out) - 1][1], $match[0], $curBlock, $ptr);
1698
+                $output = $this->parseMethodCall($out[count($out)-1][1], $match[0], $curBlock, $ptr);
1699 1699
 
1700
-                $out[count($out) - 1][0] = $output;
1701
-                $out[count($out) - 1][1] .= substr($match[0], 0, $ptr);
1700
+                $out[count($out)-1][0] = $output;
1701
+                $out[count($out)-1][1] .= substr($match[0], 0, $ptr);
1702 1702
             } else {
1703 1703
                 $out = $this->parseMethodCall($out, $match[0], $curBlock, $ptr);
1704 1704
             }
@@ -1707,7 +1707,7 @@  discard block
 block discarded – undo
1707 1707
         }
1708 1708
 
1709 1709
         if ($curBlock === 'root' && substr($out, 0, strlen(self::PHP_OPEN)) !== self::PHP_OPEN) {
1710
-            return self::PHP_OPEN . 'echo ' . $out . ';' . self::PHP_CLOSE;
1710
+            return self::PHP_OPEN.'echo '.$out.';'.self::PHP_CLOSE;
1711 1711
         } else {
1712 1712
             return $out;
1713 1713
         }
@@ -1733,11 +1733,11 @@  discard block
 block discarded – undo
1733 1733
     protected function parseFunction($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1734 1734
     {
1735 1735
         $output = '';
1736
-        $cmdstr = substr($in, $from, $to - $from);
1737
-        preg_match('/^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?)(\s*' . $this->rdr . '|\s*;)?/i', $cmdstr, $match);
1736
+        $cmdstr = substr($in, $from, $to-$from);
1737
+        preg_match('/^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?)(\s*'.$this->rdr.'|\s*;)?/i', $cmdstr, $match);
1738 1738
 
1739 1739
         if (empty($match[1])) {
1740
-            throw new CompilationException($this, 'Parse error, invalid function name : ' . substr($cmdstr, 0, 15));
1740
+            throw new CompilationException($this, 'Parse error, invalid function name : '.substr($cmdstr, 0, 15));
1741 1741
         }
1742 1742
 
1743 1743
         $func = $match[1];
@@ -1747,7 +1747,7 @@  discard block
 block discarded – undo
1747 1747
         }
1748 1748
 
1749 1749
         if ($this->debug) {
1750
-            echo 'FUNC FOUND (' . $func . ')' . "\n";
1750
+            echo 'FUNC FOUND ('.$func.')'."\n";
1751 1751
         }
1752 1752
 
1753 1753
         $paramsep = '';
@@ -1759,11 +1759,11 @@  discard block
 block discarded – undo
1759 1759
             $paramspos = $match[1][0][1];
1760 1760
             $paramsep  = substr($match[1][0][0], - 1) === '(' ? ')' : '';
1761 1761
             if ($paramsep === ')') {
1762
-                $paramspos += strlen($match[1][0][0]) - 1;
1762
+                $paramspos += strlen($match[1][0][0])-1;
1763 1763
                 if (substr($cmdstr, 0, 2) === 'if' || substr($cmdstr, 0, 6) === 'elseif') {
1764 1764
                     $paramsep = '';
1765 1765
                     if (strlen($match[1][0][0]) > 1) {
1766
-                        -- $paramspos;
1766
+                        --$paramspos;
1767 1767
                     }
1768 1768
                 }
1769 1769
             }
@@ -1788,8 +1788,8 @@  discard block
 block discarded – undo
1788 1788
                     return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1789 1789
                 }
1790 1790
             }
1791
-            $whitespace = strlen(substr($cmdstr, strlen($func), $paramspos - strlen($func)));
1792
-            $paramstr   = substr($cmdstr, $paramspos + 1);
1791
+            $whitespace = strlen(substr($cmdstr, strlen($func), $paramspos-strlen($func)));
1792
+            $paramstr   = substr($cmdstr, $paramspos+1);
1793 1793
             if (substr($paramstr, - 1, 1) === $paramsep) {
1794 1794
                 $paramstr = substr($paramstr, 0, - 1);
1795 1795
             }
@@ -1811,36 +1811,36 @@  discard block
 block discarded – undo
1811 1811
 
1812 1812
                             if ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === ')') {
1813 1813
                                 if ($this->debug) {
1814
-                                    echo 'PARAM PARSING ENDED, ")" FOUND, POINTER AT ' . $ptr . "\n";
1814
+                                    echo 'PARAM PARSING ENDED, ")" FOUND, POINTER AT '.$ptr."\n";
1815 1815
                                 }
1816 1816
                                 break 2;
1817 1817
                             } elseif ($paramstr[$ptr] === ';') {
1818
-                                ++ $ptr;
1818
+                                ++$ptr;
1819 1819
                                 if ($this->debug) {
1820
-                                    echo 'PARAM PARSING ENDED, ";" FOUND, POINTER AT ' . $ptr . "\n";
1820
+                                    echo 'PARAM PARSING ENDED, ";" FOUND, POINTER AT '.$ptr."\n";
1821 1821
                                 }
1822 1822
                                 break 2;
1823 1823
                             } elseif ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === '/') {
1824 1824
                                 if ($this->debug) {
1825
-                                    echo 'PARAM PARSING ENDED, "/" FOUND, POINTER AT ' . $ptr . "\n";
1825
+                                    echo 'PARAM PARSING ENDED, "/" FOUND, POINTER AT '.$ptr."\n";
1826 1826
                                 }
1827 1827
                                 break 2;
1828 1828
                             } elseif (substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
1829 1829
                                 if ($this->debug) {
1830
-                                    echo 'PARAM PARSING ENDED, RIGHT DELIMITER FOUND, POINTER AT ' . $ptr . "\n";
1830
+                                    echo 'PARAM PARSING ENDED, RIGHT DELIMITER FOUND, POINTER AT '.$ptr."\n";
1831 1831
                                 }
1832 1832
                                 break 2;
1833 1833
                             }
1834 1834
 
1835 1835
                             if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === ',' || $paramstr[$ptr] === "\r" || $paramstr[$ptr] === "\n" || $paramstr[$ptr] === "\t") {
1836
-                                ++ $ptr;
1836
+                                ++$ptr;
1837 1837
                             } else {
1838 1838
                                 break;
1839 1839
                             }
1840 1840
                         }
1841 1841
 
1842 1842
                         if ($this->debug) {
1843
-                            echo 'FUNC START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
1843
+                            echo 'FUNC START PARAM PARSING WITH POINTER AT '.$ptr."\n";
1844 1844
                         }
1845 1845
 
1846 1846
                         if ($func === 'if' || $func === 'elseif' || $func === 'tif') {
@@ -1852,7 +1852,7 @@  discard block
 block discarded – undo
1852 1852
                         }
1853 1853
 
1854 1854
                         if ($this->debug) {
1855
-                            echo 'PARAM PARSED, POINTER AT ' . $ptr . ' (' . substr($paramstr, $ptr - 1, 3) . ')' . "\n";
1855
+                            echo 'PARAM PARSED, POINTER AT '.$ptr.' ('.substr($paramstr, $ptr-1, 3).')'."\n";
1856 1856
                         }
1857 1857
                     }
1858 1858
                 }
@@ -1876,16 +1876,16 @@  discard block
 block discarded – undo
1876 1876
         }
1877 1877
 
1878 1878
         if ($pointer !== null) {
1879
-            $pointer += (isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func) + (isset($whitespace) ? $whitespace : 0);
1879
+            $pointer += (isset($paramstr) ? strlen($paramstr) : 0)+(')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1))+strlen($func)+(isset($whitespace) ? $whitespace : 0);
1880 1880
             if ($this->debug) {
1881
-                echo 'FUNC ADDS ' . ((isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func)) . ' TO POINTER' . "\n";
1881
+                echo 'FUNC ADDS '.((isset($paramstr) ? strlen($paramstr) : 0)+(')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1))+strlen($func)).' TO POINTER'."\n";
1882 1882
             }
1883 1883
         }
1884 1884
 
1885 1885
         if ($curBlock === 'method' || $func === 'do' || strstr($func, '::') !== false) {
1886 1886
             // handle static method calls with security policy
1887 1887
             if (strstr($func, '::') !== false && $this->securityPolicy !== null && $this->securityPolicy->isMethodAllowed(explode('::', strtolower($func))) !== true) {
1888
-                throw new SecurityException('Call to a disallowed php function : ' . $func);
1888
+                throw new SecurityException('Call to a disallowed php function : '.$func);
1889 1889
             }
1890 1890
             $pluginType = Core::NATIVE_PLUGIN;
1891 1891
         } else {
@@ -1930,19 +1930,19 @@  discard block
 block discarded – undo
1930 1930
                     $this->customPlugins[$func]['function']
1931 1931
                 ), $state);
1932 1932
             } else {
1933
-                if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
1933
+                if (class_exists('Plugin'.Core::toCamelCase($func)) !== false) {
1934 1934
                     $params = $this->mapParams($params, array(
1935
-                        'Plugin' . Core::toCamelCase($func),
1935
+                        'Plugin'.Core::toCamelCase($func),
1936 1936
                         ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1937 1937
                     ), $state);
1938
-                } elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !== false) {
1938
+                } elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func)) !== false) {
1939 1939
                     $params = $this->mapParams($params, array(
1940
-                        Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func),
1940
+                        Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func),
1941 1941
                         ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1942 1942
                     ), $state);
1943 1943
                 } else {
1944 1944
                     $params = $this->mapParams($params, array(
1945
-                        Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
1945
+                        Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func),
1946 1946
                         ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1947 1947
                     ), $state);
1948 1948
                 }
@@ -1953,24 +1953,22 @@  discard block
 block discarded – undo
1953 1953
                 $params = $this->mapParams($params, $this->customPlugins[$func]['callback'], $state);
1954 1954
             } else {
1955 1955
                 // Custom plugin
1956
-                if (function_exists('Plugin' . Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ?
1956
+                if (function_exists('Plugin'.Core::toCamelCase($func).(($pluginType & Core::COMPILABLE_PLUGIN) ?
1957 1957
                         'Compile' : '')) !== false) {
1958
-                    $params = $this->mapParams($params, 'Plugin' . Core::toCamelCase($func) . (($pluginType &
1958
+                    $params = $this->mapParams($params, 'Plugin'.Core::toCamelCase($func).(($pluginType &
1959 1959
                             Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1960 1960
                 } // Builtin helper plugin
1961
-                elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . (
1961
+                elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func).(
1962 1962
                     ($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '')) !== false) {
1963
-                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase
1964
-                        ($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1963
+                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func).(($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1965 1964
                 } // Builtin function plugin
1966 1965
                 else {
1967
-                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase
1968
-                        ($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1966
+                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func).(($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1969 1967
                 }
1970 1968
             }
1971 1969
         } // Smarty modifier
1972 1970
         elseif ($pluginType & Core::SMARTY_MODIFIER) {
1973
-            $output = 'smarty_modifier_' . $func . '(' . implode(', ', $params) . ')';
1971
+            $output = 'smarty_modifier_'.$func.'('.implode(', ', $params).')';
1974 1972
         } // Proxy plugin
1975 1973
         elseif ($pluginType & Core::PROXY_PLUGIN) {
1976 1974
             $params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state);
@@ -2010,19 +2008,19 @@  discard block
 block discarded – undo
2010 2008
             if ($func === 'do') {
2011 2009
                 $output = '';
2012 2010
                 if (isset($params['*'])) {
2013
-                    $output = implode(';', $params['*']) . ';';
2011
+                    $output = implode(';', $params['*']).';';
2014 2012
                 }
2015 2013
 
2016 2014
                 if (is_array($parsingParams) || $curBlock !== 'root') {
2017 2015
                     throw new CompilationException($this, 'Do can not be used inside another function or block');
2018 2016
                 }
2019 2017
 
2020
-                return self::PHP_OPEN . $output . self::PHP_CLOSE;
2018
+                return self::PHP_OPEN.$output.self::PHP_CLOSE;
2021 2019
             } else {
2022 2020
                 if (isset($params['*'])) {
2023
-                    $output = $func . '(' . implode(', ', $params['*']) . ')';
2021
+                    $output = $func.'('.implode(', ', $params['*']).')';
2024 2022
                 } else {
2025
-                    $output = $func . '()';
2023
+                    $output = $func.'()';
2026 2024
                 }
2027 2025
             }
2028 2026
         } // Block class OR Function class
@@ -2032,7 +2030,7 @@  discard block
 block discarded – undo
2032 2030
                     $callback = $this->customPlugins[$func]['callback'];
2033 2031
                     if (!is_array($callback)) {
2034 2032
                         if (!method_exists($callback, 'compile')) {
2035
-                            throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
2033
+                            throw new Exception('Custom plugin '.$func.' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
2036 2034
                         }
2037 2035
                         if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
2038 2036
                             $funcCompiler = array($callback, 'compile');
@@ -2043,13 +2041,13 @@  discard block
 block discarded – undo
2043 2041
                         $funcCompiler = $callback;
2044 2042
                     }
2045 2043
                 } else {
2046
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2047
-                        $funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
2048
-                    } elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !== false) {
2049
-                        $funcCompiler = array(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func), 'compile');
2044
+                    if (class_exists('Plugin'.Core::toCamelCase($func)) !== false) {
2045
+                        $funcCompiler = array('Plugin'.Core::toCamelCase($func), 'compile');
2046
+                    } elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func)) !== false) {
2047
+                        $funcCompiler = array(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func), 'compile');
2050 2048
                     } else {
2051 2049
                         $funcCompiler = array(
2052
-                            Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
2050
+                            Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func),
2053 2051
                             'compile'
2054 2052
                         );
2055 2053
                     }
@@ -2066,31 +2064,31 @@  discard block
 block discarded – undo
2066 2064
                     $callback = $this->customPlugins[$func]['callback'];
2067 2065
                     if (!is_array($callback)) {
2068 2066
                         if (!method_exists($callback, 'process')) {
2069
-                            throw new Exception('Custom plugin ' . $func . ' must implement the "process" method to be usable, or you should provide a full callback to the method to use');
2067
+                            throw new Exception('Custom plugin '.$func.' must implement the "process" method to be usable, or you should provide a full callback to the method to use');
2070 2068
                         }
2071 2069
                         if (($ref = new ReflectionMethod($callback, 'process')) && $ref->isStatic()) {
2072
-                            $output = 'call_user_func(array(\'' . $callback . '\', \'process\'), ' . $params . ')';
2070
+                            $output = 'call_user_func(array(\''.$callback.'\', \'process\'), '.$params.')';
2073 2071
                         } else {
2074
-                            $output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback . '\'), \'process\'), ' . $params . ')';
2072
+                            $output = 'call_user_func(array($this->getObjectPlugin(\''.$callback.'\'), \'process\'), '.$params.')';
2075 2073
                         }
2076 2074
                     } elseif (is_object($callback[0])) {
2077
-                        $output = 'call_user_func(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), ' . $params . ')';
2075
+                        $output = 'call_user_func(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), '.$params.')';
2078 2076
                     } elseif (($ref = new ReflectionMethod($callback[0], $callback[1])) && $ref->isStatic()) {
2079
-                        $output = 'call_user_func(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), ' . $params . ')';
2077
+                        $output = 'call_user_func(array(\''.$callback[0].'\', \''.$callback[1].'\'), '.$params.')';
2080 2078
                     } else {
2081
-                        $output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback[0] . '\'), \'' . $callback[1] . '\'), ' . $params . ')';
2079
+                        $output = 'call_user_func(array($this->getObjectPlugin(\''.$callback[0].'\'), \''.$callback[1].'\'), '.$params.')';
2082 2080
                     }
2083 2081
                     if (empty($params)) {
2084
-                        $output = substr($output, 0, - 3) . ')';
2082
+                        $output = substr($output, 0, - 3).')';
2085 2083
                     }
2086 2084
                 } else {
2087
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2088
-                        $output = '$this->classCall(\'Plugin' . $func . '\', array(' . $params . '))';
2089
-                    } elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !== false) {
2090
-                        $output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\', 
2091
-                        array(' . $params . '))';
2085
+                    if (class_exists('Plugin'.Core::toCamelCase($func)) !== false) {
2086
+                        $output = '$this->classCall(\'Plugin'.$func.'\', array('.$params.'))';
2087
+                    } elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func)) !== false) {
2088
+                        $output = '$this->classCall(\''.Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.$func.'\', 
2089
+                        array(' . $params.'))';
2092 2090
                     } else {
2093
-                        $output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
2091
+                        $output = '$this->classCall(\''.$func.'\', array('.$params.'))';
2094 2092
                     }
2095 2093
                 }
2096 2094
             }
@@ -2101,15 +2099,15 @@  discard block
 block discarded – undo
2101 2099
                     $funcCompiler = $this->customPlugins[$func]['callback'];
2102 2100
                 } else {
2103 2101
                     // Custom plugin
2104
-                    if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2105
-                        $funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
2102
+                    if (function_exists('Plugin'.Core::toCamelCase($func).'Compile') !== false) {
2103
+                        $funcCompiler = 'Plugin'.Core::toCamelCase($func).'Compile';
2106 2104
                     } // Builtin helper plugin
2107
-                    elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2108
-                        $funcCompiler = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) .
2105
+                    elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func).'Compile') !== false) {
2106
+                        $funcCompiler = Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func).
2109 2107
                             'Compile';
2110 2108
                     } // Builtin function plugin
2111 2109
                     else {
2112
-                        $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
2110
+                        $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func).
2113 2111
                             'Compile';
2114 2112
                     }
2115 2113
                 }
@@ -2125,24 +2123,24 @@  discard block
 block discarded – undo
2125 2123
                 if ($pluginType & Core::CUSTOM_PLUGIN) {
2126 2124
                     $callback = $this->customPlugins[$func]['callback'];
2127 2125
                     if ($callback instanceof Closure) {
2128
-                        $output = 'call_user_func($this->getCustomPlugin(\'' . $func . '\'), ' . $params . ')';
2126
+                        $output = 'call_user_func($this->getCustomPlugin(\''.$func.'\'), '.$params.')';
2129 2127
                     } else {
2130
-                        $output = 'call_user_func(\'' . $callback . '\', ' . $params . ')';
2128
+                        $output = 'call_user_func(\''.$callback.'\', '.$params.')';
2131 2129
                     }
2132 2130
                 } else {
2133 2131
                     // Custom plugin
2134
-                    if (function_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2135
-                        $output = 'Plugin' . Core::toCamelCase($func) . '(' . $params .
2132
+                    if (function_exists('Plugin'.Core::toCamelCase($func)) !== false) {
2133
+                        $output = 'Plugin'.Core::toCamelCase($func).'('.$params.
2136 2134
                             ')';
2137 2135
                     } // Builtin helper plugin
2138
-                    elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !==
2136
+                    elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func)) !==
2139 2137
                         false) {
2140
-                        $output = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . '(' .
2141
-                            $params . ')';
2138
+                        $output = Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func).'('.
2139
+                            $params.')';
2142 2140
                     } // Builtin function plugin
2143 2141
                     else {
2144
-                        $output = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '(' .
2145
-                            $params . ')';
2142
+                        $output = Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func).'('.
2143
+                            $params.')';
2146 2144
                     }
2147 2145
                 }
2148 2146
             }
@@ -2160,22 +2158,22 @@  discard block
 block discarded – undo
2160 2158
                 $callback = $this->customPlugins[$func]['callback'];
2161 2159
                 if (is_array($callback)) {
2162 2160
                     if (is_object($callback[0])) {
2163
-                        $output = 'call_user_func_array(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2161
+                        $output = 'call_user_func_array(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), array(array('.$params.'), $this))';
2164 2162
                     } else {
2165
-                        $output = 'call_user_func_array(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2163
+                        $output = 'call_user_func_array(array(\''.$callback[0].'\', \''.$callback[1].'\'), array(array('.$params.'), $this))';
2166 2164
                     }
2167 2165
                 } else {
2168
-                    $output = $callback . '(array(' . $params . '), $this)';
2166
+                    $output = $callback.'(array('.$params.'), $this)';
2169 2167
                 }
2170 2168
             } else {
2171
-                $output = 'smarty_function_' . $func . '(array(' . $params . '), $this)';
2169
+                $output = 'smarty_function_'.$func.'(array('.$params.'), $this)';
2172 2170
             }
2173 2171
         } // Template plugin
2174 2172
         elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
2175 2173
             array_unshift($params, '$this');
2176 2174
             $params                                 = self::implode_r($params);
2177
-            $output                                 = 'Plugin' . Core::toCamelCase($func) .
2178
-                $this->templatePlugins[$func]['uuid'] . '(' . $params . ')';
2175
+            $output                                 = 'Plugin'.Core::toCamelCase($func).
2176
+                $this->templatePlugins[$func]['uuid'].'('.$params.')';
2179 2177
             $this->templatePlugins[$func]['called'] = true;
2180 2178
         }
2181 2179
 
@@ -2207,29 +2205,29 @@  discard block
 block discarded – undo
2207 2205
      */
2208 2206
     protected function parseString($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2209 2207
     {
2210
-        $substr = substr($in, $from, $to - $from);
2208
+        $substr = substr($in, $from, $to-$from);
2211 2209
         $first  = $substr[0];
2212 2210
 
2213 2211
         if ($this->debug) {
2214
-            echo 'STRING FOUND (in ' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . ')' . "\n";
2212
+            echo 'STRING FOUND (in '.htmlentities(substr($in, $from, min($to-$from, 50))).(($to-$from) > 50 ? '...' : '').')'."\n";
2215 2213
         }
2216 2214
         $strend = false;
2217
-        $o      = $from + 1;
2215
+        $o      = $from+1;
2218 2216
         while ($strend === false) {
2219 2217
             $strend = strpos($in, $first, $o);
2220 2218
             if ($strend === false) {
2221
-                throw new CompilationException($this, 'Unfinished string, started with ' . substr($in, $from, $to - $from));
2219
+                throw new CompilationException($this, 'Unfinished string, started with '.substr($in, $from, $to-$from));
2222 2220
             }
2223
-            if (substr($in, $strend - 1, 1) === '\\') {
2224
-                $o      = $strend + 1;
2221
+            if (substr($in, $strend-1, 1) === '\\') {
2222
+                $o      = $strend+1;
2225 2223
                 $strend = false;
2226 2224
             }
2227 2225
         }
2228 2226
         if ($this->debug) {
2229
-            echo 'STRING DELIMITED: ' . substr($in, $from, $strend + 1 - $from) . "\n";
2227
+            echo 'STRING DELIMITED: '.substr($in, $from, $strend+1-$from)."\n";
2230 2228
         }
2231 2229
 
2232
-        $srcOutput = substr($in, $from, $strend + 1 - $from);
2230
+        $srcOutput = substr($in, $from, $strend+1-$from);
2233 2231
 
2234 2232
         if ($pointer !== null) {
2235 2233
             $pointer += strlen($srcOutput);
@@ -2238,13 +2236,13 @@  discard block
 block discarded – undo
2238 2236
         $output = $this->replaceStringVars($srcOutput, $first);
2239 2237
 
2240 2238
         // handle modifiers
2241
-        if ($curBlock !== 'modifier' && preg_match('#^((?:\|(?:@?[a-z0-9_]+(?::.*)*))+)#i', substr($substr, $strend + 1 - $from), $match)) {
2239
+        if ($curBlock !== 'modifier' && preg_match('#^((?:\|(?:@?[a-z0-9_]+(?::.*)*))+)#i', substr($substr, $strend+1-$from), $match)) {
2242 2240
             $modstr = $match[1];
2243 2241
 
2244 2242
             if ($curBlock === 'root' && substr($modstr, - 1) === '}') {
2245 2243
                 $modstr = substr($modstr, 0, - 1);
2246 2244
             }
2247
-            $modstr = str_replace('\\' . $first, $first, $modstr);
2245
+            $modstr = str_replace('\\'.$first, $first, $modstr);
2248 2246
             $ptr    = 0;
2249 2247
             $output = $this->replaceModifiers(array(null, null, $output, $modstr), 'string', $ptr);
2250 2248
 
@@ -2252,7 +2250,7 @@  discard block
 block discarded – undo
2252 2250
             if ($pointer !== null) {
2253 2251
                 $pointer += $ptr;
2254 2252
             }
2255
-            $srcOutput .= substr($substr, $strend + 1 - $from, $ptr);
2253
+            $srcOutput .= substr($substr, $strend+1-$from, $ptr);
2256 2254
         }
2257 2255
 
2258 2256
         if (is_array($parsingParams)) {
@@ -2283,10 +2281,10 @@  discard block
 block discarded – undo
2283 2281
      */
2284 2282
     protected function parseConst($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2285 2283
     {
2286
-        $substr = substr($in, $from, $to - $from);
2284
+        $substr = substr($in, $from, $to-$from);
2287 2285
 
2288 2286
         if ($this->debug) {
2289
-            echo 'CONST FOUND : ' . $substr . "\n";
2287
+            echo 'CONST FOUND : '.$substr."\n";
2290 2288
         }
2291 2289
 
2292 2290
         if (!preg_match('#^%([\\\\a-z0-9_:]+)#i', $substr, $m)) {
@@ -2325,7 +2323,7 @@  discard block
 block discarded – undo
2325 2323
         }
2326 2324
 
2327 2325
         if ($curBlock !== 'root') {
2328
-            $output = '(defined("' . $key . '") ? ' . $key . ' : null)';
2326
+            $output = '(defined("'.$key.'") ? '.$key.' : null)';
2329 2327
         } else {
2330 2328
             $output = $key;
2331 2329
         }
@@ -2350,7 +2348,7 @@  discard block
 block discarded – undo
2350 2348
      */
2351 2349
     protected function parseVar($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2352 2350
     {
2353
-        $substr = substr($in, $from, $to - $from);
2351
+        $substr = substr($in, $from, $to-$from);
2354 2352
 
2355 2353
         // var key
2356 2354
         $varRegex = '(\\$?\\.?[a-z0-9\\\\_:]*(?:(?:(?:\\.|->)(?:[a-z0-9\\\\_:]+|(?R))|\\[(?:[a-z0-9\\\\_:]+|(?R)|(["\'])[^\\2]*?\\2)\\]))*)';
@@ -2378,13 +2376,13 @@  discard block
 block discarded – undo
2378 2376
 
2379 2377
             if (substr($key, - 1) == '.') {
2380 2378
                 $key = substr($key, 0, - 1);
2381
-                -- $matchedLength;
2379
+                --$matchedLength;
2382 2380
             }
2383 2381
 
2384 2382
             if ($hasMethodCall) {
2385
-                $matchedLength -= strlen($match[3]) + strlen(substr($match[1], strrpos($match[1], '->')));
2386
-                $key        = substr($match[1], 1, strrpos($match[1], '->') - 1);
2387
-                $methodCall = substr($match[1], strrpos($match[1], '->')) . $match[3];
2383
+                $matchedLength -= strlen($match[3])+strlen(substr($match[1], strrpos($match[1], '->')));
2384
+                $key        = substr($match[1], 1, strrpos($match[1], '->')-1);
2385
+                $methodCall = substr($match[1], strrpos($match[1], '->')).$match[3];
2388 2386
             }
2389 2387
 
2390 2388
             if ($hasModifiers) {
@@ -2400,9 +2398,9 @@  discard block
 block discarded – undo
2400 2398
 
2401 2399
             if ($this->debug) {
2402 2400
                 if ($hasMethodCall) {
2403
-                    echo 'METHOD CALL FOUND : $' . $key . substr($methodCall, 0, 30) . "\n";
2401
+                    echo 'METHOD CALL FOUND : $'.$key.substr($methodCall, 0, 30)."\n";
2404 2402
                 } else {
2405
-                    echo 'VAR FOUND : $' . $key . "\n";
2403
+                    echo 'VAR FOUND : $'.$key."\n";
2406 2404
                 }
2407 2405
             }
2408 2406
 
@@ -2413,7 +2411,7 @@  discard block
 block discarded – undo
2413 2411
                 $uid           = 0;
2414 2412
                 $parsed        = array($uid => '');
2415 2413
                 $current       = &$parsed;
2416
-                $curTxt        = &$parsed[$uid ++];
2414
+                $curTxt        = &$parsed[$uid++];
2417 2415
                 $tree          = array();
2418 2416
                 $chars         = str_split($key, 1);
2419 2417
                 $inSplittedVar = false;
@@ -2422,33 +2420,33 @@  discard block
 block discarded – undo
2422 2420
                 while (($char = array_shift($chars)) !== null) {
2423 2421
                     if ($char === '[') {
2424 2422
                         if (count($tree) > 0) {
2425
-                            ++ $bracketCount;
2423
+                            ++$bracketCount;
2426 2424
                         } else {
2427 2425
                             $tree[]        = &$current;
2428
-                            $current[$uid] = array($uid + 1 => '');
2429
-                            $current       = &$current[$uid ++];
2430
-                            $curTxt        = &$current[$uid ++];
2426
+                            $current[$uid] = array($uid+1 => '');
2427
+                            $current       = &$current[$uid++];
2428
+                            $curTxt        = &$current[$uid++];
2431 2429
                             continue;
2432 2430
                         }
2433 2431
                     } elseif ($char === ']') {
2434 2432
                         if ($bracketCount > 0) {
2435
-                            -- $bracketCount;
2433
+                            --$bracketCount;
2436 2434
                         } else {
2437
-                            $current = &$tree[count($tree) - 1];
2435
+                            $current = &$tree[count($tree)-1];
2438 2436
                             array_pop($tree);
2439 2437
                             if (current($chars) !== '[' && current($chars) !== false && current($chars) !== ']') {
2440 2438
                                 $current[$uid] = '';
2441
-                                $curTxt        = &$current[$uid ++];
2439
+                                $curTxt        = &$current[$uid++];
2442 2440
                             }
2443 2441
                             continue;
2444 2442
                         }
2445 2443
                     } elseif ($char === '$') {
2446 2444
                         if (count($tree) == 0) {
2447
-                            $curTxt        = &$current[$uid ++];
2445
+                            $curTxt        = &$current[$uid++];
2448 2446
                             $inSplittedVar = true;
2449 2447
                         }
2450 2448
                     } elseif (($char === '.' || $char === '-') && count($tree) == 0 && $inSplittedVar) {
2451
-                        $curTxt        = &$current[$uid ++];
2449
+                        $curTxt        = &$current[$uid++];
2452 2450
                         $inSplittedVar = false;
2453 2451
                     }
2454 2452
 
@@ -2457,16 +2455,16 @@  discard block
 block discarded – undo
2457 2455
                 unset($uid, $current, $curTxt, $tree, $chars);
2458 2456
 
2459 2457
                 if ($this->debug) {
2460
-                    echo 'RECURSIVE VAR REPLACEMENT : ' . $key . "\n";
2458
+                    echo 'RECURSIVE VAR REPLACEMENT : '.$key."\n";
2461 2459
                 }
2462 2460
 
2463 2461
                 $key = $this->flattenVarTree($parsed);
2464 2462
 
2465 2463
                 if ($this->debug) {
2466
-                    echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2464
+                    echo 'RECURSIVE VAR REPLACEMENT DONE : '.$key."\n";
2467 2465
                 }
2468 2466
 
2469
-                $output = preg_replace('#(^""\.|""\.|\.""$|(\()""\.|\.""(\)))#', '$2$3', '$this->readVar("' . $key . '")');
2467
+                $output = preg_replace('#(^""\.|""\.|\.""$|(\()""\.|\.""(\)))#', '$2$3', '$this->readVar("'.$key.'")');
2470 2468
             } else {
2471 2469
                 $output = $this->parseVarKey($key, $hasModifiers ? 'modifier' : $curBlock);
2472 2470
             }
@@ -2491,10 +2489,10 @@  discard block
 block discarded – undo
2491 2489
                     if (substr($expMatch[2][$k], 0, 1) === '=') {
2492 2490
                         $assign = true;
2493 2491
                         if ($operator === '=') {
2494
-                            throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, can not use "==" in expressions');
2492
+                            throw new CompilationException($this, 'Invalid expression <em>'.$substr.'</em>, can not use "==" in expressions');
2495 2493
                         }
2496 2494
                         if ($curBlock !== 'root') {
2497
-                            throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, assignments can only be used in top level expressions like {$foo+=3} or {$foo="bar"}');
2495
+                            throw new CompilationException($this, 'Invalid expression <em>'.$substr.'</em>, assignments can only be used in top level expressions like {$foo+=3} or {$foo="bar"}');
2498 2496
                         }
2499 2497
                         $operator .= '=';
2500 2498
                         $expMatch[2][$k] = substr($expMatch[2][$k], 1);
@@ -2505,22 +2503,22 @@  discard block
 block discarded – undo
2505 2503
                         $expMatch[2][$k] = substr($expMatch[2][$k], 1);
2506 2504
                     }
2507 2505
                     if (($operator === '+' || $operator === '-') && $expMatch[2][$k] === $operator) {
2508
-                        $output = '(' . $output . $operator . $operator . ')';
2506
+                        $output = '('.$output.$operator.$operator.')';
2509 2507
                         break;
2510 2508
                     } elseif (substr($expMatch[2][$k], 0, 1) === '$') {
2511
-                        $output = '(' . $output . ' ' . $operator . ' ' . $this->parseVar($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2509
+                        $output = '('.$output.' '.$operator.' '.$this->parseVar($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression').')';
2512 2510
                     } elseif (substr($expMatch[2][$k], 0, 1) === '%') {
2513
-                        $output = '(' . $output . ' ' . $operator . ' ' . $this->parseConst($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2511
+                        $output = '('.$output.' '.$operator.' '.$this->parseConst($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression').')';
2514 2512
                     } elseif (!empty($expMatch[2][$k])) {
2515
-                        $output = '(' . $output . ' ' . $operator . ' ' . str_replace(',', '.', $expMatch[2][$k]) . ')';
2513
+                        $output = '('.$output.' '.$operator.' '.str_replace(',', '.', $expMatch[2][$k]).')';
2516 2514
                     } else {
2517
-                        throw new CompilationException($this, 'Unfinished expression <em>' . $substr . '</em>, missing var or number after math operator');
2515
+                        throw new CompilationException($this, 'Unfinished expression <em>'.$substr.'</em>, missing var or number after math operator');
2518 2516
                     }
2519 2517
                 }
2520 2518
             }
2521 2519
 
2522 2520
             if ($this->autoEscape === true && $curBlock !== 'condition') {
2523
-                $output = '(is_string($tmp=' . $output . ') ? htmlspecialchars($tmp, ENT_QUOTES, $this->charset) : $tmp)';
2521
+                $output = '(is_string($tmp='.$output.') ? htmlspecialchars($tmp, ENT_QUOTES, $this->charset) : $tmp)';
2524 2522
             }
2525 2523
 
2526 2524
             // handle modifiers
@@ -2544,7 +2542,7 @@  discard block
 block discarded – undo
2544 2542
             } elseif ($curBlock === 'expression' || $curBlock === 'variable') {
2545 2543
                 return $output;
2546 2544
             } elseif (isset($assign)) {
2547
-                return self::PHP_OPEN . $output . ';' . self::PHP_CLOSE;
2545
+                return self::PHP_OPEN.$output.';'.self::PHP_CLOSE;
2548 2546
             } else {
2549 2547
                 return $output;
2550 2548
             }
@@ -2552,7 +2550,7 @@  discard block
 block discarded – undo
2552 2550
             if ($curBlock === 'string' || $curBlock === 'delimited_string') {
2553 2551
                 return array(0, '');
2554 2552
             } else {
2555
-                throw new CompilationException($this, 'Invalid variable name <em>' . $substr . '</em>');
2553
+                throw new CompilationException($this, 'Invalid variable name <em>'.$substr.'</em>');
2556 2554
             }
2557 2555
         }
2558 2556
     }
@@ -2607,16 +2605,16 @@  discard block
 block discarded – undo
2607 2605
             if (empty($methMatch[2])) {
2608 2606
                 // property
2609 2607
                 if ($curBlock === 'root') {
2610
-                    $output .= '->' . $methMatch[1];
2608
+                    $output .= '->'.$methMatch[1];
2611 2609
                 } else {
2612
-                    $output = '(($tmp = ' . $output . ') ? $tmp->' . $methMatch[1] . ' : null)';
2610
+                    $output = '(($tmp = '.$output.') ? $tmp->'.$methMatch[1].' : null)';
2613 2611
                 }
2614 2612
                 $ptr += strlen($methMatch[1]);
2615 2613
             } else {
2616 2614
                 // method
2617 2615
                 if (substr($methMatch[2], 0, 2) === '()') {
2618
-                    $parsedCall = $methMatch[1] . '()';
2619
-                    $ptr += strlen($methMatch[1]) + 2;
2616
+                    $parsedCall = $methMatch[1].'()';
2617
+                    $ptr += strlen($methMatch[1])+2;
2620 2618
                 } else {
2621 2619
                     $parsedCall = $this->parseFunction($methodCall, $ptr, strlen($methodCall), false, 'method', $ptr);
2622 2620
                 }
@@ -2625,15 +2623,15 @@  discard block
 block discarded – undo
2625 2623
                     $method = strtolower(substr($parsedCall, 0, $argPos));
2626 2624
                     $args   = substr($parsedCall, $argPos);
2627 2625
                     if ($curBlock === 'root') {
2628
-                        $output = '$this->getSecurityPolicy()->callMethod($this, ' . $output . ', ' . var_export($method, true) . ', array' . $args . ')';
2626
+                        $output = '$this->getSecurityPolicy()->callMethod($this, '.$output.', '.var_export($method, true).', array'.$args.')';
2629 2627
                     } else {
2630
-                        $output = '(($tmp = ' . $output . ') ? $this->getSecurityPolicy()->callMethod($this, $tmp, ' . var_export($method, true) . ', array' . $args . ') : null)';
2628
+                        $output = '(($tmp = '.$output.') ? $this->getSecurityPolicy()->callMethod($this, $tmp, '.var_export($method, true).', array'.$args.') : null)';
2631 2629
                     }
2632 2630
                 } else {
2633 2631
                     if ($curBlock === 'root') {
2634
-                        $output .= '->' . $parsedCall;
2632
+                        $output .= '->'.$parsedCall;
2635 2633
                     } else {
2636
-                        $output = '(($tmp = ' . $output . ') ? $tmp->' . $parsedCall . ' : null)';
2634
+                        $output = '(($tmp = '.$output.') ? $tmp->'.$parsedCall.' : null)';
2637 2635
                     }
2638 2636
                 }
2639 2637
             }
@@ -2659,21 +2657,21 @@  discard block
 block discarded – undo
2659 2657
             return '$this->scope';
2660 2658
         }
2661 2659
         if (substr($key, 0, 1) === '.') {
2662
-            $key = 'dwoo' . $key;
2660
+            $key = 'dwoo'.$key;
2663 2661
         }
2664 2662
         if (preg_match('#dwoo\.(get|post|server|cookies|session|env|request)((?:\.[a-z0-9_-]+)+)#i', $key, $m)) {
2665 2663
             $global = strtoupper($m[1]);
2666 2664
             if ($global === 'COOKIES') {
2667 2665
                 $global = 'COOKIE';
2668 2666
             }
2669
-            $key = '$_' . $global;
2667
+            $key = '$_'.$global;
2670 2668
             foreach (explode('.', ltrim($m[2], '.')) as $part) {
2671
-                $key .= '[' . var_export($part, true) . ']';
2669
+                $key .= '['.var_export($part, true).']';
2672 2670
             }
2673 2671
             if ($curBlock === 'root') {
2674 2672
                 $output = $key;
2675 2673
             } else {
2676
-                $output = '(isset(' . $key . ')?' . $key . ':null)';
2674
+                $output = '(isset('.$key.')?'.$key.':null)';
2677 2675
             }
2678 2676
         } elseif (preg_match('#dwoo\\.const\\.([a-z0-9\\\\_:]+)#i', $key, $m)) {
2679 2677
             return $this->parseConstKey($m[1], $curBlock);
@@ -2689,9 +2687,9 @@  discard block
 block discarded – undo
2689 2687
                     $output = '$tmp_key';
2690 2688
                 } else {
2691 2689
                     if ($curBlock === 'root') {
2692
-                        $output = '$this->scope["' . $key . '"]';
2690
+                        $output = '$this->scope["'.$key.'"]';
2693 2691
                     } else {
2694
-                        $output = '(isset($this->scope["' . $key . '"]) ? $this->scope["' . $key . '"] : null)';
2692
+                        $output = '(isset($this->scope["'.$key.'"]) ? $this->scope["'.$key.'"] : null)';
2695 2693
                     }
2696 2694
                 }
2697 2695
             } else {
@@ -2702,7 +2700,7 @@  discard block
 block discarded – undo
2702 2700
                     $parentCnt = 0;
2703 2701
 
2704 2702
                     while (true) {
2705
-                        ++ $parentCnt;
2703
+                        ++$parentCnt;
2706 2704
                         array_shift($m[2]);
2707 2705
                         array_shift($m[1]);
2708 2706
                         if (current($m[2]) === '_parent') {
@@ -2711,7 +2709,7 @@  discard block
 block discarded – undo
2711 2709
                         break;
2712 2710
                     }
2713 2711
 
2714
-                    $output = '$this->readParentVar(' . $parentCnt . ')';
2712
+                    $output = '$this->readParentVar('.$parentCnt.')';
2715 2713
                 } else {
2716 2714
                     if ($i === 'dwoo') {
2717 2715
                         $output = '$this->globals';
@@ -2730,28 +2728,28 @@  discard block
 block discarded – undo
2730 2728
                     while (count($m[1]) && $m[1][0] !== '->') {
2731 2729
                         $m[2][0] = preg_replace('/(^\\\([\'"])|\\\([\'"])$)/x', '$2$3', $m[2][0]);
2732 2730
                         if (substr($m[2][0], 0, 1) == '"' || substr($m[2][0], 0, 1) == "'") {
2733
-                            $output .= '[' . $m[2][0] . ']';
2731
+                            $output .= '['.$m[2][0].']';
2734 2732
                         } else {
2735
-                            $output .= '["' . $m[2][0] . '"]';
2733
+                            $output .= '["'.$m[2][0].'"]';
2736 2734
                         }
2737 2735
                         array_shift($m[2]);
2738 2736
                         array_shift($m[1]);
2739 2737
                     }
2740 2738
 
2741 2739
                     if ($curBlock !== 'root') {
2742
-                        $output = '(isset(' . $output . ') ? ' . $output . ':null)';
2740
+                        $output = '(isset('.$output.') ? '.$output.':null)';
2743 2741
                     }
2744 2742
                 }
2745 2743
 
2746 2744
                 if (count($m[2])) {
2747 2745
                     unset($m[0]);
2748
-                    $output = '$this->readVarInto(' . str_replace("\n", '', var_export($m, true)) . ', ' . $output . ', ' . ($curBlock == 'root' ? 'false' : 'true') . ')';
2746
+                    $output = '$this->readVarInto('.str_replace("\n", '', var_export($m, true)).', '.$output.', '.($curBlock == 'root' ? 'false' : 'true').')';
2749 2747
                 }
2750 2748
             }
2751 2749
         } else {
2752 2750
             preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+)\]?#i', $key, $m);
2753 2751
             unset($m[0]);
2754
-            $output = '$this->readVar(' . str_replace("\n", '', var_export($m, true)) . ')';
2752
+            $output = '$this->readVar('.str_replace("\n", '', var_export($m, true)).')';
2755 2753
         }
2756 2754
 
2757 2755
         return $output;
@@ -2771,38 +2769,38 @@  discard block
 block discarded – undo
2771 2769
         $out = $recursed ? '".$this->readVarInto(' : '';
2772 2770
         foreach ($tree as $bit) {
2773 2771
             if (is_array($bit)) {
2774
-                $out .= '.' . $this->flattenVarTree($bit, false);
2772
+                $out .= '.'.$this->flattenVarTree($bit, false);
2775 2773
             } else {
2776 2774
                 $key = str_replace('"', '\\"', $bit);
2777 2775
 
2778 2776
                 if (substr($key, 0, 1) === '$') {
2779
-                    $out .= '".' . $this->parseVar($key, 0, strlen($key), false, 'variable') . '."';
2777
+                    $out .= '".'.$this->parseVar($key, 0, strlen($key), false, 'variable').'."';
2780 2778
                 } else {
2781 2779
                     $cnt = substr_count($key, '$');
2782 2780
 
2783 2781
                     if ($this->debug) {
2784
-                        echo 'PARSING SUBVARS IN : ' . $key . "\n";
2782
+                        echo 'PARSING SUBVARS IN : '.$key."\n";
2785 2783
                     }
2786 2784
                     if ($cnt > 0) {
2787
-                        while (-- $cnt >= 0) {
2785
+                        while (--$cnt >= 0) {
2788 2786
                             if (isset($last)) {
2789
-                                $last = strrpos($key, '$', - (strlen($key) - $last + 1));
2787
+                                $last = strrpos($key, '$', - (strlen($key)-$last+1));
2790 2788
                             } else {
2791 2789
                                 $last = strrpos($key, '$');
2792 2790
                             }
2793
-                            preg_match('#\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', substr($key, $last), $submatch);
2791
+                            preg_match('#\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*'.'((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', substr($key, $last), $submatch);
2794 2792
 
2795 2793
                             $len = strlen($submatch[0]);
2796 2794
                             $key = substr_replace(
2797 2795
                                 $key, preg_replace_callback(
2798
-                                    '#(\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*)' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', array(
2796
+                                    '#(\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*)'.'((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', array(
2799 2797
                                         $this,
2800 2798
                                         'replaceVarKeyHelper'
2801 2799
                                     ), substr($key, $last, $len)
2802 2800
                                 ), $last, $len
2803 2801
                             );
2804 2802
                             if ($this->debug) {
2805
-                                echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2803
+                                echo 'RECURSIVE VAR REPLACEMENT DONE : '.$key."\n";
2806 2804
                             }
2807 2805
                         }
2808 2806
                         unset($last);
@@ -2828,7 +2826,7 @@  discard block
 block discarded – undo
2828 2826
      */
2829 2827
     protected function replaceVarKeyHelper($match)
2830 2828
     {
2831
-        return '".' . $this->parseVar($match[0], 0, strlen($match[0]), false, 'variable') . '."';
2829
+        return '".'.$this->parseVar($match[0], 0, strlen($match[0]), false, 'variable').'."';
2832 2830
     }
2833 2831
 
2834 2832
     /**
@@ -2848,7 +2846,7 @@  discard block
 block discarded – undo
2848 2846
      */
2849 2847
     protected function parseOthers($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2850 2848
     {
2851
-        $substr = substr($in, $from, $to - $from);
2849
+        $substr = substr($in, $from, $to-$from);
2852 2850
 
2853 2851
         $end = strlen($substr);
2854 2852
 
@@ -2922,48 +2920,48 @@  discard block
 block discarded – undo
2922 2920
 
2923 2921
         if (strtolower($substr) === 'false' || strtolower($substr) === 'no' || strtolower($substr) === 'off') {
2924 2922
             if ($this->debug) {
2925
-                echo 'BOOLEAN(FALSE) PARSED' . "\n";
2923
+                echo 'BOOLEAN(FALSE) PARSED'."\n";
2926 2924
             }
2927 2925
             $substr = 'false';
2928 2926
             $type   = self::T_BOOL;
2929 2927
         } elseif (strtolower($substr) === 'true' || strtolower($substr) === 'yes' || strtolower($substr) === 'on') {
2930 2928
             if ($this->debug) {
2931
-                echo 'BOOLEAN(TRUE) PARSED' . "\n";
2929
+                echo 'BOOLEAN(TRUE) PARSED'."\n";
2932 2930
             }
2933 2931
             $substr = 'true';
2934 2932
             $type   = self::T_BOOL;
2935 2933
         } elseif ($substr === 'null' || $substr === 'NULL') {
2936 2934
             if ($this->debug) {
2937
-                echo 'NULL PARSED' . "\n";
2935
+                echo 'NULL PARSED'."\n";
2938 2936
             }
2939 2937
             $substr = 'null';
2940 2938
             $type   = self::T_NULL;
2941 2939
         } elseif (is_numeric($substr)) {
2942
-            $substr = (float)$substr;
2943
-            if ((int)$substr == $substr) {
2944
-                $substr = (int)$substr;
2940
+            $substr = (float) $substr;
2941
+            if ((int) $substr == $substr) {
2942
+                $substr = (int) $substr;
2945 2943
             }
2946 2944
             $type = self::T_NUMERIC;
2947 2945
             if ($this->debug) {
2948
-                echo 'NUMBER (' . $substr . ') PARSED' . "\n";
2946
+                echo 'NUMBER ('.$substr.') PARSED'."\n";
2949 2947
             }
2950 2948
         } elseif (preg_match('{^-?(\d+|\d*(\.\d+))\s*([/*%+-]\s*-?(\d+|\d*(\.\d+)))+$}', $substr)) {
2951 2949
             if ($this->debug) {
2952 2950
                 echo 'SIMPLE MATH PARSED . "\n"';
2953 2951
             }
2954 2952
             $type   = self::T_MATH;
2955
-            $substr = '(' . $substr . ')';
2953
+            $substr = '('.$substr.')';
2956 2954
         } elseif ($curBlock === 'condition' && array_search($substr, $breakChars, true) !== false) {
2957 2955
             if ($this->debug) {
2958
-                echo 'BREAKCHAR (' . $substr . ') PARSED' . "\n";
2956
+                echo 'BREAKCHAR ('.$substr.') PARSED'."\n";
2959 2957
             }
2960 2958
             $type = self::T_BREAKCHAR;
2961 2959
             //$substr = '"'.$substr.'"';
2962 2960
         } else {
2963
-            $substr = $this->replaceStringVars('\'' . str_replace('\'', '\\\'', $substr) . '\'', '\'', $curBlock);
2961
+            $substr = $this->replaceStringVars('\''.str_replace('\'', '\\\'', $substr).'\'', '\'', $curBlock);
2964 2962
             $type   = self::T_UNQUOTED_STRING;
2965 2963
             if ($this->debug) {
2966
-                echo 'BLABBER (' . $substr . ') CASTED AS STRING' . "\n";
2964
+                echo 'BLABBER ('.$substr.') CASTED AS STRING'."\n";
2967 2965
             }
2968 2966
         }
2969 2967
 
@@ -2993,28 +2991,28 @@  discard block
 block discarded – undo
2993 2991
     {
2994 2992
         $pos = 0;
2995 2993
         if ($this->debug) {
2996
-            echo 'STRING VAR REPLACEMENT : ' . $string . "\n";
2994
+            echo 'STRING VAR REPLACEMENT : '.$string."\n";
2997 2995
         }
2998 2996
         // replace vars
2999 2997
         while (($pos = strpos($string, '$', $pos)) !== false) {
3000
-            $prev = substr($string, $pos - 1, 1);
2998
+            $prev = substr($string, $pos-1, 1);
3001 2999
             if ($prev === '\\') {
3002
-                ++ $pos;
3000
+                ++$pos;
3003 3001
                 continue;
3004 3002
             }
3005 3003
 
3006 3004
             $var = $this->parse($string, $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3007 3005
             $len = $var[0];
3008
-            $var = $this->parse(str_replace('\\' . $first, $first, $string), $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3006
+            $var = $this->parse(str_replace('\\'.$first, $first, $string), $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3009 3007
 
3010
-            if ($prev === '`' && substr($string, $pos + $len, 1) === '`') {
3011
-                $string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos - 1, $len + 2);
3008
+            if ($prev === '`' && substr($string, $pos+$len, 1) === '`') {
3009
+                $string = substr_replace($string, $first.'.'.$var[1].'.'.$first, $pos-1, $len+2);
3012 3010
             } else {
3013
-                $string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos, $len);
3011
+                $string = substr_replace($string, $first.'.'.$var[1].'.'.$first, $pos, $len);
3014 3012
             }
3015
-            $pos += strlen($var[1]) + 2;
3013
+            $pos += strlen($var[1])+2;
3016 3014
             if ($this->debug) {
3017
-                echo 'STRING VAR REPLACEMENT DONE : ' . $string . "\n";
3015
+                echo 'STRING VAR REPLACEMENT DONE : '.$string."\n";
3018 3016
             }
3019 3017
         }
3020 3018
 
@@ -3050,7 +3048,7 @@  discard block
 block discarded – undo
3050 3048
     protected function replaceModifiers(array $m, $curBlock = null, &$pointer = null)
3051 3049
     {
3052 3050
         if ($this->debug) {
3053
-            echo 'PARSING MODIFIERS : ' . $m[3] . "\n";
3051
+            echo 'PARSING MODIFIERS : '.$m[3]."\n";
3054 3052
         }
3055 3053
 
3056 3054
         if ($pointer !== null) {
@@ -3074,7 +3072,7 @@  discard block
 block discarded – undo
3074 3072
             }
3075 3073
             if ($cmdstrsrc[0] === ' ' || $cmdstrsrc[0] === ';' || substr($cmdstrsrc, 0, strlen($this->rd)) === $this->rd) {
3076 3074
                 if ($this->debug) {
3077
-                    echo 'MODIFIER PARSING ENDED, RIGHT DELIMITER or ";" FOUND' . "\n";
3075
+                    echo 'MODIFIER PARSING ENDED, RIGHT DELIMITER or ";" FOUND'."\n";
3078 3076
                 }
3079 3077
                 $continue = false;
3080 3078
                 if ($pointer !== null) {
@@ -3085,7 +3083,7 @@  discard block
 block discarded – undo
3085 3083
             $cmdstr   = $cmdstrsrc;
3086 3084
             $paramsep = ':';
3087 3085
             if (!preg_match('/^(@{0,2}[a-z_][a-z0-9_]*)(:)?/i', $cmdstr, $match)) {
3088
-                throw new CompilationException($this, 'Invalid modifier name, started with : ' . substr($cmdstr, 0, 10));
3086
+                throw new CompilationException($this, 'Invalid modifier name, started with : '.substr($cmdstr, 0, 10));
3089 3087
             }
3090 3088
             $paramspos = !empty($match[2]) ? strlen($match[1]) : false;
3091 3089
             $func      = $match[1];
@@ -3095,10 +3093,10 @@  discard block
 block discarded – undo
3095 3093
                 $cmdstrsrc = substr($cmdstrsrc, strlen($func));
3096 3094
                 $params    = array();
3097 3095
                 if ($this->debug) {
3098
-                    echo 'MODIFIER (' . $func . ') CALLED WITH NO PARAMS' . "\n";
3096
+                    echo 'MODIFIER ('.$func.') CALLED WITH NO PARAMS'."\n";
3099 3097
                 }
3100 3098
             } else {
3101
-                $paramstr = substr($cmdstr, $paramspos + 1);
3099
+                $paramstr = substr($cmdstr, $paramspos+1);
3102 3100
                 if (substr($paramstr, - 1, 1) === $paramsep) {
3103 3101
                     $paramstr = substr($paramstr, 0, - 1);
3104 3102
                 }
@@ -3107,41 +3105,41 @@  discard block
 block discarded – undo
3107 3105
                 $params = array();
3108 3106
                 while ($ptr < strlen($paramstr)) {
3109 3107
                     if ($this->debug) {
3110
-                        echo 'MODIFIER (' . $func . ') START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
3108
+                        echo 'MODIFIER ('.$func.') START PARAM PARSING WITH POINTER AT '.$ptr."\n";
3111 3109
                     }
3112 3110
                     if ($this->debug) {
3113
-                        echo $paramstr . '--' . $ptr . '--' . strlen($paramstr) . '--modifier' . "\n";
3111
+                        echo $paramstr.'--'.$ptr.'--'.strlen($paramstr).'--modifier'."\n";
3114 3112
                     }
3115 3113
                     $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'modifier', $ptr);
3116 3114
                     if ($this->debug) {
3117
-                        echo 'PARAM PARSED, POINTER AT ' . $ptr . "\n";
3115
+                        echo 'PARAM PARSED, POINTER AT '.$ptr."\n";
3118 3116
                     }
3119 3117
 
3120 3118
                     if ($ptr >= strlen($paramstr)) {
3121 3119
                         if ($this->debug) {
3122
-                            echo 'PARAM PARSING ENDED, PARAM STRING CONSUMED' . "\n";
3120
+                            echo 'PARAM PARSING ENDED, PARAM STRING CONSUMED'."\n";
3123 3121
                         }
3124 3122
                         break;
3125 3123
                     }
3126 3124
 
3127 3125
                     if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === '|' || $paramstr[$ptr] === ';' || substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
3128 3126
                         if ($this->debug) {
3129
-                            echo 'PARAM PARSING ENDED, " ", "|", RIGHT DELIMITER or ";" FOUND, POINTER AT ' . $ptr . "\n";
3127
+                            echo 'PARAM PARSING ENDED, " ", "|", RIGHT DELIMITER or ";" FOUND, POINTER AT '.$ptr."\n";
3130 3128
                         }
3131 3129
                         if ($paramstr[$ptr] !== '|') {
3132 3130
                             $continue = false;
3133 3131
                             if ($pointer !== null) {
3134
-                                $pointer -= strlen($paramstr) - $ptr;
3132
+                                $pointer -= strlen($paramstr)-$ptr;
3135 3133
                             }
3136 3134
                         }
3137
-                        ++ $ptr;
3135
+                        ++$ptr;
3138 3136
                         break;
3139 3137
                     }
3140 3138
                     if ($ptr < strlen($paramstr) && $paramstr[$ptr] === ':') {
3141
-                        ++ $ptr;
3139
+                        ++$ptr;
3142 3140
                     }
3143 3141
                 }
3144
-                $cmdstrsrc = substr($cmdstrsrc, strlen($func) + 1 + $ptr);
3142
+                $cmdstrsrc = substr($cmdstrsrc, strlen($func)+1+$ptr);
3145 3143
                 foreach ($params as $k => $p) {
3146 3144
                     if (is_array($p) && is_array($p[1])) {
3147 3145
                         $state |= 2;
@@ -3181,9 +3179,9 @@  discard block
 block discarded – undo
3181 3179
                 $params = self::implode_r($params);
3182 3180
 
3183 3181
                 if ($mapped) {
3184
-                    $output = '$this->arrayMap(\'' . $func . '\', array(' . $params . '))';
3182
+                    $output = '$this->arrayMap(\''.$func.'\', array('.$params.'))';
3185 3183
                 } else {
3186
-                    $output = $func . '(' . $params . ')';
3184
+                    $output = $func.'('.$params.')';
3187 3185
                 }
3188 3186
             } elseif ($pluginType & Core::PROXY_PLUGIN) {
3189 3187
                 $params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state);
@@ -3201,36 +3199,36 @@  discard block
 block discarded – undo
3201 3199
                     $callback = $this->customPlugins[$func]['callback'];
3202 3200
                     if (is_array($callback)) {
3203 3201
                         if (is_object($callback[0])) {
3204
-                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(' . $params . '))';
3202
+                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), array('.$params.'))';
3205 3203
                         } else {
3206
-                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3204
+                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array(\''.$callback[0].'\', \''.$callback[1].'\'), array('.$params.'))';
3207 3205
                         }
3208 3206
                     } elseif ($mapped) {
3209
-                        $output = '$this->arrayMap(\'' . $callback . '\', array(' . $params . '))';
3207
+                        $output = '$this->arrayMap(\''.$callback.'\', array('.$params.'))';
3210 3208
                     } else {
3211
-                        $output = $callback . '(' . $params . ')';
3209
+                        $output = $callback.'('.$params.')';
3212 3210
                     }
3213 3211
                 } elseif ($mapped) {
3214
-                    $output = '$this->arrayMap(\'smarty_modifier_' . $func . '\', array(' . $params . '))';
3212
+                    $output = '$this->arrayMap(\'smarty_modifier_'.$func.'\', array('.$params.'))';
3215 3213
                 } else {
3216
-                    $output = 'smarty_modifier_' . $func . '(' . $params . ')';
3214
+                    $output = 'smarty_modifier_'.$func.'('.$params.')';
3217 3215
                 }
3218 3216
             } else {
3219 3217
                 if ($pluginType & Core::CUSTOM_PLUGIN) {
3220 3218
                     $callback   = $this->customPlugins[$func]['callback'];
3221 3219
                     $pluginName = $callback;
3222 3220
                 } else {
3223
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false || function_exists('Plugin' .
3224
-                            Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''))
3221
+                    if (class_exists('Plugin'.Core::toCamelCase($func)) !== false || function_exists('Plugin'.
3222
+                            Core::toCamelCase($func).(($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''))
3225 3223
                         !== false) {
3226
-                        $pluginName = 'Plugin' . Core::toCamelCase($func);
3224
+                        $pluginName = 'Plugin'.Core::toCamelCase($func);
3227 3225
                     } else {
3228
-                        $pluginName = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func);
3226
+                        $pluginName = Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func);
3229 3227
                     }
3230 3228
                     if ($pluginType & Core::CLASS_PLUGIN) {
3231 3229
                         $callback = array($pluginName, ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process');
3232 3230
                     } else {
3233
-                        $callback = $pluginName . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '');
3231
+                        $callback = $pluginName.(($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '');
3234 3232
                     }
3235 3233
                 }
3236 3234
                 $params = $this->mapParams($params, $callback, $state);
@@ -3248,10 +3246,10 @@  discard block
 block discarded – undo
3248 3246
                         if ($pluginType & Core::CUSTOM_PLUGIN) {
3249 3247
                             $funcCompiler = $this->customPlugins[$func]['callback'];
3250 3248
                         } else {
3251
-                            if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
3252
-                                $funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
3249
+                            if (function_exists('Plugin'.Core::toCamelCase($func).'Compile') !== false) {
3250
+                                $funcCompiler = 'Plugin'.Core::toCamelCase($func).'Compile';
3253 3251
                             } else {
3254
-                                $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
3252
+                                $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func).
3255 3253
                                     'Compile';
3256 3254
                             }
3257 3255
                         }
@@ -3262,9 +3260,9 @@  discard block
 block discarded – undo
3262 3260
 
3263 3261
                         $params = self::implode_r($params);
3264 3262
                         if ($mapped) {
3265
-                            $output = '$this->arrayMap(\'' . $pluginName . '\', array(' . $params . '))';
3263
+                            $output = '$this->arrayMap(\''.$pluginName.'\', array('.$params.'))';
3266 3264
                         } else {
3267
-                            $output = $pluginName . '(' . $params . ')';
3265
+                            $output = $pluginName.'('.$params.')';
3268 3266
                         }
3269 3267
                     }
3270 3268
                 } else {
@@ -3276,7 +3274,7 @@  discard block
 block discarded – undo
3276 3274
                             $callback = $this->customPlugins[$func]['callback'];
3277 3275
                             if (!is_array($callback)) {
3278 3276
                                 if (!method_exists($callback, 'compile')) {
3279
-                                    throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
3277
+                                    throw new Exception('Custom plugin '.$func.' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
3280 3278
                                 }
3281 3279
                                 if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
3282 3280
                                     $funcCompiler = array($callback, 'compile');
@@ -3287,11 +3285,11 @@  discard block
 block discarded – undo
3287 3285
                                 $funcCompiler = $callback;
3288 3286
                             }
3289 3287
                         } else {
3290
-                            if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3291
-                                $funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
3288
+                            if (class_exists('Plugin'.Core::toCamelCase($func)) !== false) {
3289
+                                $funcCompiler = array('Plugin'.Core::toCamelCase($func), 'compile');
3292 3290
                             } else {
3293 3291
                                 $funcCompiler = array(
3294
-                                    Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
3292
+                                    Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func),
3295 3293
                                     'compile'
3296 3294
                                 );
3297 3295
                             }
@@ -3303,23 +3301,23 @@  discard block
 block discarded – undo
3303 3301
 
3304 3302
                         if ($pluginType & Core::CUSTOM_PLUGIN) {
3305 3303
                             if (is_object($callback[0])) {
3306
-                                $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(' . $params . '))';
3304
+                                $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), array('.$params.'))';
3307 3305
                             } else {
3308
-                                $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3306
+                                $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array(\''.$callback[0].'\', \''.$callback[1].'\'), array('.$params.'))';
3309 3307
                             }
3310 3308
                         } elseif ($mapped) {
3311 3309
                             $output = '$this->arrayMap(array($this->getObjectPlugin(\''.
3312
-                                Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '\'), 
3313
-                            \'process\'), array(' . $params . '))';
3310
+                                Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func).'\'), 
3311
+                            \'process\'), array(' . $params.'))';
3314 3312
                         } else {
3315
-                            if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3316
-                                $output = '$this->classCall(\'Plugin' . Core::toCamelCase($func) . '\', array(' . $params . '))';
3317
-                            } elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($func)) !== false) {
3318
-                                $output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . $func . '\', array(' . $params . '))';
3319
-                            } elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !== false) {
3320
-                                $output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\', array(' . $params . '))';
3313
+                            if (class_exists('Plugin'.Core::toCamelCase($func)) !== false) {
3314
+                                $output = '$this->classCall(\'Plugin'.Core::toCamelCase($func).'\', array('.$params.'))';
3315
+                            } elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($func)) !== false) {
3316
+                                $output = '$this->classCall(\''.Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.$func.'\', array('.$params.'))';
3317
+                            } elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func)) !== false) {
3318
+                                $output = '$this->classCall(\''.Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.$func.'\', array('.$params.'))';
3321 3319
                             } else {
3322
-                                $output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
3320
+                                $output = '$this->classCall(\''.$func.'\', array('.$params.'))';
3323 3321
                             }
3324 3322
                         }
3325 3323
                     }
@@ -3332,7 +3330,7 @@  discard block
 block discarded – undo
3332 3330
         } elseif ($curBlock === 'var' || $m[1] === null) {
3333 3331
             return $output;
3334 3332
         } elseif ($curBlock === 'string' || $curBlock === 'root') {
3335
-            return $m[1] . '.' . $output . '.' . $m[1] . (isset($add) ? $add : null);
3333
+            return $m[1].'.'.$output.'.'.$m[1].(isset($add) ? $add : null);
3336 3334
         }
3337 3335
 
3338 3336
         return '';
@@ -3355,14 +3353,14 @@  discard block
 block discarded – undo
3355 3353
             if (is_array($p)) {
3356 3354
                 $out2 = 'array(';
3357 3355
                 foreach ($p as $k2 => $v) {
3358
-                    $out2 .= var_export($k2, true) . ' => ' . (is_array($v) ? 'array(' . self::implode_r($v, true) . ')' : $v) . ', ';
3356
+                    $out2 .= var_export($k2, true).' => '.(is_array($v) ? 'array('.self::implode_r($v, true).')' : $v).', ';
3359 3357
                 }
3360
-                $p = rtrim($out2, ', ') . ')';
3358
+                $p = rtrim($out2, ', ').')';
3361 3359
             }
3362 3360
             if ($recursiveCall) {
3363
-                $out .= var_export($k, true) . ' => ' . $p . ', ';
3361
+                $out .= var_export($k, true).' => '.$p.', ';
3364 3362
             } else {
3365
-                $out .= $p . ', ';
3363
+                $out .= $p.', ';
3366 3364
             }
3367 3365
         }
3368 3366
 
@@ -3386,7 +3384,7 @@  discard block
 block discarded – undo
3386 3384
         if (($this->securityPolicy === null && (function_exists($name) || strtolower($name) === 'isset' || strtolower($name) === 'empty')) || ($this->securityPolicy !== null && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) !== false)) {
3387 3385
             $phpFunc = true;
3388 3386
         } elseif ($this->securityPolicy !== null && function_exists($name) && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) === false) {
3389
-            throw new SecurityException('Call to a disallowed php function : ' . $name);
3387
+            throw new SecurityException('Call to a disallowed php function : '.$name);
3390 3388
         }
3391 3389
 
3392 3390
         while ($pluginType <= 0) {
@@ -3397,58 +3395,58 @@  discard block
 block discarded – undo
3397 3395
             elseif (isset($this->customPlugins[$name])) {
3398 3396
                 $pluginType = $this->customPlugins[$name]['type'] | Core::CUSTOM_PLUGIN;
3399 3397
             } // Class blocks plugin
3400
-            elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3398
+            elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($name)) !== false) {
3401 3399
                 $pluginType = Core::CLASS_PLUGIN;
3402
-                if (is_subclass_of(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3400
+                if (is_subclass_of(Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3403 3401
                     $pluginType += Core::BLOCK_PLUGIN;
3404 3402
                 }
3405
-                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name));
3403
+                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($name));
3406 3404
                 if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3407 3405
                     $pluginType |= Core::COMPILABLE_PLUGIN;
3408 3406
                 }
3409 3407
             } // Class functions plugin
3410
-            elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3411
-                $pluginType = Core::FUNC_PLUGIN + Core::CLASS_PLUGIN;
3412
-                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name));
3408
+            elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($name)) !== false) {
3409
+                $pluginType = Core::FUNC_PLUGIN+Core::CLASS_PLUGIN;
3410
+                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($name));
3413 3411
                 if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3414 3412
                     $pluginType |= Core::COMPILABLE_PLUGIN;
3415 3413
                 }
3416 3414
             } // Class without namespace
3417
-            elseif (class_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3415
+            elseif (class_exists('Plugin'.Core::toCamelCase($name)) !== false) {
3418 3416
                 $pluginType = Core::CLASS_PLUGIN;
3419
-                $interfaces = class_implements('Plugin' . Core::toCamelCase($name));
3417
+                $interfaces = class_implements('Plugin'.Core::toCamelCase($name));
3420 3418
                 if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3421 3419
                     $pluginType |= Core::COMPILABLE_PLUGIN;
3422 3420
                 }
3423 3421
             } // Function plugin (with/without namespaces)
3424
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase ($name)) !==
3425
-                false || function_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3422
+            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($name)) !==
3423
+                false || function_exists('Plugin'.Core::toCamelCase($name)) !== false) {
3426 3424
                 $pluginType = Core::FUNC_PLUGIN;
3427 3425
             } // Function plugin compile (with/without namespaces)
3428
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name) .
3429
-                    'Compile') !== false || function_exists('Plugin' . Core::toCamelCase($name) . 'Compile') !==
3426
+            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($name).
3427
+                    'Compile') !== false || function_exists('Plugin'.Core::toCamelCase($name).'Compile') !==
3430 3428
                 false) {
3431 3429
                 $pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3432 3430
             } // Helper plugin class compile
3433
-            elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3431
+            elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($name)) !== false) {
3434 3432
                 $pluginType = Core::CLASS_PLUGIN | Core::COMPILABLE_PLUGIN;
3435 3433
             } // Helper plugin function compile
3436
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name) . 'Compile') !== false) {
3434
+            elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($name).'Compile') !== false) {
3437 3435
                 $pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3438 3436
             } // Smarty modifier
3439
-            elseif (function_exists('smarty_modifier_' . $name) !== false) {
3437
+            elseif (function_exists('smarty_modifier_'.$name) !== false) {
3440 3438
                 $pluginType = Core::SMARTY_MODIFIER;
3441 3439
             } // Smarty function
3442
-            elseif (function_exists('smarty_function_' . $name) !== false) {
3440
+            elseif (function_exists('smarty_function_'.$name) !== false) {
3443 3441
                 $pluginType = Core::SMARTY_FUNCTION;
3444 3442
             } // Smarty block
3445
-            elseif (function_exists('smarty_block_' . $name) !== false) {
3443
+            elseif (function_exists('smarty_block_'.$name) !== false) {
3446 3444
                 $pluginType = Core::SMARTY_BLOCK;
3447 3445
             } // Everything else
3448 3446
             else {
3449 3447
                 if ($pluginType === - 1) {
3450 3448
                     try {
3451
-                        $this->getDwoo()->getLoader()->loadPlugin('Plugin' . Core::toCamelCase($name));
3449
+                        $this->getDwoo()->getLoader()->loadPlugin('Plugin'.Core::toCamelCase($name));
3452 3450
                     }
3453 3451
                     catch (Exception $e) {
3454 3452
                         if (isset($phpFunc)) {
@@ -3461,9 +3459,9 @@  discard block
 block discarded – undo
3461 3459
                         }
3462 3460
                     }
3463 3461
                 } else {
3464
-                    throw new Exception('Plugin "' . $name . '" could not be found, type:' . $pluginType);
3462
+                    throw new Exception('Plugin "'.$name.'" could not be found, type:'.$pluginType);
3465 3463
                 }
3466
-                ++ $pluginType;
3464
+                ++$pluginType;
3467 3465
             }
3468 3466
         }
3469 3467
 
@@ -3532,15 +3530,15 @@  discard block
 block discarded – undo
3532 3530
         }
3533 3531
 
3534 3532
         // loops over the param map and assigns values from the template or default value for unset optional params
3535
-        foreach ($map as $k => $v){
3533
+        foreach ($map as $k => $v) {
3536 3534
             if ($v[0] === '*') {
3537 3535
                 // "rest" array parameter, fill every remaining params in it and then break
3538 3536
                 if (count($ps) === 0) {
3539 3537
                     if ($v[1] === false) {
3540 3538
                         throw new CompilationException(
3541
-                            $this, 'Rest argument missing for ' . str_replace(
3539
+                            $this, 'Rest argument missing for '.str_replace(
3542 3540
                                 array(
3543
-                                    Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3541
+                                    Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin',
3544 3542
                                 'Compile'
3545 3543
                                 ), '', (is_array($callback) ? $callback[0] : $callback)
3546 3544
                             )
@@ -3573,7 +3571,7 @@  discard block
 block discarded – undo
3573 3571
                 // parameter is not defined and not optional, throw error
3574 3572
                 if (is_array($callback)) {
3575 3573
                     if (is_object($callback[0])) {
3576
-                        $name = get_class($callback[0]) . '::' . $callback[1];
3574
+                        $name = get_class($callback[0]).'::'.$callback[1];
3577 3575
                     } else {
3578 3576
                         $name = $callback[0];
3579 3577
                     }
@@ -3582,9 +3580,9 @@  discard block
 block discarded – undo
3582 3580
                 }
3583 3581
 
3584 3582
                 throw new CompilationException(
3585
-                    $this, 'Argument ' . $k . '/' . $v[0] . ' missing for ' . str_replace(
3583
+                    $this, 'Argument '.$k.'/'.$v[0].' missing for '.str_replace(
3586 3584
                         array(
3587
-                            Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3585
+                            Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin',
3588 3586
                         'Compile'
3589 3587
                         ), '', $name
3590 3588
                     )
Please login to merge, or discard this patch.
Braces   +3 added lines, -6 removed lines patch added patch discarded remove patch
@@ -478,8 +478,7 @@  discard block
 block discarded – undo
478 478
         if (!class_exists($class) && !function_exists($class)) {
479 479
             try {
480 480
                 $this->getDwoo()->getLoader()->loadPlugin($name);
481
-            }
482
-            catch (Exception $e) {
481
+            } catch (Exception $e) {
483 482
                 throw new Exception('Processor ' . $name . ' could not be found in your plugin directories, please ensure it is in a file named ' . $name . '.php in the plugin directory');
484 483
             }
485 484
         }
@@ -1633,8 +1632,7 @@  discard block
 block discarded – undo
1633 1632
                     // load if plugin
1634 1633
                     try {
1635 1634
                         $this->getPluginType('if');
1636
-                    }
1637
-                    catch (Exception $e) {
1635
+                    } catch (Exception $e) {
1638 1636
                         throw new CompilationException($this, 'Assignments require the "if" plugin to be accessible');
1639 1637
                     }
1640 1638
 
@@ -3449,8 +3447,7 @@  discard block
 block discarded – undo
3449 3447
                 if ($pluginType === - 1) {
3450 3448
                     try {
3451 3449
                         $this->getDwoo()->getLoader()->loadPlugin('Plugin' . Core::toCamelCase($name));
3452
-                    }
3453
-                    catch (Exception $e) {
3450
+                    } catch (Exception $e) {
3454 3451
                         if (isset($phpFunc)) {
3455 3452
                             $pluginType = Core::NATIVE_PLUGIN;
3456 3453
                         } elseif (is_object($this->getDwoo()->getPluginProxy()) && $this->getDwoo()->getPluginProxy()->handles($name)) {
Please login to merge, or discard this patch.
lib/Dwoo/ITemplate.php 1 patch
Indentation   +122 added lines, -122 removed lines patch added patch discarded remove patch
@@ -23,139 +23,139 @@
 block discarded – undo
23 23
  */
24 24
 interface ITemplate
25 25
 {
26
-    /**
27
-     * Returns the cache duration for this template.
28
-     * defaults to null if it was not provided
29
-     *
30
-     * @return int|null
31
-     */
32
-    public function getCacheTime();
26
+	/**
27
+	 * Returns the cache duration for this template.
28
+	 * defaults to null if it was not provided
29
+	 *
30
+	 * @return int|null
31
+	 */
32
+	public function getCacheTime();
33 33
 
34
-    /**
35
-     * Sets the cache duration for this template.
36
-     * can be used to set it after the object is created if you did not provide
37
-     * it in the constructor
38
-     *
39
-     * @param int $seconds duration of the cache validity for this template, if
40
-     *                     null it defaults to the Dwoo instance's cache time. 0 = disable and
41
-     *                     -1 = infinite cache
42
-     */
43
-    public function setCacheTime($seconds = null);
34
+	/**
35
+	 * Sets the cache duration for this template.
36
+	 * can be used to set it after the object is created if you did not provide
37
+	 * it in the constructor
38
+	 *
39
+	 * @param int $seconds duration of the cache validity for this template, if
40
+	 *                     null it defaults to the Dwoo instance's cache time. 0 = disable and
41
+	 *                     -1 = infinite cache
42
+	 */
43
+	public function setCacheTime($seconds = null);
44 44
 
45
-    /**
46
-     * Returns the cached template output file name, true if it's cache-able but not cached
47
-     * or false if it's not cached.
48
-     *
49
-     * @param Core $core the dwoo instance that requests it
50
-     *
51
-     * @return string|bool
52
-     */
53
-    public function getCachedTemplate(Core $core);
45
+	/**
46
+	 * Returns the cached template output file name, true if it's cache-able but not cached
47
+	 * or false if it's not cached.
48
+	 *
49
+	 * @param Core $core the dwoo instance that requests it
50
+	 *
51
+	 * @return string|bool
52
+	 */
53
+	public function getCachedTemplate(Core $core);
54 54
 
55
-    /**
56
-     * Caches the provided output into the cache file.
57
-     *
58
-     * @param Core   $core   the dwoo instance that requests it
59
-     * @param string $output the template output
60
-     *
61
-     * @return mixed full path of the cached file or false upon failure
62
-     */
63
-    public function cache(Core $core, $output);
55
+	/**
56
+	 * Caches the provided output into the cache file.
57
+	 *
58
+	 * @param Core   $core   the dwoo instance that requests it
59
+	 * @param string $output the template output
60
+	 *
61
+	 * @return mixed full path of the cached file or false upon failure
62
+	 */
63
+	public function cache(Core $core, $output);
64 64
 
65
-    /**
66
-     * Clears the cached template if it's older than the given time.
67
-     *
68
-     * @param Core $core      the dwoo instance that was used to cache that template
69
-     * @param int  $olderThan minimum time (in seconds) required for the cache to be cleared
70
-     *
71
-     * @return bool true if the cache was not present or if it was deleted, false if it remains there
72
-     */
73
-    public function clearCache(Core $core, $olderThan = - 1);
65
+	/**
66
+	 * Clears the cached template if it's older than the given time.
67
+	 *
68
+	 * @param Core $core      the dwoo instance that was used to cache that template
69
+	 * @param int  $olderThan minimum time (in seconds) required for the cache to be cleared
70
+	 *
71
+	 * @return bool true if the cache was not present or if it was deleted, false if it remains there
72
+	 */
73
+	public function clearCache(Core $core, $olderThan = - 1);
74 74
 
75
-    /**
76
-     * Returns the compiled template file name.
77
-     *
78
-     * @param Core      $core     the dwoo instance that requests it
79
-     * @param ICompiler $compiler the compiler that must be used
80
-     *
81
-     * @return string
82
-     */
83
-    public function getCompiledTemplate(Core $core, ICompiler $compiler = null);
75
+	/**
76
+	 * Returns the compiled template file name.
77
+	 *
78
+	 * @param Core      $core     the dwoo instance that requests it
79
+	 * @param ICompiler $compiler the compiler that must be used
80
+	 *
81
+	 * @return string
82
+	 */
83
+	public function getCompiledTemplate(Core $core, ICompiler $compiler = null);
84 84
 
85
-    /**
86
-     * Returns the template name.
87
-     *
88
-     * @return string
89
-     */
90
-    public function getName();
85
+	/**
86
+	 * Returns the template name.
87
+	 *
88
+	 * @return string
89
+	 */
90
+	public function getName();
91 91
 
92
-    /**
93
-     * Returns the resource name for this template class.
94
-     *
95
-     * @return string
96
-     */
97
-    public function getResourceName();
92
+	/**
93
+	 * Returns the resource name for this template class.
94
+	 *
95
+	 * @return string
96
+	 */
97
+	public function getResourceName();
98 98
 
99
-    /**
100
-     * Returns the resource identifier for this template or false if it has no identifier.
101
-     *
102
-     * @return string|false
103
-     */
104
-    public function getResourceIdentifier();
99
+	/**
100
+	 * Returns the resource identifier for this template or false if it has no identifier.
101
+	 *
102
+	 * @return string|false
103
+	 */
104
+	public function getResourceIdentifier();
105 105
 
106
-    /**
107
-     * Returns the template source of this template.
108
-     *
109
-     * @return string
110
-     */
111
-    public function getSource();
106
+	/**
107
+	 * Returns the template source of this template.
108
+	 *
109
+	 * @return string
110
+	 */
111
+	public function getSource();
112 112
 
113
-    /**
114
-     * Returns an unique string identifying the current version of this template,
115
-     * for example a timestamp of the last modified date or a hash of the template source.
116
-     *
117
-     * @return string
118
-     */
119
-    public function getUid();
113
+	/**
114
+	 * Returns an unique string identifying the current version of this template,
115
+	 * for example a timestamp of the last modified date or a hash of the template source.
116
+	 *
117
+	 * @return string
118
+	 */
119
+	public function getUid();
120 120
 
121
-    /**
122
-     * Returns the compiler used by this template, if it was just compiled, or null.
123
-     *
124
-     * @return ICompiler
125
-     */
126
-    public function getCompiler();
121
+	/**
122
+	 * Returns the compiler used by this template, if it was just compiled, or null.
123
+	 *
124
+	 * @return ICompiler
125
+	 */
126
+	public function getCompiler();
127 127
 
128
-    /**
129
-     * Returns some php code that will check if this template has been modified or not.
130
-     * if the function returns null, the template will be instanciated and then the Uid checked
131
-     *
132
-     * @return string
133
-     */
134
-    public function getIsModifiedCode();
128
+	/**
129
+	 * Returns some php code that will check if this template has been modified or not.
130
+	 * if the function returns null, the template will be instanciated and then the Uid checked
131
+	 *
132
+	 * @return string
133
+	 */
134
+	public function getIsModifiedCode();
135 135
 
136
-    /**
137
-     * Returns a new template object from the given resource identifier, null if no include is
138
-     * possible (resource not found), or false if include is not permitted by this resource type.
139
-     * this method should also check if $dwoo->getSecurityPolicy() is null or not and do the
140
-     * necessary permission checks if required, if the security policy prevents the template
141
-     * generation it should throw a new Security\Exception with a relevant message
142
-     *
143
-     * @param Core      $core
144
-     * @param mixed     $resourceId     the resource identifier
145
-     * @param int       $cacheTime      duration of the cache validity for this template, if null it defaults to the
146
-     *                                  Dwoo instance that will render this template if null it defaults to the Dwoo
147
-     *                                  instance that will render this template
148
-     * @param string    $cacheId        the unique cache identifier of this page or anything else that makes this
149
-     *                                  template's content unique, if null it defaults to the current url makes this
150
-     *                                  template's content unique, if null it defaults to the current url
151
-     * @param string    $compileId      the unique compiled identifier, which is used to distinguish this template from
152
-     *                                  others, if null it defaults to the filename+bits of the path template from
153
-     *                                  others, if null it defaults to the filename+bits of the path
154
-     * @param ITemplate $parentTemplate the template that is requesting a new template object (through an include,
155
-     *                                  extends or any other plugin) an include, extends or any other plugin)
156
-     *
157
-     * @return ITemplate|false|null
158
-     */
159
-    public static function templateFactory(Core $core, $resourceId, $cacheTime = null, $cacheId = null,
160
-                                           $compileId = null, ITemplate $parentTemplate = null);
136
+	/**
137
+	 * Returns a new template object from the given resource identifier, null if no include is
138
+	 * possible (resource not found), or false if include is not permitted by this resource type.
139
+	 * this method should also check if $dwoo->getSecurityPolicy() is null or not and do the
140
+	 * necessary permission checks if required, if the security policy prevents the template
141
+	 * generation it should throw a new Security\Exception with a relevant message
142
+	 *
143
+	 * @param Core      $core
144
+	 * @param mixed     $resourceId     the resource identifier
145
+	 * @param int       $cacheTime      duration of the cache validity for this template, if null it defaults to the
146
+	 *                                  Dwoo instance that will render this template if null it defaults to the Dwoo
147
+	 *                                  instance that will render this template
148
+	 * @param string    $cacheId        the unique cache identifier of this page or anything else that makes this
149
+	 *                                  template's content unique, if null it defaults to the current url makes this
150
+	 *                                  template's content unique, if null it defaults to the current url
151
+	 * @param string    $compileId      the unique compiled identifier, which is used to distinguish this template from
152
+	 *                                  others, if null it defaults to the filename+bits of the path template from
153
+	 *                                  others, if null it defaults to the filename+bits of the path
154
+	 * @param ITemplate $parentTemplate the template that is requesting a new template object (through an include,
155
+	 *                                  extends or any other plugin) an include, extends or any other plugin)
156
+	 *
157
+	 * @return ITemplate|false|null
158
+	 */
159
+	public static function templateFactory(Core $core, $resourceId, $cacheTime = null, $cacheId = null,
160
+										   $compileId = null, ITemplate $parentTemplate = null);
161 161
 }
Please login to merge, or discard this patch.
lib/Dwoo/Plugins/Functions/PluginCapitalize.php 2 patches
Indentation   +23 added lines, -23 removed lines patch added patch discarded remove patch
@@ -29,28 +29,28 @@
 block discarded – undo
29 29
  */
30 30
 class PluginCapitalize extends Plugin
31 31
 {
32
-    /**
33
-     * @param string $value
34
-     * @param bool   $numwords
35
-     *
36
-     * @return string
37
-     */
38
-    public function process($value, $numwords = false)
39
-    {
40
-        if ($numwords || preg_match('#^[^0-9]+$#', $value)) {
41
-            return mb_convert_case((string)$value, MB_CASE_TITLE, $this->core->getCharset());
42
-        } else {
43
-            $bits = explode(' ', (string)$value);
44
-            $out  = '';
45
-            foreach ($bits as $k => $v){
46
-                if (preg_match('#^[^0-9]+$#', $v)) {
47
-                    $out .= ' ' . mb_convert_case($v, MB_CASE_TITLE, $this->core->getCharset());
48
-                } else {
49
-                    $out .= ' ' . $v;
50
-                }
51
-            }
32
+	/**
33
+	 * @param string $value
34
+	 * @param bool   $numwords
35
+	 *
36
+	 * @return string
37
+	 */
38
+	public function process($value, $numwords = false)
39
+	{
40
+		if ($numwords || preg_match('#^[^0-9]+$#', $value)) {
41
+			return mb_convert_case((string)$value, MB_CASE_TITLE, $this->core->getCharset());
42
+		} else {
43
+			$bits = explode(' ', (string)$value);
44
+			$out  = '';
45
+			foreach ($bits as $k => $v){
46
+				if (preg_match('#^[^0-9]+$#', $v)) {
47
+					$out .= ' ' . mb_convert_case($v, MB_CASE_TITLE, $this->core->getCharset());
48
+				} else {
49
+					$out .= ' ' . $v;
50
+				}
51
+			}
52 52
 
53
-            return substr($out, 1);
54
-        }
55
-    }
53
+			return substr($out, 1);
54
+		}
55
+	}
56 56
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -38,15 +38,15 @@
 block discarded – undo
38 38
     public function process($value, $numwords = false)
39 39
     {
40 40
         if ($numwords || preg_match('#^[^0-9]+$#', $value)) {
41
-            return mb_convert_case((string)$value, MB_CASE_TITLE, $this->core->getCharset());
41
+            return mb_convert_case((string) $value, MB_CASE_TITLE, $this->core->getCharset());
42 42
         } else {
43
-            $bits = explode(' ', (string)$value);
43
+            $bits = explode(' ', (string) $value);
44 44
             $out  = '';
45
-            foreach ($bits as $k => $v){
45
+            foreach ($bits as $k => $v) {
46 46
                 if (preg_match('#^[^0-9]+$#', $v)) {
47
-                    $out .= ' ' . mb_convert_case($v, MB_CASE_TITLE, $this->core->getCharset());
47
+                    $out .= ' '.mb_convert_case($v, MB_CASE_TITLE, $this->core->getCharset());
48 48
                 } else {
49
-                    $out .= ' ' . $v;
49
+                    $out .= ' '.$v;
50 50
                 }
51 51
             }
52 52
 
Please login to merge, or discard this patch.