3 * The own template engine for loading caching and sending out the web pages
6 class TemplateEngine extends BaseFrameworkSystem implements CompileableTemplate {
8 * The local path name where all templates and sub folders for special
9 * templates are stored. We will internally determine the language plus
10 * "html" for web templates or "emails" for email templates
12 private $basePath = "";
15 * The extension for web and email templates (not compiled templates)
17 private $templateExtension = ".tpl";
20 * The extension for code templates (not compiled templates)
22 private $codeExtension = ".ctp";
25 * Path relative to $basePath and language code for compiled code-templates
27 private $compileOutputPath = "templates/_compiled";
30 * The raw (maybe uncompiled) template
32 private $rawTemplateData = "";
35 * Template data with compiled-in variables
37 private $compiledData = "";
40 * The last loaded template's FQFN for debugging the engine
42 private $lastTemplate = "";
45 * The variable stack for the templates. This must be initialized and
46 * shall become an instance of FrameworkArrayObject.
48 private $varStack = null;
51 * Configuration variables in a simple array
53 private $configVariables = array();
56 * The language instance which should link to an object of LanguageSystem
58 private $langInstance = null;
61 * Loaded templates for recursive protection and detection
63 private $loadedTemplates = array();
66 * Compiled templates for recursive protection and detection
68 private $compiledTemplates = array();
71 * Loaded raw template data
73 private $loadedRawData = null;
76 * Raw templates which are linked in code templates
78 private $rawTemplates = null;
81 * A regular expression for variable=value pairs
83 private $regExpVarValue = '/([\w_]+)(="([^"]*)"|=([\w_]+))?/';
86 * A regular expression for filtering out code tags
88 * E.g.: {?template:variable=value;var2=value2;[...]?}
90 private $regExpCodeTags = '/\{\?([a-z_]+)(:("[^"]+"|[^?}]+)+)?\?\}/';
92 // Exception codes for the template engine
93 const EXCEPTION_TEMPLATE_TYPE_IS_UNEXPECTED = 0xa00;
94 const TEMPLATE_CONTAINS_INVALID_VAR_EXCEPTION = 0xa01;
101 private final function __construct () {
102 // Call parent constructor
103 parent::constructor(__CLASS__);
105 // Set part description
106 $this->setPartDescr("Template-Engine");
108 // Create unique ID number
109 $this->createUniqueID();
112 $this->removeNumberFormaters();
113 $this->removeSystemArray();
117 * Creates an instance of the class TemplateEngine and prepares it for usage
119 * @param $basePath The local base path for all templates
120 * @param $langInstance An instance of LanguageSystem (default)
121 * @param $ioInstance An instance of FileIOHandler (default, middleware!)
122 * @return $tplInstance An instance of TemplateEngine
123 * @throws BasePathIsEmptyException If the provided $basePath is empty
124 * @throws InvalidBasePathStringException If $basePath is no string
125 * @throws BasePathIsNoDirectoryException If $basePath is no
126 * directory or not found
127 * @throws BasePathReadProtectedException If $basePath is
130 public final static function createTemplateEngine ($basePath, $langInstance, $ioInstance) {
131 // Get a new instance
132 $tplInstance = new TemplateEngine();
134 // Is the base path valid?
135 if (empty($basePath)) {
136 // Base path is empty
137 throw new BasePathIsEmptyException($tplInstance, self::EXCEPTION_UNEXPECTED_EMPTY_STRING);
138 } elseif (!is_string($basePath)) {
140 throw new InvalidBasePathStringException(array($tplInstance, $basePath), self::EXCEPTION_INVALID_STRING);
141 } elseif (!is_dir($basePath)) {
143 throw new BasePathIsNoDirectoryException(array($tplInstance, $basePath), self::EXCEPTION_INVALID_PATH_NAME);
144 } elseif (!is_readable($basePath)) {
146 throw new BasePathReadProtectedException(array($tplInstance, $basePath), self::EXCEPTION_READ_PROTECED_PATH);
149 // Get configuration instance
150 $cfgInstance = $tplInstance->getConfigInstance();
153 $tplInstance->setBasePath($basePath);
155 // Initialize the variable stack
156 $tplInstance->initVariableStack();
158 // Set the language and IO instances
159 $tplInstance->setLanguageInstance($langInstance);
160 $tplInstance->setIOInstance($ioInstance);
162 // Set template extensions
163 $tplInstance->setRawTemplateExtension($cfgInstance->readConfig("raw_template_extension"));
164 $tplInstance->setCodeTemplateExtension($cfgInstance->readConfig("code_template_extension"));
166 // Absolute output path for compiled templates
167 $tplInstance->setCompileOutputPath(PATH . $cfgInstance->readConfig("compile_output_path"));
169 // Return the prepared instance
174 * Search for a variable in the stack
176 * @param $var The variable we are looking for
177 * @return $idx FALSE means not found, > 0 means found on a specific index
179 private function isVariableAlreadySet ($var) {
180 // First everything is not found
184 for ($idx = $this->varStack->getIterator(); $idx->valid(); $idx->next()) {
186 $currEntry = $idx->current();
188 // Is the entry found?
189 if ($currEntry['name'] == $var) {
191 $found = $idx->key();
196 // Return the current position
201 * Add a variable to the stack
203 * @param $var The variable we are looking for
204 * @param $value The value we want to store in the variable
207 private function addVariable ($var, $value) {
208 // Add it to the stack
209 $this->varStack->append(array(
216 * Modify an entry on the stack
218 * @param $var The variable we are looking for
219 * @param $value The value we want to store in the variable
222 private function modifyVariable ($var, $value) {
223 // It should be there so let's look again...
224 for ($idx = $this->varStack->getIterator(); $idx->valid(); $idx->next()) {
226 $currEntry = $idx->current();
228 // Is this the requested variable?
229 if ($currEntry['name'] == $var) {
230 // Change it to the other value
231 $this->varStack->offsetSet($idx->key(), array(
240 * Initialize the variable stack. This holds all variables for later
245 public final function initVariableStack () {
246 $this->varStack = new FrameworkArrayObject();
250 * Setter for language instance which should be LanguageSystem
252 * @param $langInstance The language instance
255 public final function setLanguageInstance (ManageableLanguage $langInstance) {
256 $this->langInstance = $langInstance;
260 * Setter for file I/O instance which should be FileIOHandler
262 * @param $ioInstance The file I/O instance
265 public final function setIOInstance (FileIOHandler $ioInstance) {
266 $this->ioInstance = $ioInstance;
270 * Getter for file I/O instance which should be FileIOHandler
272 * @return $ioInstance The file I/O instance
274 public final function getIOInstance () {
275 return $this->ioInstance;
279 * Setter for base path
281 * @param $basePath The local base path for all templates
284 public final function setBasePath ($basePath) {
286 $basePath = (string) $basePath;
289 $this->basePath = $basePath;
293 * Getter for base path
295 * @return $basePath The local base path for all templates
297 public final function getBasePath () {
299 return $this->basePath;
303 * Setter for template extension
305 * @param $templateExtension The file extension for all uncompiled
309 public final function setRawTemplateExtension ($templateExtension) {
311 $templateExtension = (string) $templateExtension;
314 $this->templateExtension = $templateExtension;
318 * Setter for code template extension
320 * @param $codeExtension The file extension for all uncompiled
324 public final function setCodeTemplateExtension ($codeExtension) {
326 $codeExtension = (string) $codeExtension;
329 $this->codeExtension = $codeExtension;
333 * Getter for template extension
335 * @return $templateExtension The file extension for all uncompiled
338 public final function getRawTemplateExtension () {
340 return $this->templateExtension;
344 * Getter for code-template extension
346 * @return $codeExtension The file extension for all code-
349 public final function getCodeTemplateExtension () {
351 return $this->codeExtension;
355 * Setter for path of compiled templates
357 * @param $compileOutputPath The local base path for all
361 public final function setCompileOutputPath ($compileOutputPath) {
363 $compileOutputPath = (string) $compileOutputPath;
366 $this->compileOutputPath = $compileOutputPath;
370 * Setter for template type. Only "html", "emails" and "compiled" should
373 * @param $templateType The current template's type
376 private final function setTemplateType ($templateType) {
378 $templateType = (string) $templateType;
380 // And set it (only 2 letters)
381 $this->templateType = $templateType;
385 * Getter for template type
387 * @return $templateType The current template's type
389 public final function getTemplateType () {
390 return $this->templateType;
394 * Setter for the last loaded template's FQFN
396 * @param $template The last loaded template
399 private final function setLastTemplate ($template) {
401 $template = (string) $template;
402 $this->lastTemplate = $template;
406 * Getter for the last loaded template's FQFN
408 * @return $template The last loaded template
410 private final function getLastTemplate () {
411 return $this->lastTemplate;
415 * Assign (add) a given variable with a value
417 * @param $var The variable we are looking for
418 * @param $value The value we want to store in the variable
421 public final function assignVariable ($var, $value) {
422 // First search for the variable if it was already added
423 $idx = $this->isVariableAlreadySet($var);
426 if ($idx === false) {
427 // Add it to the stack
428 $this->addVariable($var, $value);
429 } elseif (!empty($value)) {
430 // Modify the stack entry
431 $this->modifyVariable($var, $value);
436 * Assign a given congfiguration variable with a value
438 * @param $var The configuration variable we are looking for
439 * @param $value The value we want to store in the variable
442 public final function assignConfigVariable ($var, $value) {
443 // Sweet and simple...
444 $this->configVariables[$var] = $value;
448 * Removes a given variable
450 * @param $var The variable we are looking for
453 public final function removeVariable ($var) {
454 // First search for the variable if it was already added
455 $idx = $this->isVariableAlreadySet($var);
458 if ($idx !== false) {
459 // Remove this variable
460 $this->varStack->offsetUnset($idx);
465 * Private setter for raw template data
467 * @param $rawTemplateData The raw data from the template
470 private final function setRawTemplateData ($rawTemplateData) {
472 $rawTemplateData = (string) $rawTemplateData;
474 // And store it in this class
475 $this->rawTemplateData = $rawTemplateData;
479 * Private setter for compiled templates
481 private final function setCompiledData ($compiledData) {
483 $compiledData = (string) $compiledData;
485 // And store it in this class
486 $this->compiledData = $compiledData;
490 * Private loader for all template types
492 * @param $template The template we shall load
495 private final function loadTemplate ($template) {
497 $template = (string) $template;
499 // Get extension for the template
500 $ext = $this->getRawTemplateExtension();
502 // If we shall load a code-template we need to switch the file extension
503 if ($this->getTemplateType() == $this->getConfigInstance()->readConfig("code_template_type")) {
504 // Switch over to the code-template extension
505 $ext = $this->getCodeTemplateExtension();
508 // Construct the FQFN for the template by honoring the current language
509 $fqfn = sprintf("%s%s/%s/%s%s",
510 $this->getBasePath(),
511 $this->langInstance->getLanguageCode(),
512 $this->getTemplateType(),
517 // Load the raw template data
518 $this->loadRawTemplateData($fqfn);
522 * A private loader for raw template names
524 * @param $fqfn The full-qualified file name for a template
526 * @throws NullPointerException If $inputInstance is null
527 * @throws NoObjectException If $inputInstance is not an object
528 * @throws MissingMethodException If $inputInstance is missing a
531 private function loadRawTemplateData ($fqfn) {
533 if ((defined('DEBUG_TEMPLATE')) && (is_object($this->getDebugInstance()))) $this->getDebugInstance()->output(sprintf("[%s:] Template <strong>%s</strong> vom Typ <strong>%s</strong> wird geladen.<br />\n",
536 $this->getTemplateType()
539 // Get a input/output instance from the middleware
540 $ioInstance = $this->getIOInstance();
542 // Validate the instance
543 if (is_null($ioInstance)) {
545 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
546 } elseif (!is_object($ioInstance)) {
547 // Throw another exception
548 throw new NoObjectException($ioInstance, self::EXCEPTION_IS_NO_OBJECT);
549 } elseif (!method_exists($ioInstance, 'loadFileContents')) {
550 // Throw yet another exception
551 throw new MissingMethodException(array($ioInstance, 'loadFileContents'), self::EXCEPTION_MISSING_METHOD);
554 // Load the raw template
555 $rawTemplateData = $ioInstance->loadFileContents($fqfn);
558 if ((defined('DEBUG_TEMPLATE')) && (is_object($this->getDebugInstance()))) $this->getDebugInstance()->output(sprintf("[%s:] <strong>%s</strong> Byte Rohdaten geladen.<br />\n",
560 strlen($rawTemplateData)
563 // Store the template's contents into this class
564 $this->setRawTemplateData($rawTemplateData);
566 // Remember the template's FQFN
567 $this->setLastTemplate($fqfn);
571 * Try to assign an extracted template variable as a "content" or "config"
574 * @param $varName The variable's name (shall be content or
576 * @param $var The variable we want to assign
578 private function assignTemplateVariable ($varName, $var) {
579 // Is it not a config variable?
580 if ($varName != "config") {
581 // Regular template variables
582 $this->assignVariable($var, "");
584 // Configuration variables
585 $this->assignConfigVariable($var, $this->getConfigInstance()->readConfig($var));
590 * Extract variables from a given raw data stream
592 * @param $rawData The raw template data we shall analyze
594 * @throws InvalidTemplateVariableNameException If a variable name
598 private function extractVariablesFromRawData ($rawData) {
600 $rawData = (string) $rawData;
602 // Search for variables
603 @preg_match_all('/\$(\w+)(\[(\w+)\])?/', $rawData, $variableMatches);
605 // Did we find some variables?
606 if ((is_array($variableMatches)) && (count($variableMatches) == 4) && (count($variableMatches[0]) > 0)) {
607 // Initialize all missing variables
608 foreach ($variableMatches[3] as $key=>$var) {
609 // Is the variable name valid?
610 if (($variableMatches[1][$key] != $this->getConfigInstance()->readConfig("tpl_valid_var")) && ($variableMatches[1][$key] != "config")) {
611 // Invalid variable name
612 throw new InvalidTemplateVariableNameException(array($this, $this->getLastTemplate(), $variableMatches[1][$key], $this->getConfigInstance()), self::TEMPLATE_CONTAINS_INVALID_VAR_EXCEPTION);
615 // Try to assign it, empty strings are being ignored
616 $this->assignTemplateVariable($variableMatches[1][$key], $var);
622 * Main analysis of the loaded template
624 * @param $templateMatches Found template place-holders, see below
627 *---------------------------------
628 * Structure of $templateMatches:
629 *---------------------------------
630 * [0] => Array - An array with all full matches
631 * [1] => Array - An array with left part (before the ":") of a match
632 * [2] => Array - An array with right part of a match including ":"
633 * [3] => Array - An array with right part of a match excluding ":"
635 private function analyzeTemplate ($templateMatches) {
636 // Backup raw template data
637 $backup = $this->getRawTemplateData();
639 // Initialize some arrays
640 if (is_null($this->loadedRawData)) { $this->loadedRawData = array(); $this->rawTemplates = array(); }
642 // Load all requested templates
643 foreach ($templateMatches[1] as $template) {
645 // Load and compile only templates which we have not yet loaded
646 // RECURSIVE PROTECTION! BE CAREFUL HERE!
647 if ((!isset($this->loadedRawData[$template])) && (!in_array($template, $this->loadedTemplates))) {
649 // Then try to search for code-templates first
651 // Load the code template and remember it's contents
652 $this->loadCodeTemplate($template);
653 $this->loadedRawData[$template] = $this->getRawTemplateData();
655 // Remember this template for recursion detection
656 // RECURSIVE PROTECTION!
657 $this->loadedTemplates[] = $template;
658 } catch (FilePointerNotOpenedException $e) {
659 // Template not found!
660 $this->rawTemplates[] = $template;
663 } // if ((!isset( ...
665 } // for ($templateMatches ...
667 // Restore the raw template data
668 $this->setRawTemplateData($backup);
672 * Compile a given raw template code and remember it for later usage
674 * @param $code The raw template code
675 * @param $template The template's name
678 private function compileCode ($code, $template) {
679 // Is this template already compiled?
680 if (in_array($template, $this->compiledTemplates)) {
685 // Remember this template being compiled
686 $this->compiledTemplates[] = $template;
688 // Compile the loaded code in five steps:
690 // 1. Backup current template data
691 $backup = $this->getRawTemplateData();
693 // 2. Set the current template's raw data as the new content
694 $this->setRawTemplateData($code);
696 // 3. Compile the template data
697 $this->compileTemplate();
699 // 4. Remember it's contents
700 $this->loadedRawData[$template] = $this->getRawTemplateData();
702 // 5. Restore the previous raw content from backup variable
703 $this->setRawTemplateData($backup);
707 * Insert all given and loaded templates by running through all loaded
708 * codes and searching for their place-holder in the main template
710 * @param $templateMatches See method analyzeTemplate()
713 private function insertAllTemplates ($templateMatches) {
714 // Run through all loaded codes
715 foreach ($this->loadedRawData as $template => $code) {
717 // Search for the template
718 $foundIndex = array_search($template, $templateMatches[1]);
720 // Lookup the matching template replacement
721 if (isset($templateMatches[0][$foundIndex])) {
723 // Get the current raw template
724 $rawData = $this->getRawTemplateData();
726 // Replace the space holder with the template code
727 $rawData = str_replace($templateMatches[0][$foundIndex], $code, $rawData);
729 // Set the new raw data
730 $this->setRawTemplateData($rawData);
736 * Load all extra raw templates
740 private function loadExtraRawTemplates () {
741 // Are there some raw templates we need to load?
742 if (count($this->rawTemplates) > 0) {
743 // Try to load all raw templates
744 foreach ($this->rawTemplates as $key => $template) {
747 $this->loadWebTemplate($template);
749 // Remember it's contents
750 $this->rawTemplates[$template] = $this->getRawTemplateData();
752 // Remove it from the loader list
753 unset($this->rawTemplates[$key]);
755 // Remember this template for recursion detection
756 // RECURSIVE PROTECTION!
757 $this->loadedTemplates[] = $template;
758 } catch (FilePointerNotOpenedException $e) {
759 // This template was never found. We silently ignore it
760 unset($this->rawTemplates[$key]);
767 * Assign all found template variables
769 * @param $varMatches An array full of variable/value pairs.
772 private function assignAllVariables ($varMatches) {
773 // Search for all variables
774 foreach ($varMatches[1] as $key=>$var) {
776 // Detect leading equals
777 if (substr($varMatches[2][$key], 0, 1) == "=") {
778 // Remove and cast it
779 $varMatches[2][$key] = (string) substr($varMatches[2][$key], 1);
782 // Do we have some quotes left and right side? Then it is free text
783 if ((substr($varMatches[2][$key], 0, 1) == "\"") && (substr($varMatches[2][$key], -1, 1) == "\"")) {
784 // Free string detected! Which we can assign directly
785 $this->assignVariable($var, $varMatches[3][$key]);
787 // Non-string found so we need some deeper analysis...
788 die("Deeper analysis not yet implemented!");
791 } // for ($varMatches ...
794 * Compiles all loaded raw templates
796 * @param $templateMatches See method analyzeTemplate() for details
799 private function compileRawTemplateData ($templateMatches) {
800 // Are some code-templates found which we need to compile?
801 if (count($this->loadedRawData) > 0) {
804 foreach ($this->loadedRawData as $template => $code) {
806 // Search for the template
807 $foundIndex = array_search($template, $templateMatches[1]);
809 // Lookup the matching variable data
810 if (isset($templateMatches[3][$foundIndex])) {
812 // Split it up with another reg. exp. into variable=value pairs
813 @preg_match_all($this->regExpVarValue, $templateMatches[3][$foundIndex], $varMatches);
815 // Assign all variables
816 $this->assignAllVariables($varMatches);
818 } // END - if (isset($templateMatches ...
820 // Compile the loaded template
821 $this->compileCode($code, $template);
823 } // END - foreach ($this->loadedRawData ...
825 // Insert all templates
826 $this->insertAllTemplates($templateMatches);
828 } // END - if (count($this->loadedRawData) ...
832 * Getter for raw template data
834 * @return $rawTemplateData The raw data from the template
836 public final function getRawTemplateData () {
837 return $this->rawTemplateData;
841 * Getter for compiled templates
843 public final function getCompiledData () {
844 return $this->compiledData;
848 * Load a specified web template into the engine
850 * @param $template The web template we shall load which is
851 * located in "html" by default
854 public final function loadWebTemplate ($template) {
856 $this->setTemplateType($this->getConfigInstance()->readConfig("web_template_type"));
858 // Load the special template
859 $this->loadTemplate($template);
863 * Load a specified email template into the engine
865 * @param $template The email template we shall load which is
866 * located in "emails" by default
869 public final function loadEmailTemplate ($template) {
871 $this->setTemplateType($this->getConfigInstance()->readConfig("email_template_type"));
873 // Load the special template
874 $this->loadTemplate($template);
878 * Load a specified code template into the engine
880 * @param $template The code template we shall load which is
881 * located in "code" by default
884 public final function loadCodeTemplate ($template) {
886 $this->setTemplateType($this->getConfigInstance()->readConfig("code_template_type"));
888 // Load the special template
889 $this->loadTemplate($template);
893 * Compile all variables by inserting their respective values
897 public final function compileVariables () {
898 // Initialize the $content array
899 $validVar = $this->getConfigInstance()->readConfig("tpl_valid_var");
902 // Iterate through all variables
903 for ($idx = $this->varStack->getIterator(); $idx->valid(); $idx->next()) {
904 // Get current variable from the stack
905 $currVariable = $idx->current();
907 // Transfer it's name/value combination to the $content array
908 $dummy[$currVariable['name']] = $currVariable['value'];
912 // Prepare all configuration variables
913 $config = $this->configVariables;
915 // Remove some variables
917 unset($currVariable);
919 // Prepare the eval() command for comiling the template
920 $eval = sprintf("\$this->setCompiledData(\"%s\");",
921 addslashes($this->getRawTemplateData())
925 if (((defined('DEBUG_EVAL')) || (defined('DEBUG_ALL'))) && (is_object($this->getDebugInstance()))) $this->getDebugInstance()->output(sprintf("[%s:] Konstruierte PHP-Anweisung: <pre><em>%s</em></pre><br />\n",
930 // Run the constructed command. This will "compile" all variables in
935 * Compile all required templates into the current loaded one
938 * @throws UnexpectedTemplateTypeException If the template type is
940 * @throws InvalidArrayCountException If an unexpected array
941 * count has been found
943 public final function compileTemplate () {
944 // We will only work with template type "code" from configuration
945 if ($this->getTemplateType() != $this->getConfigInstance()->readConfig("code_template_type")) {
947 throw new UnexpectedTemplateTypeException(array($this, $this->getTemplateType(), $this->getConfigInstance()->readConfig("code_template_type")), self::EXCEPTION_TEMPLATE_TYPE_IS_UNEXPECTED);
950 // Get the raw data. Thanks to Flobee(R) for given me a hint using the
951 // modifier "m" in regular expressions. I had implemented a regex here
952 // like this: (\n|\r)
953 $rawData = $this->getRawTemplateData();
955 // Remove double spaces and trim leading/trailing spaces
956 $rawData = trim(str_replace(" ", " ", $rawData));
958 // Search for raw variables
959 $this->extractVariablesFromRawData($rawData);
961 // Search for code-tags which are {? ?}
962 @preg_match_all($this->regExpCodeTags, $rawData, $templateMatches);
964 // Analyze the matches array
965 if ((is_array($templateMatches)) && (count($templateMatches) == 4) && (count($templateMatches[0]) > 0)) {
966 // Entries are found:
969 $this->analyzeTemplate($templateMatches);
971 // Compile raw template data
972 $this->compileRawTemplateData($templateMatches);
974 // Are there some raw templates left for loading?
975 $this->loadExtraRawTemplates();
977 // Are some raw templates found and loaded?
978 if (count($this->rawTemplates) > 0) {
979 die("NOT YET IMPLEMENTED");
981 } // END - if($templateMatches ...
985 * Output the compiled page to the outside world. In case of web templates
986 * this would be vaild (X)HTML code. And in case of email templates this
987 * would store a prepared email body inside the template engine.
991 public final function output () {
992 // Check which type of template we have
993 switch ($this->getTemplateType()) {
994 case "html": // Raw HTML templates can be send to the output buffer
996 $this->getWebOutputInstance()->output($this->getCompiledData());
999 default: // Unknown type found
1000 if ((is_object($this->getDebugInstance())) && (method_exists($this->getDebugInstance(), 'output'))) {
1001 // Use debug output handler
1002 $this->getDebugInstance()->output(sprintf("[%s:] Unbekannter Template-Typ <strong>%s</strong> erkannt.",
1003 $this->__toString(),
1004 $this->getTemplateType()
1009 // DO NOT REWRITE THIS TO app_die() !!!
1010 die(sprintf("[%s:] Unbekannter Template-Typ <strong>%s</strong> erkannt.",
1011 $this->__toString(),
1012 $this->getTemplateType()