4 * Smarty Internal Plugin Smarty Template Compiler Base
5 * This file contains the basic classes and methods for compiling Smarty templates with lexer/parser
13 * Main abstract compiler class
16 * @subpackage Compiler
18 abstract class Smarty_Internal_TemplateCompilerBase
25 public $smarty = null;
28 * hash for nocache sections
32 public $nocache_hash = null;
35 * suppress generation of nocache code
39 public $suppressNocacheProcessing = false;
46 public static $_tag_objects = array();
53 public $_tag_stack = array();
58 * @var Smarty_Internal_Template
60 public $template = null;
63 * merged included sub template data
67 public $mergedSubTemplatesData = array();
70 * merged sub template code
74 public $mergedSubTemplatesCode = array();
77 * collected template properties during compilation
81 public $templateProperties = array();
84 * sources which must be compiled
88 public $sources = array();
91 * flag that we are inside {block}
95 public $inheritance = false;
98 * flag when compiling inheritance child template
102 public $inheritance_child = false;
105 * uid of templates called by {extends} for recursion check
109 public $extends_uid = array();
112 * source line offset for error messages
116 public $trace_line_offset = 0;
123 public $trace_uid = '';
130 public $trace_filepath = '';
132 * stack for tracing file and line of nested {block} tags
136 public $trace_stack = array();
139 * plugins loaded by default plugin handler
143 public $default_handler_plugins = array();
146 * saved preprocessed modifier list
150 public $default_modifier_list = null;
153 * force compilation of complete template as nocache
157 public $forceNocache = false;
160 * suppress Smarty header code in compiled template
164 public $suppressHeader = false;
167 * suppress template property header code in compiled template
171 public $suppressTemplatePropertyHeader = false;
174 * suppress pre and post filter
178 public $suppressFilter = false;
181 * flag if compiled template file shall we written
185 public $write_compiled_code = true;
188 * flag if currently a template function is compiled
192 public $compiles_template_function = false;
195 * called sub functions from template function
199 public $called_functions = array();
202 * compiled template function code
206 public $templateFunctionCode = '';
209 * flags for used modifier plugins
213 public $modifier_plugins = array();
216 * type of already compiled modifier
220 public $known_modifier_type = array();
223 * parent compiler object for merged subtemplates and template functions
225 * @var Smarty_Internal_TemplateCompilerBase
227 public $parent_compiler = null;
230 * Flag true when compiling nocache section
234 public $nocache = false;
237 * Flag true when tag is compiled as nocache
241 public $tag_nocache = false;
244 * Flag to restart parsing
248 public $abort_and_recompile = false;
251 * Compiled tag prefix code
255 public $prefix_code = array();
262 public $prefixCodeStack = array();
265 * Tag has compiled code
269 public $has_code = false;
272 * A variable string was compiled
276 public $has_variable_string = false;
283 public $has_output = false;
290 public $stripRegEx = '![\t ]*[\r\n]+[\t ]*!';
293 * method to compile a Smarty template
295 * @param mixed $_content template source
297 * @return bool true if compiling succeeded, false if it failed
299 abstract protected function doCompile($_content);
302 * Initialize compiler
304 public function __construct()
306 $this->nocache_hash
= str_replace(array('.', ','), '_', uniqid(rand(), true));
310 * Method to compile a Smarty template
312 * @param Smarty_Internal_Template $template template object to compile
313 * @param bool $nocache true is shall be compiled in nocache mode
314 * @param null|Smarty_Internal_TemplateCompilerBase $parent_compiler
316 * @return bool true if compiling succeeded, false if it failed
318 public function compileTemplate(Smarty_Internal_Template
$template, $nocache = null, $parent_compiler = null)
320 $this->parent_compiler
= $parent_compiler ?
$parent_compiler : $this;
321 $nocache = isset($nocache) ?
$nocache : false;
322 if (empty($template->properties
['nocache_hash'])) {
323 $template->properties
['nocache_hash'] = $this->nocache_hash
;
325 $this->nocache_hash
= $template->properties
['nocache_hash'];
327 // flag for nochache sections
328 $this->nocache
= $nocache;
329 $this->tag_nocache
= false;
330 // save template object in compiler class
331 $this->template
= $template;
332 // reset has nocache code flag
333 $this->template
->has_nocache_code
= false;
334 $save_source = $this->template
->source
;
335 // template header code
336 $template_header = '';
337 if (!$this->suppressHeader
) {
338 $template_header .= "<?php /* Smarty version " . Smarty
::SMARTY_VERSION
. ", created on " . strftime("%Y-%m-%d %H:%M:%S") . "\n";
339 $template_header .= " compiled from \"" . $this->template
->source
->filepath
. "\" */ ?>\n";
342 if (empty($this->template
->source
->components
)) {
343 $this->sources
= array($template->source
);
345 // we have array of inheritance templates by extends: resource
346 $this->sources
= array_reverse($template->source
->components
);
349 // the $this->sources array can get additional elements while compiling by the {extends} tag
350 while ($this->template
->source
= array_shift($this->sources
)) {
351 $this->smarty
->_current_file
= $this->template
->source
->filepath
;
352 if ($this->smarty
->debugging
) {
353 Smarty_Internal_Debug
::start_compile($this->template
);
355 $no_sources = count($this->sources
);
356 $this->parent_compiler
->template
->properties
['file_dependency'][$this->template
->source
->uid
] = array($this->template
->source
->filepath
, $this->template
->source
->timestamp
, $this->template
->source
->type
);
359 $this->inheritance_child
= true;
361 $this->inheritance_child
= false;
364 $_compiled_code = '';
365 // flag for aborting current and start recompile
366 $this->abort_and_recompile
= false;
367 // get template source
368 $_content = $this->template
->source
->content
;
369 if ($_content != '') {
370 // run prefilter if required
371 if ((isset($this->smarty
->autoload_filters
['pre']) ||
isset($this->smarty
->registered_filters
['pre'])) && !$this->suppressFilter
) {
372 $_content = Smarty_Internal_Filter_Handler
::runFilter('pre', $_content, $template);
375 $_compiled_code = $this->doCompile($_content, true);
377 } while ($this->abort_and_recompile
);
378 if ($this->smarty
->debugging
) {
379 Smarty_Internal_Debug
::end_compile($this->template
);
383 $this->template
->source
= $save_source;
385 $this->smarty
->_current_file
= $this->template
->source
->filepath
;
387 unset($this->parser
->root_buffer
, $this->parser
->current_buffer
, $this->parser
, $this->lex
);
388 self
::$_tag_objects = array();
389 // return compiled code to template object
391 if (!empty($this->mergedSubTemplatesCode
)) {
392 foreach ($this->mergedSubTemplatesCode
as $code) {
393 $merged_code .= $code;
396 // run postfilter if required on compiled template code
397 if ((isset($this->smarty
->autoload_filters
['post']) ||
isset($this->smarty
->registered_filters
['post'])) && !$this->suppressFilter
&& $_compiled_code != '') {
398 $_compiled_code = Smarty_Internal_Filter_Handler
::runFilter('post', $_compiled_code, $template);
400 if ($this->suppressTemplatePropertyHeader
) {
401 $_compiled_code .= $merged_code;
403 $_compiled_code = $template_header . Smarty_Internal_Extension_CodeFrame
::create($template, $_compiled_code) . $merged_code;
405 if (!empty($this->templateFunctionCode
)) {
406 // run postfilter if required on compiled template code
407 if ((isset($this->smarty
->autoload_filters
['post']) ||
isset($this->smarty
->registered_filters
['post'])) && !$this->suppressFilter
) {
408 $_compiled_code .= Smarty_Internal_Filter_Handler
::runFilter('post', $this->templateFunctionCode
, $template);
410 $_compiled_code .= $this->templateFunctionCode
;
413 // unset content because template inheritance could have replace source with parent code
414 unset ($template->source
->content
);
415 $this->parent_compiler
= null;
416 $this->template
= null;
417 return $_compiled_code;
422 * This is a call back from the lexer/parser
424 * Save current prefix code
426 * Merge tag prefix code with saved one
427 * (required nested tags in attributes)
429 * @param string $tag tag name
430 * @param array $args array with tag attributes
431 * @param array $parameter array with compilation parameter
433 * @throws SmartyCompilerException
434 * @throws SmartyException
435 * @return string compiled code
437 public function compileTag($tag, $args, $parameter = array())
439 $this->prefixCodeStack
[] = $this->prefix_code
;
440 $this->prefix_code
= array();
441 $result = $this->compileTag2($tag, $args, $parameter);
442 $this->prefix_code
= array_merge($this->prefix_code
, array_pop($this->prefixCodeStack
));
449 * @param string $tag tag name
450 * @param array $args array with tag attributes
451 * @param array $parameter array with compilation parameter
453 * @throws SmartyCompilerException
454 * @throws SmartyException
455 * @return string compiled code
457 private function compileTag2($tag, $args, $parameter)
460 // $args contains the attributes parsed and compiled by the lexer/parser
461 // assume that tag does compile into code, but creates no HTML output
462 $this->has_code
= true;
463 $this->has_output
= false;
464 // log tag/attributes
465 if (isset($this->smarty
->get_used_tags
) && $this->smarty
->get_used_tags
) {
466 $this->template
->used_tags
[] = array($tag, $args);
468 // check nocache option flag
469 if (in_array("'nocache'", $args) ||
in_array(array('nocache' => 'true'), $args)
470 ||
in_array(array('nocache' => '"true"'), $args) ||
in_array(array('nocache' => "'true'"), $args)
472 $this->tag_nocache
= true;
474 // compile the smarty tag (required compile classes to compile the tag are autoloaded)
475 if (($_output = $this->callTagCompiler($tag, $args, $parameter)) === false) {
476 if (isset($this->parent_compiler
->templateProperties
['tpl_function'][$tag])) {
477 // template defined by {template} tag
478 $args['_attr']['name'] = "'" . $tag . "'";
479 $_output = $this->callTagCompiler('call', $args, $parameter);
482 if ($_output !== false) {
483 if ($_output !== true) {
484 // did we get compiled code
485 if ($this->has_code
) {
486 // Does it create output?
487 if ($this->has_output
) {
490 // return compiled code
494 // tag did not produce compiled code
497 // map_named attributes
498 if (isset($args['_attr'])) {
499 foreach ($args['_attr'] as $key => $attribute) {
500 if (is_array($attribute)) {
501 $args = array_merge($args, $attribute);
505 // not an internal compiler tag
506 if (strlen($tag) < 6 ||
substr($tag, - 5) != 'close') {
507 // check if tag is a registered object
508 if (isset($this->smarty
->registered_objects
[$tag]) && isset($parameter['object_method'])) {
509 $method = $parameter['object_method'];
510 if (!in_array($method, $this->smarty
->registered_objects
[$tag][3]) &&
511 (empty($this->smarty
->registered_objects
[$tag][1]) ||
in_array($method, $this->smarty
->registered_objects
[$tag][1]))
513 return $this->callTagCompiler('private_object_function', $args, $parameter, $tag, $method);
514 } elseif (in_array($method, $this->smarty
->registered_objects
[$tag][3])) {
515 return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $method);
518 $this->trigger_template_error('not allowed method "' . $method . '" in registered object "' . $tag . '"', $this->lex
->taglineno
);
521 // check if tag is registered
522 foreach (array(Smarty
::PLUGIN_COMPILER
, Smarty
::PLUGIN_FUNCTION
, Smarty
::PLUGIN_BLOCK
) as $plugin_type) {
523 if (isset($this->smarty
->registered_plugins
[$plugin_type][$tag])) {
524 // if compiler function plugin call it now
525 if ($plugin_type == Smarty
::PLUGIN_COMPILER
) {
527 foreach ($args as $key => $mixed) {
528 if (is_array($mixed)) {
529 $new_args = array_merge($new_args, $mixed);
531 $new_args[$key] = $mixed;
534 if (!$this->smarty
->registered_plugins
[$plugin_type][$tag][1]) {
535 $this->tag_nocache
= true;
537 $function = $this->smarty
->registered_plugins
[$plugin_type][$tag][0];
538 if (!is_array($function)) {
539 return $function($new_args, $this);
540 } elseif (is_object($function[0])) {
541 return $this->smarty
->registered_plugins
[$plugin_type][$tag][0][0]->$function[1]($new_args, $this);
543 return call_user_func_array($function, array($new_args, $this));
546 // compile registered function or block function
547 if ($plugin_type == Smarty
::PLUGIN_FUNCTION ||
$plugin_type == Smarty
::PLUGIN_BLOCK
) {
548 return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter, $tag);
552 // check plugins from plugins folder
553 foreach ($this->smarty
->plugin_search_order
as $plugin_type) {
554 if ($plugin_type == Smarty
::PLUGIN_COMPILER
&& $this->smarty
->loadPlugin('smarty_compiler_' . $tag) && (!isset($this->smarty
->security_policy
) ||
$this->smarty
->security_policy
->isTrustedTag($tag, $this))) {
555 $plugin = 'smarty_compiler_' . $tag;
556 if (is_callable($plugin)) {
557 // convert arguments format for old compiler plugins
559 foreach ($args as $key => $mixed) {
560 if (is_array($mixed)) {
561 $new_args = array_merge($new_args, $mixed);
563 $new_args[$key] = $mixed;
567 return $plugin($new_args, $this->smarty
);
569 if (class_exists($plugin, false)) {
570 $plugin_object = new $plugin;
571 if (method_exists($plugin_object, 'compile')) {
572 return $plugin_object->compile($args, $this);
575 throw new SmartyException("Plugin \"{$tag}\" not callable");
577 if ($function = $this->getPlugin($tag, $plugin_type)) {
578 if (!isset($this->smarty
->security_policy
) ||
$this->smarty
->security_policy
->isTrustedTag($tag, $this)) {
579 return $this->callTagCompiler('private_' . $plugin_type . '_plugin', $args, $parameter, $tag, $function);
584 if (is_callable($this->smarty
->default_plugin_handler_func
)) {
586 // look for already resolved tags
587 foreach ($this->smarty
->plugin_search_order
as $plugin_type) {
588 if (isset($this->default_handler_plugins
[$plugin_type][$tag])) {
594 // call default handler
595 foreach ($this->smarty
->plugin_search_order
as $plugin_type) {
596 if ($this->getPluginFromDefaultHandler($tag, $plugin_type)) {
603 // if compiler function plugin call it now
604 if ($plugin_type == Smarty
::PLUGIN_COMPILER
) {
606 foreach ($args as $mixed) {
607 $new_args = array_merge($new_args, $mixed);
609 $function = $this->default_handler_plugins
[$plugin_type][$tag][0];
610 if (!is_array($function)) {
611 return $function($new_args, $this);
612 } elseif (is_object($function[0])) {
613 return $this->default_handler_plugins
[$plugin_type][$tag][0][0]->$function[1]($new_args, $this);
615 return call_user_func_array($function, array($new_args, $this));
618 return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter, $tag);
623 // compile closing tag of block function
624 $base_tag = substr($tag, 0, - 5);
625 // check if closing tag is a registered object
626 if (isset($this->smarty
->registered_objects
[$base_tag]) && isset($parameter['object_method'])) {
627 $method = $parameter['object_method'];
628 if (in_array($method, $this->smarty
->registered_objects
[$base_tag][3])) {
629 return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $method);
632 $this->trigger_template_error('not allowed closing tag method "' . $method . '" in registered object "' . $base_tag . '"', $this->lex
->taglineno
);
635 // registered block tag ?
636 if (isset($this->smarty
->registered_plugins
[Smarty
::PLUGIN_BLOCK
][$base_tag]) ||
isset($this->default_handler_plugins
[Smarty
::PLUGIN_BLOCK
][$base_tag])) {
637 return $this->callTagCompiler('private_registered_block', $args, $parameter, $tag);
640 if ($function = $this->getPlugin($base_tag, Smarty
::PLUGIN_BLOCK
)) {
641 return $this->callTagCompiler('private_block_plugin', $args, $parameter, $tag, $function);
643 // registered compiler plugin ?
644 if (isset($this->smarty
->registered_plugins
[Smarty
::PLUGIN_COMPILER
][$tag])) {
645 // if compiler function plugin call it now
647 if (!$this->smarty
->registered_plugins
[Smarty
::PLUGIN_COMPILER
][$tag][1]) {
648 $this->tag_nocache
= true;
650 $function = $this->smarty
->registered_plugins
[Smarty
::PLUGIN_COMPILER
][$tag][0];
651 if (!is_array($function)) {
652 return $function($args, $this);
653 } elseif (is_object($function[0])) {
654 return $this->smarty
->registered_plugins
[Smarty
::PLUGIN_COMPILER
][$tag][0][0]->$function[1]($args, $this);
656 return call_user_func_array($function, array($args, $this));
659 if ($this->smarty
->loadPlugin('smarty_compiler_' . $tag)) {
660 $plugin = 'smarty_compiler_' . $tag;
661 if (is_callable($plugin)) {
662 return $plugin($args, $this->smarty
);
664 if (class_exists($plugin, false)) {
665 $plugin_object = new $plugin;
666 if (method_exists($plugin_object, 'compile')) {
667 return $plugin_object->compile($args, $this);
670 throw new SmartyException("Plugin \"{$tag}\" not callable");
673 $this->trigger_template_error("unknown tag \"" . $tag . "\"", $this->lex
->taglineno
);
680 * @param string $variable
684 public function compileVariable($variable)
686 if (strpos($variable, '(') == 0) {
687 // not a variable variable
688 $var = trim($variable, '\'');
689 $this->tag_nocache
= $this->tag_nocache |
$this->template
->getVariable($var, null, true, false)->nocache
;
690 $this->template
->properties
['variables'][$var] = $this->tag_nocache |
$this->nocache
;
692 return '$_smarty_tpl->tpl_vars[' . $variable . ']->value';
696 * This method is called from parser to process a text content section
697 * - remove text from inheritance child templates as they may generate output
698 * - strip text if strip is enabled
700 * @param string $text
702 * @return null|\Smarty_Internal_ParseTree_Text
704 public function processText($text)
706 if ($this->inheritance_child
&& !$this->blockTagNestingLevel
) {
709 if ($this->parser
->strip
) {
710 return new Smarty_Internal_ParseTree_Text($this->parser
, preg_replace($this->stripRegEx
, '', $text));
712 return new Smarty_Internal_ParseTree_Text($this->parser
, $text);
717 * lazy loads internal compile plugin for tag and calls the compile method
718 * compile objects cached for reuse.
719 * class name format: Smarty_Internal_Compile_TagName
720 * plugin filename format: Smarty_Internal_Tagname.php
722 * @param string $tag tag name
723 * @param array $args list of tag attributes
724 * @param mixed $param1 optional parameter
725 * @param mixed $param2 optional parameter
726 * @param mixed $param3 optional parameter
728 * @return string compiled code
730 public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null)
732 // check if tag allowed by security
733 if (!isset($this->smarty
->security_policy
) ||
$this->smarty
->security_policy
->isTrustedTag($tag, $this)) {
734 // re-use object if already exists
735 if (!isset(self
::$_tag_objects[$tag])) {
736 // lazy load internal compiler plugin
737 $class_name = 'Smarty_Internal_Compile_' . $tag;
738 if ($this->smarty
->loadPlugin($class_name)) {
739 self
::$_tag_objects[$tag] = new $class_name;
745 return self
::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3);
747 // no internal compile plugin for this tag
752 * Check for plugins and return function name
754 * @param $plugin_name
755 * @param string $plugin_type type of plugin
757 * @return string call name of function
759 public function getPlugin($plugin_name, $plugin_type)
762 if ($this->template
->caching
&& ($this->nocache ||
$this->tag_nocache
)) {
763 if (isset($this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type])) {
764 $function = $this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type]['function'];
765 } elseif (isset($this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type])) {
766 $this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type] = $this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type];
767 $function = $this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type]['function'];
770 if (isset($this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type])) {
771 $function = $this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type]['function'];
772 } elseif (isset($this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type])) {
773 $this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type] = $this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type];
774 $function = $this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type]['function'];
777 if (isset($function)) {
778 if ($plugin_type == 'modifier') {
779 $this->modifier_plugins
[$plugin_name] = true;
784 // loop through plugin dirs and find the plugin
785 $function = 'smarty_' . $plugin_type . '_' . $plugin_name;
786 $file = $this->smarty
->loadPlugin($function, false);
788 if (is_string($file)) {
789 if ($this->template
->caching
&& ($this->nocache ||
$this->tag_nocache
)) {
790 $this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type]['file'] = $file;
791 $this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type]['function'] = $function;
793 $this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type]['file'] = $file;
794 $this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type]['function'] = $function;
796 if ($plugin_type == 'modifier') {
797 $this->modifier_plugins
[$plugin_name] = true;
802 if (is_callable($function)) {
803 // plugin function is defined in the script
811 * Check for plugins by default plugin handler
813 * @param string $tag name of tag
814 * @param string $plugin_type type of plugin
816 * @return boolean true if found
818 public function getPluginFromDefaultHandler($tag, $plugin_type)
823 $result = call_user_func_array(
824 $this->smarty
->default_plugin_handler_func
, array($tag, $plugin_type, $this->template
, &$callback, &$script, &$cacheable)
827 $this->tag_nocache
= $this->tag_nocache ||
!$cacheable;
828 if ($script !== null) {
829 if (is_file($script)) {
830 if ($this->template
->caching
&& ($this->nocache ||
$this->tag_nocache
)) {
831 $this->template
->required_plugins
['nocache'][$tag][$plugin_type]['file'] = $script;
832 $this->template
->required_plugins
['nocache'][$tag][$plugin_type]['function'] = $callback;
834 $this->template
->required_plugins
['compiled'][$tag][$plugin_type]['file'] = $script;
835 $this->template
->required_plugins
['compiled'][$tag][$plugin_type]['function'] = $callback;
837 require_once $script;
839 $this->trigger_template_error("Default plugin handler: Returned script file \"{$script}\" for \"{$tag}\" not found");
842 if (!is_string($callback) && !(is_array($callback) && is_string($callback[0]) && is_string($callback[1]))) {
843 $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" must be a static function name or array of class and function name");
845 if (is_callable($callback)) {
846 $this->default_handler_plugins
[$plugin_type][$tag] = array($callback, true, array());
850 $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" not callable");
858 * Inject inline code for nocache template sections
859 * This method gets the content of each template element from the parser.
860 * If the content is compiled code and it should be not cached the code is injected
861 * into the rendered output.
863 * @param string $content content of template element
864 * @param boolean $is_code true if content is compiled code
866 * @return string content
868 public function processNocacheCode($content, $is_code)
870 // If the template is not evaluated and we have a nocache section and or a nocache tag
871 if ($is_code && !empty($content)) {
872 // generate replacement code
873 if ((!($this->template
->source
->recompiled
) ||
$this->forceNocache
) && $this->template
->caching
&& !$this->suppressNocacheProcessing
&&
874 ($this->nocache ||
$this->tag_nocache
)
876 $this->template
->has_nocache_code
= true;
877 $_output = addcslashes($content, '\'\\');
878 $_output = str_replace("^#^", "'", $_output);
879 $_output = "<?php echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/" . $_output . "/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>\n";
880 // make sure we include modifier plugins for nocache code
881 foreach ($this->modifier_plugins
as $plugin_name => $dummy) {
882 if (isset($this->template
->required_plugins
['compiled'][$plugin_name]['modifier'])) {
883 $this->template
->required_plugins
['nocache'][$plugin_name]['modifier'] = $this->template
->required_plugins
['compiled'][$plugin_name]['modifier'];
892 $this->modifier_plugins
= array();
893 $this->suppressNocacheProcessing
= false;
894 $this->tag_nocache
= false;
900 * Generate nocache code string
902 * @param string $code PHP code
906 public function makeNocacheCode($code)
908 return "echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/<?php " . str_replace("^#^", "'", addcslashes($code, '\'\\')) . "?>/*/%%SmartyNocache:{$this->nocache_hash}%%*/';\n";
912 * push current file and line offset on stack for tracing {block} source lines
914 * @param string $file new filename
915 * @param string $uid uid of file
916 * @param int $line line offset to source
917 * @param bool $debug false debug end_compile shall not be called
919 public function pushTrace($file, $uid, $line, $debug = true)
921 if ($this->smarty
->debugging
&& $debug) {
922 Smarty_Internal_Debug
::end_compile($this->template
);
924 array_push($this->trace_stack
, array($this->smarty
->_current_file
, $this->trace_filepath
, $this->trace_uid
, $this->trace_line_offset
));
925 $this->trace_filepath
= $this->smarty
->_current_file
= $file;
926 $this->trace_uid
= $uid;
927 $this->trace_line_offset
= $line;
928 if ($this->smarty
->debugging
) {
929 Smarty_Internal_Debug
::start_compile($this->template
);
934 * restore file and line offset
936 public function popTrace()
938 if ($this->smarty
->debugging
) {
939 Smarty_Internal_Debug
::end_compile($this->template
);
941 $r = array_pop($this->trace_stack
);
942 $this->smarty
->_current_file
= $r[0];
943 $this->trace_filepath
= $r[1];
944 $this->trace_uid
= $r[2];
945 $this->trace_line_offset
= $r[3];
946 if ($this->smarty
->debugging
) {
947 Smarty_Internal_Debug
::start_compile($this->template
);
952 * display compiler error messages without dying
953 * If parameter $args is empty it is a parser detected syntax error.
954 * In this case the parser is called to obtain information about expected tokens.
955 * If parameter $args contains a string this is used as error message
957 * @param string $args individual error message or null
958 * @param string $line line-number
960 * @throws SmartyCompilerException when an unexpected token is found
962 public function trigger_template_error($args = null, $line = null)
964 // get template source line which has error
966 $line = $this->lex
->line
;
968 // $line += $this->trace_line_offset;
969 $match = preg_split("/\n/", $this->lex
->data
);
970 $error_text = 'Syntax error in template "' . (empty($this->trace_filepath
) ?
$this->template
->source
->filepath
: $this->trace_filepath
) . '" on line ' . ($line +
$this->trace_line_offset
) . ' "' . trim(preg_replace('![\t\r\n]+!', ' ', $match[$line - 1])) . '" ';
972 // individual error message
973 $error_text .= $args;
976 // expected token from parser
977 $error_text .= ' - Unexpected "' . $this->lex
->value
. '"';
978 if (count($this->parser
->yy_get_expected_tokens($this->parser
->yymajor
)) <= 4) {
979 foreach ($this->parser
->yy_get_expected_tokens($this->parser
->yymajor
) as $token) {
980 $exp_token = $this->parser
->yyTokenName
[$token];
981 if (isset($this->lex
->smarty_token_names
[$exp_token])) {
982 // token type from lexer
983 $expect[] = '"' . $this->lex
->smarty_token_names
[$exp_token] . '"';
985 // otherwise internal token name
986 $expect[] = $this->parser
->yyTokenName
[$token];
989 $error_text .= ', expected one of: ' . implode(' , ', $expect);
992 $e = new SmartyCompilerException($error_text);
994 $e->source
= trim(preg_replace('![\t\r\n]+!', ' ', $match[$line - 1]));
996 $e->template
= $this->template
->source
->filepath
;