Setting back compacted template content will reduce memory usage
[core.git] / inc / classes / main / template / class_BaseTemplateEngine.php
1 <?php
2 /**
3  * A generic template engine
4  *
5  * @author              Roland Haeder <webmaster@ship-simu.org>
6  * @version             0.0.0
7  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2011 Core Developer Team
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.ship-simu.org
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <http://www.gnu.org/licenses/>.
23  */
24 class BaseTemplateEngine extends BaseFrameworkSystem {
25         /**
26          * The local path name where all templates and sub folders for special
27          * templates are stored. We will internally determine the language plus
28          * "html" for web templates or "emails" for email templates
29          */
30         private $templateBasePath = '';
31
32         /**
33          * Template type
34          */
35         private $templateType = 'html';
36
37         /**
38          * The extension for web and email templates (not compiled templates)
39          */
40         private $templateExtension = '.tpl';
41
42         /**
43          * The extension for code templates (not compiled templates)
44          */
45         private $codeExtension = '.ctp';
46
47         /**
48          * Path relative to $templateBasePath and language code for compiled code-templates
49          */
50         private $compileOutputPath = 'templates/_compiled/';
51
52         /**
53          * The path name for all templates
54          */
55         private $genericBasePath = 'templates/';
56
57         /**
58          * The raw (maybe uncompiled) template
59          */
60         private $rawTemplateData = '';
61
62         /**
63          * Template data with compiled-in variables
64          */
65         private $compiledData = '';
66
67         /**
68          * The last loaded template's FQFN for debugging the engine
69          */
70         private $lastTemplate = '';
71
72         /**
73          * The variable stack for the templates
74          */
75         private $varStack = array();
76
77         /**
78          * Loaded templates for recursive protection and detection
79          */
80         private $loadedTemplates = array();
81
82         /**
83          * Compiled templates for recursive protection and detection
84          */
85         private $compiledTemplates = array();
86
87         /**
88          * Loaded raw template data
89          */
90         private $loadedRawData = null;
91
92         /**
93          * Raw templates which are linked in code templates
94          */
95         private $rawTemplates = null;
96
97         /**
98          * A regular expression for variable=value pairs
99          */
100         private $regExpVarValue = '/([\w_]+)(="([^"]*)"|=([\w_]+))?/';
101
102         /**
103          * A regular expression for filtering out code tags
104          *
105          * E.g.: {?template:variable=value;var2=value2;[...]?}
106          */
107         private $regExpCodeTags = '/\{\?([a-z_]+)(:("[^"]+"|[^?}]+)+)?\?\}/';
108
109         /**
110          * Loaded helpers
111          */
112         private $helpers = array();
113
114         /**
115          * Current variable group
116          */
117         private $currGroup = 'general';
118
119         /**
120          * All template groups except "general"
121          */
122         private $varGroups = array();
123
124         /**
125          * Code begin
126          */
127         private $codeBegin = '<?php';
128
129         /**
130          * Code end
131          */
132         private $codeEnd = '?>';
133
134         /**
135          * Language support is enabled by default
136          */
137         private $languageSupport = true;
138
139         /**
140          * XML compacting is disabled by default
141          */
142         private $xmlCompacting = false;
143
144         // Exception codes for the template engine
145         const EXCEPTION_TEMPLATE_TYPE_IS_UNEXPECTED   = 0x110;
146         const EXCEPTION_TEMPLATE_CONTAINS_INVALID_VAR = 0x111;
147         const EXCEPTION_INVALID_VIEW_HELPER           = 0x112;
148         const EXCEPTION_VARIABLE_IS_MISSING           = 0x113;
149
150         /**
151          * Protected constructor
152          *
153          * @param       $className      Name of the class
154          * @return      void
155          */
156         protected function __construct ($className) {
157                 // Call parent constructor
158                 parent::__construct($className);
159
160                 // Init file I/O instance
161                 $ioInstance = ObjectFactory::createObjectByConfiguredName('file_io_class');
162
163                 // Set it
164                 $this->setFileIoInstance($ioInstance);
165         }
166
167         /**
168          * Search for a variable in the stack
169          *
170          * @param       $var    The variable we are looking for
171          * @param       $stack  Optional variable stack to look in
172          * @return      $index  FALSE means not found, >=0 means found on a specific index
173          */
174         private function getVariableIndex ($var, $stack = null) {
175                 // First everything is not found
176                 $found = false;
177
178                 // If the stack is null, use the current group
179                 if (is_null($stack)) $stack = $this->currGroup;
180
181                 // Is the group there?
182                 if ($this->isVarStackSet($stack)) {
183                         // Now search for it
184                         foreach ($this->getVarStack($stack) as $index => $currEntry) {
185                                 //* DEBUG: */ echo __METHOD__.":currGroup={$stack},idx={$index},currEntry={$currEntry['name']},var={$var}<br />\n";
186                                 // Is the entry found?
187                                 if ($currEntry['name'] == $var) {
188                                         // Found!
189                                         //* DEBUG: */ echo __METHOD__.":FOUND!<br />\n";
190                                         $found = $index;
191                                         break;
192                                 } // END - if
193                         } // END - foreach
194                 } // END - if
195
196                 // Return the current position
197                 return $found;
198         }
199
200         /**
201          * Checks wether the given variable stack is set
202          *
203          * @param       $stack  Variable stack to check
204          * @return      $isSet  Wether the given variable stack is set
205          */
206         protected final function isVarStackSet ($stack) {
207                 // Check it
208                 $isSet = isset($this->varStack[$stack]);
209
210                 // Return result
211                 return $isSet;
212         }
213
214         /**
215          * Getter for given variable stack
216          *
217          * @param       $stack          Variable stack to check
218          * @return      $varStack       Found variable stack
219          */
220         public final function getVarStack ($stack) {
221                 return $this->varStack[$stack];
222         }
223
224         /**
225          * Setter for given variable stack
226          *
227          * @param       $stack          Variable stack to check
228          * @param       $varStack       Variable stack to check
229          * @return      void
230          */
231         protected final function setVarStack ($stack, array $varStack) {
232                 $this->varStack[$stack]  = $varStack;
233         }
234
235         /**
236          * Return a content of a variable or null if not found
237          *
238          * @param       $var            The variable we are looking for
239          * @param       $stack          Optional variable stack to look in
240          * @return      $content        Content of the variable or null if not found
241          */
242         protected function readVariable ($var, $stack = null) {
243                 // First everything is not found
244                 $content = null;
245
246                 // If the stack is null, use the current group
247                 if (is_null($stack)) $stack = $this->currGroup;
248
249                 // Get variable index
250                 $found = $this->getVariableIndex($var, $stack);
251
252                 // Is the variable found?
253                 if ($found !== false) {
254                         // Read it
255                         $content = $this->getVariableValue($stack, $found);
256                 } // END - if
257
258                 // Return the current position
259                 //* DEBUG: */ echo __METHOD__.": group=".$stack.",var=".$var.", content[".gettype($content)."]=".$content."<br />\n";
260                 return $content;
261         }
262
263         /**
264          * Add a variable to the stack
265          *
266          * @param       $var    The variable we are looking for
267          * @param       $value  The value we want to store in the variable
268          * @return      void
269          */
270         private function addVariable ($var, $value) {
271                 // Set general variable group
272                 $this->setVariableGroup('general');
273
274                 // Add it to the stack
275                 $this->addGroupVariable($var, $value);
276         }
277
278         /**
279          * Returns all variables of current group or empty array
280          *
281          * @return      $result         Wether array of found variables or empty array
282          */
283         private function readCurrentGroup () {
284                 // Default is not found
285                 $result = array();
286
287                 // Is the group there?
288                 if ($this->isVarStackSet($this->currGroup)) {
289                         // Then use it
290                         $result = $this->getVarStack($this->currGroup);
291                 } // END - if
292
293                 // Return result
294                 return $result;
295         }
296
297         /**
298          * Settter for variable group
299          *
300          * @param       $groupName      Name of variable group
301          * @param       $add            Wether add this group
302          * @return      void
303          */
304         public function setVariableGroup ($groupName, $add = true) {
305                 // Set group name
306                 //* DEBIG: */ echo __METHOD__.": currGroup=".$groupName."<br />\n";
307                 $this->currGroup = $groupName;
308
309                 // Skip group 'general'
310                 if (($groupName != 'general') && ($add === true)) {
311                         $this->varGroups[$groupName] = 'OK';
312                 } // END - if
313         }
314
315
316         /**
317          * Adds a variable to current group
318          *
319          * @param       $var    Variable to set
320          * @param       $value  Value to store in variable
321          * @return      void
322          */
323         public function addGroupVariable ($var, $value) {
324                 //* DEBUG: */ echo __METHOD__.": group=".$this->currGroup.", var=".$var.", value=".$value."<br />\n";
325
326                 // Get current variables in group
327                 $currVars = $this->readCurrentGroup();
328
329                 // Append our variable
330                 $currVars[] = $this->generateVariableArray($var, $value);
331
332                 // Add it to the stack
333                 $this->setVarStack($this->currGroup, $currVars);
334         }
335
336         /**
337          * Getter for variable value, throws a NoVariableException if the variable is not found
338          *
339          * @param       $varGroup       Variable group to use
340          * @param       $index          Index in variable array
341          * @return      $value          Value to set
342          */
343         private function getVariableValue ($varGroup, $index) {
344                 // Return it
345                 return $this->varStack[$varGroup][$index]['value'];
346         }
347
348         /**
349          * Modify an entry on the stack
350          *
351          * @param       $var    The variable we are looking for
352          * @param       $value  The value we want to store in the variable
353          * @return      void
354          * @throws      NoVariableException     If the given variable is not found
355          */
356         private function modifyVariable ($var, $value) {
357                 // Get index for variable
358                 $index = $this->getVariableIndex($var);
359
360                 // Is the variable set?
361                 if ($index === false) {
362                         // Unset variables cannot be modified
363                         throw new NoVariableException(array($this, $var, $value), self::EXCEPTION_VARIABLE_IS_MISSING);
364                 } // END - if
365
366                 // Then modify it
367                 $this->setVariableValue($this->currGroup, $index, $value);
368         }
369
370         /**
371          * Sets a variable value for given variable group and index
372          *
373          * @param       $varGroup       Variable group to use
374          * @param       $index          Index in variable array
375          * @param       $value          Value to set
376          * @return      void
377          */
378         private function setVariableValue ($varGroup, $index, $value) {
379                 $this->varStack[$varGroup][$index]['value'] = $value;
380         }
381
382         /**
383          * Sets a variable within given group. This method does detect if the
384          * variable is already set. If so, the variable got modified, otherwise
385          * added.
386          *
387          * @param       $varGroup       Variable group to use
388          * @param       $var            Variable to set
389          * @param       $value          Value to set
390          * @return      void
391          */
392         protected function setVariable ($varGroup, $var, $value) {
393                 // Get index for variable
394                 $index = $this->getVariableIndex($var);
395
396                 // Is the variable set?
397                 if ($index === false) {
398                         // Not found, add it
399                         $this->varStack[$varGroup][] = $this->generateVariableArray($var, $value);
400                 } else {
401                         // Then modify it
402                         $this->setVariableValue($this->currGroup, $index, $value);
403                 }
404         }
405
406         /**
407          * "Generates" (better returns) an array for all variables for given
408          * variable/value pay.
409          *
410          * @param       $var            Variable to set
411          * @param       $value          Value to set
412          * @return      $varData        Variable data array
413          */
414         private function generateVariableArray ($var, $value) {
415                 // Generate the temporary array
416                 $varData = array(
417                         'name'  => $var,
418                         'value' => $value
419                 );
420
421                 // And return it
422                 return $varData;
423         }
424
425         /**
426          * Setter for template type. Only 'html', 'emails' and 'compiled' should
427          * be sent here
428          *
429          * @param       $templateType   The current template's type
430          * @return      void
431          */
432         protected final function setTemplateType ($templateType) {
433                 $this->templateType = (string) $templateType;
434         }
435
436         /**
437          * Setter for the last loaded template's FQFN
438          *
439          * @param       $template       The last loaded template
440          * @return      void
441          */
442         private final function setLastTemplate ($template) {
443                 $this->lastTemplate = (string) $template;
444         }
445
446         /**
447          * Getter for the last loaded template's FQFN
448          *
449          * @return      $template       The last loaded template
450          */
451         private final function getLastTemplate () {
452                 return $this->lastTemplate;
453         }
454
455         /**
456          * Setter for base path
457          *
458          * @param               $templateBasePath               The relative base path for all templates
459          * @return      void
460          */
461         public final function setTemplateBasePath ($templateBasePath) {
462                 // And set it
463                 $this->templateBasePath = (string) $templateBasePath;
464         }
465
466         /**
467          * Getter for base path
468          *
469          * @return      $templateBasePath               The relative base path for all templates
470          */
471         public final function getTemplateBasePath () {
472                 // And set it
473                 return $this->templateBasePath;
474         }
475
476         /**
477          * Getter for generic base path
478          *
479          * @return      $templateBasePath               The relative base path for all templates
480          */
481         public final function getGenericBasePath () {
482                 // And set it
483                 return $this->genericBasePath;
484         }
485
486         /**
487          * Setter for template extension
488          *
489          * @param               $templateExtension      The file extension for all uncompiled
490          *                                                      templates
491          * @return      void
492          */
493         public final function setRawTemplateExtension ($templateExtension) {
494                 // And set it
495                 $this->templateExtension = (string) $templateExtension;
496         }
497
498         /**
499          * Setter for code template extension
500          *
501          * @param               $codeExtension          The file extension for all uncompiled
502          *                                                      templates
503          * @return      void
504          */
505         public final function setCodeTemplateExtension ($codeExtension) {
506                 // And set it
507                 $this->codeExtension = (string) $codeExtension;
508         }
509
510         /**
511          * Getter for template extension
512          *
513          * @return      $templateExtension      The file extension for all uncompiled
514          *                                                      templates
515          */
516         public final function getRawTemplateExtension () {
517                 // And set it
518                 return $this->templateExtension;
519         }
520
521         /**
522          * Getter for code-template extension
523          *
524          * @return      $codeExtension          The file extension for all code-
525          *                                                      templates
526          */
527         public final function getCodeTemplateExtension () {
528                 // And set it
529                 return $this->codeExtension;
530         }
531
532         /**
533          * Setter for path of compiled templates
534          *
535          * @param       $compileOutputPath      The local base path for all compiled
536          *                                                              templates
537          * @return      void
538          */
539         public final function setCompileOutputPath ($compileOutputPath) {
540                 // And set it
541                 $this->compileOutputPath = (string) $compileOutputPath;
542         }
543
544         /**
545          * Getter for template type
546          *
547          * @return      $templateType   The current template's type
548          */
549         public final function getTemplateType () {
550                 return $this->templateType;
551         }
552
553         /**
554          * Assign (add) a given variable with a value
555          *
556          * @param       $var    The variable we are looking for
557          * @param       $value  The value we want to store in the variable
558          * @return      void
559          * @throws      EmptyVariableException  If the variable name is left empty
560          */
561         public final function assignVariable ($var, $value) {
562                 // Trim spaces of variable name
563                 $var = trim($var);
564
565                 // Empty variable found?
566                 if (empty($var)) {
567                         // Throw an exception
568                         throw new EmptyVariableException(array($this, 'var'), self::EXCEPTION_UNEXPECTED_EMPTY_STRING);
569                 } // END - if
570
571                 // First search for the variable if it was already added
572                 $index = $this->getVariableIndex($var);
573
574                 // Was it found?
575                 if ($index === false) {
576                         // Add it to the stack
577                         //* DEBUG: */ echo "ADD: ".$var."<br />\n";
578                         $this->addVariable($var, $value);
579                 } elseif (!empty($value)) {
580                         // Modify the stack entry
581                         //* DEBUG: */ echo "MOD: ".$var."<br />\n";
582                         $this->modifyVariable($var, $value);
583                 }
584         }
585
586         /**
587          * Removes a given variable
588          *
589          * @param       $var    The variable we are looking for
590          * @return      void
591          */
592         public final function removeVariable ($var) {
593                 // First search for the variable if it was already added
594                 $index = $this->getVariableIndex($var);
595
596                 // Was it found?
597                 if ($index !== false) {
598                         // Remove this variable
599                         $this->unsetVariableStackOffset($index);
600                 } // END - if
601         }
602
603         /**
604          * Unsets the given offset in the variable stack
605          *
606          * @param       $index  Index to unset
607          * @return      void
608          */
609         protected final function unsetVariableStackOffset ($index) {
610                 // Is the entry there?
611                 if (!isset($this->varStack[$this->currGroup][$index])) {
612                         // Abort here, we need fixing!
613                         $this->debugInstance();
614                 } // END - if
615
616                 // Remove it
617                 unset($this->varStack[$this->currGroup][$index]);
618         }
619
620         /**
621          * Private setter for raw template data
622          *
623          * @param       $rawTemplateData        The raw data from the template
624          * @return      void
625          */
626         protected final function setRawTemplateData ($rawTemplateData) {
627                 // And store it in this class
628                 //* DEBUG: */ echo __METHOD__.':'.$this->getUniqueId().': '.strlen($rawTemplateData).' Bytes set.<br />\n';
629                 //* DEBUG: */ echo $this->currGroup.' variables: '.count($this->getVarStack($this->currGroup)).', groups='.count($this->varStack).'<br />\n';
630                 $this->rawTemplateData = (string) $rawTemplateData;
631         }
632
633         /**
634          * Getter for raw template data
635          *
636          * @return      $rawTemplateData        The raw data from the template
637          */
638         public final function getRawTemplateData () {
639                 //* DEBUG: */ echo __METHOD__.':'.$this->getUniqueId().': '.strlen($this->rawTemplateData).' Bytes read.<br />\n';
640                 return $this->rawTemplateData;
641         }
642
643         /**
644          * Private setter for compiled templates
645          *
646          * @return      void
647          */
648         private final function setCompiledData ($compiledData) {
649                 // And store it in this class
650                 //* DEBUG: */ echo __METHOD__.':'.$this->getUniqueId().': '.strlen($compiledData).' Bytes set.<br />\n';
651                 $this->compiledData = (string) $compiledData;
652         }
653
654         /**
655          * Getter for compiled templates
656          *
657          * @return      $compiledData   Compiled template data
658          */
659         public final function getCompiledData () {
660                 //* DEBUG: */ echo __METHOD__.':'.$this->getUniqueId().': '.strlen($this->compiledData).' Bytes read.<br />\n';
661                 return $this->compiledData;
662         }
663
664         /**
665          * Private loader for all template types
666          *
667          * @param       $template       The template we shall load
668          * @param       $extOther       An other extension to use
669          * @return      void
670          * @throws      FileIoException If the template was not found
671          */
672         protected function loadTemplate ($template, $extOther = '') {
673                 // Get extension for the template if empty
674                 if (empty($extOther)) {
675                         // None provided, so get the raw one
676                         $ext = $this->getRawTemplateExtension();
677                 } else {
678                         // Then use it!
679                         $ext = (string) $extOther;
680                 }
681
682                 // Is language support enabled?
683                 if ($this->isLanguageSupportEnabled()) {
684                         // Construct the FQFN for the template by honoring the current language
685                         $fqfn = sprintf("%s%s%s%s/%s/%s%s",
686                                 $this->getConfigInstance()->getConfigEntry('base_path'),
687                                 $this->getTemplateBasePath(),
688                                 $this->getGenericBasePath(),
689                                 $this->getLanguageInstance()->getLanguageCode(),
690                                 $this->getTemplateType(),
691                                 (string) $template,
692                                 $ext
693                         );
694                 } else {
695                         // Construct the FQFN for the template without language
696                         $fqfn = sprintf("%s%s%s%s/%s%s",
697                                 $this->getConfigInstance()->getConfigEntry('base_path'),
698                                 $this->getTemplateBasePath(),
699                                 $this->getGenericBasePath(),
700                                 $this->getTemplateType(),
701                                 (string) $template,
702                                 $ext
703                         );
704                 }
705
706                 // First try this
707                 try {
708                         // Load the raw template data
709                         $this->loadRawTemplateData($fqfn);
710                 } catch (FileIoException $e) {
711                         // If we shall load a code-template we need to switch the file extension
712                         if (($this->getTemplateType() != $this->getConfigInstance()->getConfigEntry('web_template_type')) && (empty($extOther))) {
713                                 // Switch over to the code-template extension and try it again
714                                 $ext = $this->getCodeTemplateExtension();
715
716                                 // Try it again...
717                                 $this->loadTemplate($template, $ext);
718                         } else {
719                                 // Throw it again
720                                 throw new FileIoException($fqfn, FrameworkFileInputPointer::EXCEPTION_FILE_NOT_FOUND);
721                         }
722                 }
723
724         }
725
726         /**
727          * A private loader for raw template names
728          *
729          * @param       $fqfn   The full-qualified file name for a template
730          * @return      void
731          */
732         private function loadRawTemplateData ($fqfn) {
733                 // Get a input/output instance from the middleware
734                 $ioInstance = $this->getFileIoInstance();
735
736                 // Some debug code to look on the file which is being loaded
737                 //* DEBUG: */ echo __METHOD__.": FQFN=".$fqfn."<br />\n";
738
739                 // Load the raw template
740                 $rawTemplateData = $ioInstance->loadFileContents($fqfn);
741
742                 // Store the template's contents into this class
743                 $this->setRawTemplateData($rawTemplateData);
744
745                 // Remember the template's FQFN
746                 $this->setLastTemplate($fqfn);
747         }
748
749         /**
750          * Try to assign an extracted template variable as a "content" or 'config'
751          * variable.
752          *
753          * @param       $varName        The variable's name (shall be content orconfig) by
754          *                                              default
755          * @param       $var            The variable we want to assign
756          */
757         private function assignTemplateVariable ($varName, $var) {
758                 // Is it not a config variable?
759                 if ($varName != 'config') {
760                         // Regular template variables
761                         $this->assignVariable($var, '');
762                 } else {
763                         // Configuration variables
764                         $this->assignConfigVariable($var);
765                 }
766         }
767
768         /**
769          * Extract variables from a given raw data stream
770          *
771          * @param       $rawData        The raw template data we shall analyze
772          * @return      void
773          */
774         private function extractVariablesFromRawData ($rawData) {
775                 // Cast to string
776                 $rawData = (string) $rawData;
777
778                 // Search for variables
779                 @preg_match_all('/\$(\w+)(\[(\w+)\])?/', $rawData, $variableMatches);
780
781                 // Did we find some variables?
782                 if ((is_array($variableMatches)) && (count($variableMatches) == 4) && (count($variableMatches[0]) > 0)) {
783                         // Initialize all missing variables
784                         foreach ($variableMatches[3] as $key => $var) {
785                                 // Variable name
786                                 $varName = $variableMatches[1][$key];
787
788                                 // Workarround: Do not assign empty variables
789                                 if (!empty($var)) {
790                                         // Try to assign it, empty strings are being ignored
791                                         $this->assignTemplateVariable($varName, $var);
792                                 } // END - if
793                         } // END - foreach
794                 } // END - if
795         }
796
797         /**
798          * Main analysis of the loaded template
799          *
800          * @param       $templateMatches        Found template place-holders, see below
801          * @return      void
802          *
803          *---------------------------------
804          * Structure of $templateMatches:
805          *---------------------------------
806          * [0] => Array - An array with all full matches
807          * [1] => Array - An array with left part (before the ':') of a match
808          * [2] => Array - An array with right part of a match including ':'
809          * [3] => Array - An array with right part of a match excluding ':'
810          */
811         private function analyzeTemplate (array $templateMatches) {
812                 // Backup raw template data
813                 $backup = $this->getRawTemplateData();
814
815                 // Initialize some arrays
816                 if (is_null($this->loadedRawData)) { $this->loadedRawData = array(); $this->rawTemplates = array(); }
817
818                 // Load all requested templates
819                 foreach ($templateMatches[1] as $template) {
820
821                         // Load and compile only templates which we have not yet loaded
822                         // RECURSIVE PROTECTION! BE CAREFUL HERE!
823                         if ((!isset($this->loadedRawData[$template])) && (!in_array($template, $this->loadedTemplates))) {
824
825                                 // Template not found, but maybe variable assigned?
826                                 //* DEBUG: */ echo __METHOD__.":template={$template}<br />\n";
827                                 if ($this->getVariableIndex($template) !== false) {
828                                         // Use that content here
829                                         $this->loadedRawData[$template] = $this->readVariable($template);
830
831                                         // Recursive protection:
832                                         $this->loadedTemplates[] = $template;
833                                 } elseif ($this->getVariableIndex($template, 'config')) {
834                                         // Use that content here
835                                         $this->loadedRawData[$template] = $this->readVariable($template, 'config');
836
837                                         // Recursive protection:
838                                         $this->loadedTemplates[] = $template;
839                                 } else {
840                                         // Then try to search for code-templates
841                                         try {
842                                                 // Load the code template and remember it's contents
843                                                 $this->loadCodeTemplate($template);
844                                                 $this->loadedRawData[$template] = $this->getRawTemplateData();
845
846                                                 // Remember this template for recursion detection
847                                                 // RECURSIVE PROTECTION!
848                                                 $this->loadedTemplates[] = $template;
849                                         } catch (FileIoException $e) {
850                                                 // Even this is not done... :/
851                                                 $this->rawTemplates[] = $template;
852                                         }
853                                 }
854                         } // END - if
855                 } // END - foreach
856
857                 // Restore the raw template data
858                 $this->setRawTemplateData($backup);
859         }
860
861         /**
862          * Compile a given raw template code and remember it for later usage
863          *
864          * @param       $code           The raw template code
865          * @param       $template       The template's name
866          * @return      void
867          */
868         private function compileCode ($code, $template) {
869                 // Is this template already compiled?
870                 if (in_array($template, $this->compiledTemplates)) {
871                         // Abort here...
872                         return;
873                 } // END - if
874
875                 // Remember this template being compiled
876                 $this->compiledTemplates[] = $template;
877
878                 // Compile the loaded code in five steps:
879                 //
880                 // 1. Backup current template data
881                 $backup = $this->getRawTemplateData();
882
883                 // 2. Set the current template's raw data as the new content
884                 $this->setRawTemplateData($code);
885
886                 // 3. Compile the template data
887                 $this->compileTemplate();
888
889                 // 4. Remember it's contents
890                 $this->loadedRawData[$template] = $this->getRawTemplateData();
891
892                 // 5. Restore the previous raw content from backup variable
893                 $this->setRawTemplateData($backup);
894         }
895
896         /**
897          * Insert all given and loaded templates by running through all loaded
898          * codes and searching for their place-holder in the main template
899          *
900          * @param       $templateMatches        See method analyzeTemplate()
901          * @return      void
902          */
903         private function insertAllTemplates (array $templateMatches) {
904                 // Run through all loaded codes
905                 foreach ($this->loadedRawData as $template => $code) {
906
907                         // Search for the template
908                         $foundIndex = array_search($template, $templateMatches[1]);
909
910                         // Lookup the matching template replacement
911                         if (($foundIndex !== false) && (isset($templateMatches[0][$foundIndex]))) {
912
913                                 // Get the current raw template
914                                 $rawData = $this->getRawTemplateData();
915
916                                 // Replace the space holder with the template code
917                                 $rawData = str_replace($templateMatches[0][$foundIndex], $code, $rawData);
918
919                                 // Set the new raw data
920                                 $this->setRawTemplateData($rawData);
921                         } // END - if
922                 } // END - foreach
923         }
924
925         /**
926          * Load all extra raw templates
927          *
928          * @return      void
929          */
930         private function loadExtraRawTemplates () {
931                 // Are there some raw templates we need to load?
932                 if (count($this->rawTemplates) > 0) {
933                         // Try to load all raw templates
934                         foreach ($this->rawTemplates as $key => $template) {
935                                 try {
936                                         // Load the template
937                                         $this->loadWebTemplate($template);
938
939                                         // Remember it's contents
940                                         $this->rawTemplates[$template] = $this->getRawTemplateData();
941
942                                         // Remove it from the loader list
943                                         unset($this->rawTemplates[$key]);
944
945                                         // Remember this template for recursion detection
946                                         // RECURSIVE PROTECTION!
947                                         $this->loadedTemplates[] = $template;
948                                 } catch (FileIoException $e) {
949                                         // This template was never found. We silently ignore it
950                                         unset($this->rawTemplates[$key]);
951                                 }
952                         } // END - foreach
953                 } // END - if
954         }
955
956         /**
957          * Assign all found template variables
958          *
959          * @param       $varMatches             An array full of variable/value pairs.
960          * @return      void
961          * @todo        Unfinished work or don't die here.
962          */
963         private function assignAllVariables (array $varMatches) {
964                 // Search for all variables
965                 foreach ($varMatches[1] as $key => $var) {
966
967                         // Detect leading equals
968                         if (substr($varMatches[2][$key], 0, 1) == '=') {
969                                 // Remove and cast it
970                                 $varMatches[2][$key] = (string) substr($varMatches[2][$key], 1);
971                         } // END - if
972
973                         // Do we have some quotes left and right side? Then it is free text
974                         if ((substr($varMatches[2][$key], 0, 1) == "\"") && (substr($varMatches[2][$key], -1, 1) == "\"")) {
975                                 // Free string detected! Which we can assign directly
976                                 $this->assignVariable($var, $varMatches[3][$key]);
977                         } elseif (!empty($varMatches[2][$key])) {
978                                 // @TODO Non-string found so we need some deeper analysis...
979                                 ApplicationEntryPoint::app_die('Deeper analysis not yet implemented!');
980                         }
981
982                 } // for ($varMatches ...
983         }
984
985         /**
986          * Compiles all loaded raw templates
987          *
988          * @param       $templateMatches        See method analyzeTemplate() for details
989          * @return      void
990          */
991         private function compileRawTemplateData (array $templateMatches) {
992                 // Are some code-templates found which we need to compile?
993                 if (count($this->loadedRawData) > 0) {
994
995                         // Then compile all!
996                         foreach ($this->loadedRawData as $template => $code) {
997
998                                 // Is this template already compiled?
999                                 if (in_array($template, $this->compiledTemplates)) {
1000                                         // Then skip it
1001                                         continue;
1002                                 }
1003
1004                                 // Search for the template
1005                                 $foundIndex = array_search($template, $templateMatches[1]);
1006
1007                                 // Lookup the matching variable data
1008                                 if (($foundIndex !== false) && (isset($templateMatches[3][$foundIndex]))) {
1009
1010                                         // Split it up with another reg. exp. into variable=value pairs
1011                                         preg_match_all($this->regExpVarValue, $templateMatches[3][$foundIndex], $varMatches);
1012
1013                                         // Assign all variables
1014                                         $this->assignAllVariables($varMatches);
1015
1016                                 } // END - if (isset($templateMatches ...
1017
1018                                 // Compile the loaded template
1019                                 $this->compileCode($code, $template);
1020
1021                         } // END - foreach ($this->loadedRawData ...
1022
1023                         // Insert all templates
1024                         $this->insertAllTemplates($templateMatches);
1025
1026                 } // END - if (count($this->loadedRawData) ...
1027         }
1028
1029         /**
1030          * Inserts all raw templates into their respective variables
1031          *
1032          * @return      void
1033          */
1034         private function insertRawTemplates () {
1035                 // Load all templates
1036                 foreach ($this->rawTemplates as $template => $content) {
1037                         // Set the template as a variable with the content
1038                         $this->assignVariable($template, $content);
1039                 }
1040         }
1041
1042         /**
1043          * Finalizes the compilation of all template variables
1044          *
1045          * @return      void
1046          */
1047         private function finalizeVariableCompilation () {
1048                 // Get the content
1049                 $content = $this->getRawTemplateData();
1050                 //* DEBUG: */ echo __METHOD__.': content before='.strlen($content).' ('.md5($content).')<br />\n';
1051
1052                 // Do we have the stack?
1053                 if (!$this->isVarStackSet('general')) {
1054                         // Abort here silently
1055                         // @TODO This silent abort should be logged, maybe.
1056                         return;
1057                 } // END - if
1058
1059                 // Walk through all variables
1060                 foreach ($this->getVarStack('general') as $currEntry) {
1061                         //* DEBUG: */ echo __METHOD__.': name='.$currEntry['name'].', value=<pre>'.htmlentities($currEntry['value']).'</pre>\n';
1062                         // Replace all [$var] or {?$var?} with the content
1063                         // @TODO Old behaviour, will become obsolete!
1064                         $content = str_replace('$content[' . $currEntry['name'] . ']', $currEntry['value'], $content);
1065
1066                         // @TODO Yet another old way
1067                         $content = str_replace('[' . $currEntry['name'] . ']', $currEntry['value'], $content);
1068
1069                         // The new behaviour
1070                         $content = str_replace('{?' . $currEntry['name'] . '?}', $currEntry['value'], $content);
1071                 } // END - for
1072
1073                 //* DEBUG: */ echo __METHOD__.': content after='.strlen($content).' ('.md5($content).')<br />\n';
1074
1075                 // Set the content back
1076                 $this->setRawTemplateData($content);
1077         }
1078
1079         /**
1080          * Load a specified web template into the engine
1081          *
1082          * @param       $template       The web template we shall load which is located in
1083          *                                              'html' by default
1084          * @return      void
1085          */
1086         public function loadWebTemplate ($template) {
1087                 // Set template type
1088                 $this->setTemplateType($this->getConfigInstance()->getConfigEntry('web_template_type'));
1089
1090                 // Load the special template
1091                 $this->loadTemplate($template);
1092         }
1093
1094         /**
1095          * Assign a given congfiguration variable with a value
1096          *
1097          * @param       $var    The configuration variable we want to assign
1098          * @return      void
1099          */
1100         public function assignConfigVariable ($var) {
1101                 // Sweet and simple...
1102                 //* DEBUG: */ echo __METHOD__.':var={$var}<br />\n';
1103                 $this->setVariable('config', $var, $this->getConfigInstance()->getConfigEntry($var));
1104         }
1105
1106         /**
1107          * Load a specified code template into the engine
1108          *
1109          * @param       $template       The code template we shall load which is
1110          *                                              located in 'code' by default
1111          * @return      void
1112          */
1113         public function loadCodeTemplate ($template) {
1114                 // Set template type
1115                 $this->setTemplateType($this->getConfigInstance()->getConfigEntry('code_template_type'));
1116
1117                 // Load the special template
1118                 $this->loadTemplate($template);
1119         }
1120
1121         /**
1122          * Compiles configuration place-holders in all variables. This 'walks'
1123          * through the variable stack 'general'. It interprets all values from that
1124          * variables as configuration entries after compiling them.
1125          *
1126          * @return      void
1127          */
1128         public final function compileConfigInVariables () {
1129                 // Do we have the stack?
1130                 if (!$this->isVarStackSet('general')) {
1131                         // Abort here silently
1132                         // @TODO This silent abort should be logged, maybe.
1133                         return;
1134                 } // END - if
1135
1136                 // Iterate through all general variables
1137                 foreach ($this->getVarStack('general') as $index=>$currVariable) {
1138                         // Compile the value
1139                         $value = $this->compileRawCode($this->readVariable($currVariable['name']), true);
1140
1141                         // Remove it from stack
1142                         $this->removeVariable($index, 'general');
1143
1144                         // Re-assign the variable
1145                         $this->assignConfigVariable($value);
1146                 } // END - foreach
1147         }
1148
1149         /**
1150          * Compile all variables by inserting their respective values
1151          *
1152          * @return      void
1153          * @todo        Make this code some nicer...
1154          */
1155         public final function compileVariables () {
1156                 // Initialize the $content array
1157                 $validVar = $this->getConfigInstance()->getConfigEntry('tpl_valid_var');
1158                 $dummy = array();
1159
1160                 // Iterate through all general variables
1161                 foreach ($this->getVarStack('general') as $currVariable) {
1162                         // Transfer it's name/value combination to the $content array
1163                         //* DEBUG: */ echo $currVariable['name'].'=<pre>'.htmlentities($currVariable['value']).'</pre>\n';
1164                         $dummy[$currVariable['name']] = $currVariable['value'];
1165                 }// END - if
1166
1167                 // Set the new variable (don't remove the second dollar!)
1168                 $$validVar = $dummy;
1169
1170                 // Prepare all configuration variables
1171                 $config = null;
1172                 if ($this->isVarStackSet('config')) {
1173                         $config = $this->getVarStack('config');
1174                 } // END - if
1175
1176                 // Remove some variables
1177                 unset($index);
1178                 unset($currVariable);
1179
1180                 // Run the compilation three times to get content from helper classes in
1181                 $cnt = 0;
1182                 while ($cnt < 3) {
1183                         // Finalize the compilation of template variables
1184                         $this->finalizeVariableCompilation();
1185
1186                         // Prepare the eval() command for comiling the template
1187                         $eval = sprintf("\$result = \"%s\";",
1188                                 addslashes($this->getRawTemplateData())
1189                         );
1190
1191                         // This loop does remove the backslashes (\) in PHP parameters
1192                         while (strpos($eval, $this->codeBegin) !== false) {
1193                                 // Get left part before "<?"
1194                                 $evalLeft = substr($eval, 0, strpos($eval, $this->codeBegin));
1195
1196                                 // Get all from right of "<?"
1197                                 $evalRight = substr($eval, (strpos($eval, $this->codeBegin) + 5));
1198
1199                                 // Cut middle part out and remove escapes
1200                                 $evalMiddle = trim(substr($evalRight, 0, strpos($evalRight, $this->codeEnd)));
1201                                 $evalMiddle = stripslashes($evalMiddle);
1202
1203                                 // Remove the middle part from right one
1204                                 $evalRight = substr($evalRight, (strpos($evalRight, $this->codeEnd) + 2));
1205
1206                                 // And put all together
1207                                 $eval = sprintf("%s<%%php %s %%>%s", $evalLeft, $evalMiddle, $evalRight);
1208                         } // END - while
1209
1210                         // Prepare PHP code for eval() command
1211                         $eval = str_replace(
1212                                 "<%php", "\";",
1213                                 str_replace(
1214                                         "%>",
1215                                         "\n\$result .= \"",
1216                                         $eval
1217                                 )
1218                         );
1219
1220                         // Run the constructed command. This will "compile" all variables in
1221                         eval($eval);
1222
1223                         // Goes something wrong?
1224                         if ((!isset($result)) || (empty($result))) {
1225                                 // Output eval command
1226                                 $this->debugOutput(sprintf("Failed eval() code: <pre>%s</pre>", $this->markupCode($eval, true)), true);
1227
1228                                 // Output backtrace here
1229                                 $this->debugBackTrace();
1230                         } // END - if
1231
1232                         // Set raw template data
1233                         $this->setRawTemplateData($result);
1234                         $cnt++;
1235                 } // END - while
1236
1237                 // Final variable assignment
1238                 $this->finalizeVariableCompilation();
1239
1240                 // Set the new content
1241                 $this->setCompiledData($this->getRawTemplateData());
1242         }
1243
1244         /**
1245          * Compile all required templates into the current loaded one
1246          *
1247          * @return      void
1248          * @throws      UnexpectedTemplateTypeException If the template type is
1249          *                                                                                      not "code"
1250          * @throws      InvalidArrayCountException              If an unexpected array
1251          *                                                                                      count has been found
1252          */
1253         public function compileTemplate () {
1254                 // Get code type to make things shorter
1255                 $codeType = $this->getConfigInstance()->getConfigEntry('code_template_type');
1256
1257                 // We will only work with template type "code" from configuration
1258                 if (substr($this->getTemplateType(), 0, strlen($codeType)) != $codeType) {
1259                         // Abort here
1260                         throw new UnexpectedTemplateTypeException(array($this, $this->getTemplateType(), $this->getConfigInstance()->getConfigEntry('code_template_type')), self::EXCEPTION_TEMPLATE_TYPE_IS_UNEXPECTED);
1261                 } // END - if
1262
1263                 // Get the raw data.
1264                 $rawData = $this->getRawTemplateData();
1265
1266                 // Remove double spaces and trim leading/trailing spaces
1267                 $rawData = trim(str_replace('  ', ' ', $rawData));
1268
1269                 // Search for raw variables
1270                 $this->extractVariablesFromRawData($rawData);
1271
1272                 // Search for code-tags which are {? ?}
1273                 preg_match_all($this->regExpCodeTags, $rawData, $templateMatches);
1274
1275                 // Analyze the matches array
1276                 if ((is_array($templateMatches)) && (count($templateMatches) == 4) && (count($templateMatches[0]) > 0)) {
1277                         // Entries are found:
1278                         //
1279                         // The main analysis
1280                         $this->analyzeTemplate($templateMatches);
1281
1282                         // Compile raw template data
1283                         $this->compileRawTemplateData($templateMatches);
1284
1285                         // Are there some raw templates left for loading?
1286                         $this->loadExtraRawTemplates();
1287
1288                         // Are some raw templates found and loaded?
1289                         if (count($this->rawTemplates) > 0) {
1290
1291                                 // Insert all raw templates
1292                                 $this->insertRawTemplates();
1293
1294                                 // Remove the raw template content as well
1295                                 $this->setRawTemplateData('');
1296
1297                         } // END - if
1298
1299                 } // END - if($templateMatches ...
1300         }
1301
1302         /**
1303          * Loads a given view helper (by name)
1304          *
1305          * @param       $helperName             The helper's name
1306          * @return      void
1307          */
1308         protected function loadViewHelper ($helperName) {
1309                 // Make first character upper case, rest low
1310                 $helperName = $this->convertToClassName($helperName);
1311
1312                 // Is this view helper loaded?
1313                 if (!isset($this->helpers[$helperName])) {
1314                         // Create a class name
1315                         $className = "{$helperName}ViewHelper";
1316
1317                         // Generate new instance
1318                         $this->helpers[$helperName] = ObjectFactory::createObjectByName($className);
1319                 } // END - if
1320
1321                 // Return the requested instance
1322                 return $this->helpers[$helperName];
1323         }
1324
1325         /**
1326          * Assigns the last loaded raw template content with a given variable
1327          *
1328          * @param       $templateName   Name of the template we want to assign
1329          * @param       $variableName   Name of the variable we want to assign
1330          * @return      void
1331          */
1332         public function assignTemplateWithVariable ($templateName, $variableName) {
1333                 // Get the content from last loaded raw template
1334                 $content = $this->getRawTemplateData();
1335
1336                 // Assign the variable
1337                 $this->assignVariable($variableName, $content);
1338
1339                 // Purge raw content
1340                 $this->setRawTemplateData('');
1341         }
1342
1343         /**
1344          * Transfers the content of this template engine to a given response instance
1345          *
1346          * @param       $responseInstance       An instance of a response class
1347          * @return      void
1348          */
1349         public function transferToResponse (Responseable $responseInstance) {
1350                 // Get the content and set it in response class
1351                 $responseInstance->writeToBody($this->getCompiledData());
1352         }
1353
1354         /**
1355          * Assigns all the application data with template variables
1356          *
1357          * @param       $applicationInstance    A manageable application instance
1358          * @return      void
1359          */
1360         public function assignApplicationData (ManageableApplication $applicationInstance) {
1361                 // Get long name and assign it
1362                 $this->assignVariable('app_full_name' , $applicationInstance->getAppName());
1363
1364                 // Get short name and assign it
1365                 $this->assignVariable('app_short_name', $applicationInstance->getAppShortName());
1366
1367                 // Get version number and assign it
1368                 $this->assignVariable('app_version'   , $applicationInstance->getAppVersion());
1369
1370                 // Assign extra application-depending data
1371                 $applicationInstance->assignExtraTemplateData($this);
1372         }
1373
1374         /**
1375          * "Compiles" a variable by replacing {?var?} with it's content
1376          *
1377          * @param       $rawCode                        Raw code to compile
1378          * @param       $setMatchAsCode         Sets $match if readVariable() returns empty result
1379          * @return      $rawCode        Compile code with inserted variable value
1380          */
1381         public function compileRawCode ($rawCode, $setMatchAsCode=false) {
1382                 // Find the variables
1383                 //* DEBUG: */ echo __METHOD__.":rawCode=<pre>".htmlentities($rawCode)."</pre>\n";
1384                 preg_match_all($this->regExpVarValue, $rawCode, $varMatches);
1385
1386                 // Compile all variables
1387                 //* DEBUG: */ echo __METHOD__.":<pre>".print_r($varMatches, true)."</pre>\n";
1388                 foreach ($varMatches[0] as $match) {
1389                         // Add variable tags around it
1390                         $varCode = '{?' . $match . '?}';
1391
1392                         // Is the variable found in code? (safes some calls)
1393                         if (strpos($rawCode, $varCode) !== false) {
1394                                 // Replace the variable with it's value, if found
1395                                 $value = $this->readVariable($match);
1396                                 //* DEBUG: */ echo __METHOD__.": match=".$match.",value[".gettype($value)."]=".$value."<br />\n";
1397                                 if (($setMatchAsCode === true) && (is_null($value))) {
1398                                         // Insert match
1399                                         $rawCode = str_replace($varCode, $match, $rawCode);
1400                                 } else {
1401                                         // Insert value
1402                                         $rawCode = str_replace($varCode, $value, $rawCode);
1403                                 }
1404                         } // END - if
1405                 } // END - foreach
1406
1407                 // Return the compiled data
1408                 //* DEBUG: */ echo __METHOD__.":rawCode=<pre>".htmlentities($rawCode)."</pre>\n";
1409                 return $rawCode;
1410         }
1411
1412         /**
1413          * Getter for variable group array
1414          *
1415          * @return      $vargroups      All variable groups
1416          */
1417         public final function getVariableGroups () {
1418                 return $this->varGroups;
1419         }
1420
1421         /**
1422          * Renames a variable in code and in stack
1423          *
1424          * @param       $oldName        Old name of variable
1425          * @param       $newName        New name of variable
1426          * @return      void
1427          */
1428         public function renameVariable ($oldName, $newName) {
1429                 //* DEBUG: */ echo __METHOD__.": oldName={$oldName}, newName={$newName}<br />\n";
1430                 // Get raw template code
1431                 $rawData = $this->getRawTemplateData();
1432
1433                 // Replace it
1434                 $rawData = str_replace($oldName, $newName, $rawData);
1435
1436                 // Set the code back
1437                 $this->setRawTemplateData($rawData);
1438         }
1439
1440         /**
1441          * Renders the given XML content
1442          *
1443          * @param       $content        Valid XML content or if not set the current loaded raw content
1444          * @return      void
1445          * @throws      XmlParserException      If an XML error was found
1446          */
1447         public function renderXmlContent ($content = null) {
1448                 // Is the content set?
1449                 if (is_null($content)) {
1450                         // Get current content
1451                         $content = $this->getRawTemplateData();
1452                 } // END - if
1453
1454                 // Get a XmlParser instance
1455                 $parserInstance = ObjectFactory::createObjectByConfiguredName('xml_parser_class', array($this));
1456
1457                 // Check if we have XML compacting enabled
1458                 if ($this->isXmlCompactingEnabled()) {
1459                         // Yes, so get a decorator class for transparent compacting
1460                         $parserInstance = ObjectFactory::createObjectByConfiguredName('deco_compacting_xml_parser_class', array($parserInstance));
1461                 } // END - if
1462
1463                 // Parse the XML document
1464                 $parserInstance->parseXmlContent($content);
1465         }
1466
1467         /**
1468          * Enables or disables language support
1469          *
1470          * @param       $languageSupport        New language support setting
1471          * @return      void
1472          */
1473         public final function enableLanguageSupport ($languageSupport = true) {
1474                 $this->languageSupport = (bool) $languageSupport;
1475         }
1476
1477         /**
1478          * Checks wether language support is enabled
1479          *
1480          * @return      $languageSupport        Wether language support is enabled or disabled
1481          */
1482         public final function isLanguageSupportEnabled () {
1483                 return $this->languageSupport;
1484         }
1485
1486         /**
1487          * Enables or disables XML compacting
1488          *
1489          * @param       $xmlCompacting  New XML compacting setting
1490          * @return      void
1491          */
1492         public final function enableXmlCompacting ($xmlCompacting = true) {
1493                 $this->xmlCompacting = (bool) $xmlCompacting;
1494         }
1495
1496         /**
1497          * Checks wether XML compacting is enabled
1498          *
1499          * @return      $xmlCompacting  Wether XML compacting is enabled or disabled
1500          */
1501         public final function isXmlCompactingEnabled () {
1502                 return $this->xmlCompacting;
1503         }
1504
1505         /**
1506          * Removes all commentd, tabs and new-line characters to compact the content
1507          *
1508          * @param       $uncompactedContent             The uncompacted content
1509          * @return      $compactedContent               The compacted content
1510          */
1511         public function compactContent ($uncompactedContent) {
1512                 // First, remove all tab/new-line/revert characters
1513                 $compactedContent = str_replace("\t", '', str_replace("\n", '', str_replace("\r", '', $uncompactedContent)));
1514
1515                 // Then regex all comments like <!-- //--> away
1516                 preg_match_all('/<!--[\w\W]*?(\/\/){0,1}-->/', $compactedContent, $matches);
1517
1518                 // Do we have entries?
1519                 if (isset($matches[0][0])) {
1520                         // Remove all
1521                         foreach ($matches[0] as $match) {
1522                                 // Remove the match
1523                                 $compactedContent = str_replace($match, '', $compactedContent);
1524                         } // END - foreach
1525                 } // END - if
1526
1527                 // Set the content again
1528                 $this->setRawTemplateData($compactedContent);
1529
1530                 // Return compacted content
1531                 return $compactedContent;
1532         }
1533 }
1534
1535 // [EOF]
1536 ?>