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
26 public $smarty = null;
29 * hash for nocache sections
33 public $nocache_hash = null;
36 * suppress generation of nocache code
40 public $suppressNocacheProcessing = false;
47 public static $_tag_objects = array();
54 public $_tag_stack = array();
59 * @var Smarty_Internal_Template
61 public $template = null;
64 * merged included sub template data
68 public $mergedSubTemplatesData = array();
71 * merged sub template code
75 public $mergedSubTemplatesCode = array();
78 * collected template properties during compilation
82 public $templateProperties = array();
85 * sources which must be compiled
89 public $sources = array();
92 * flag that we are inside {block}
96 public $inheritance = false;
99 * flag when compiling inheritance child template
103 public $inheritance_child = false;
106 * uid of templates called by {extends} for recursion check
110 public $extends_uid = array();
113 * source line offset for error messages
117 public $trace_line_offset = 0;
124 public $trace_uid = '';
131 public $trace_filepath = '';
134 * stack for tracing file and line of nested {block} tags
138 public $trace_stack = array();
141 * plugins loaded by default plugin handler
145 public $default_handler_plugins = array();
148 * saved preprocessed modifier list
152 public $default_modifier_list = null;
155 * force compilation of complete template as nocache
159 public $forceNocache = false;
162 * suppress Smarty header code in compiled template
166 public $suppressHeader = false;
169 * suppress template property header code in compiled template
173 public $suppressTemplatePropertyHeader = false;
176 * suppress pre and post filter
180 public $suppressFilter = false;
183 * flag if compiled template file shall we written
187 public $write_compiled_code = true;
190 * flag if currently a template function is compiled
194 public $compiles_template_function = false;
197 * called sub functions from template function
201 public $called_functions = array();
204 * compiled template function code
208 public $templateFunctionCode = '';
211 * php_handling setting either from Smarty or security
215 public $php_handling = 0;
218 * flags for used modifier plugins
222 public $modifier_plugins = array();
225 * type of already compiled modifier
229 public $known_modifier_type = array();
232 * parent compiler object for merged subtemplates and template functions
234 * @var Smarty_Internal_TemplateCompilerBase
236 public $parent_compiler = null;
239 * Flag true when compiling nocache section
243 public $nocache = false;
246 * Flag true when tag is compiled as nocache
250 public $tag_nocache = false;
253 * Flag to restart parsing
257 public $abort_and_recompile = false;
260 * Compiled tag prefix code
264 public $prefix_code = array();
271 public $prefixCodeStack = array();
274 * Tag has compiled code
278 public $has_code = false;
281 * A variable string was compiled
285 public $has_variable_string = false;
292 public $has_output = false;
299 public $stripRegEx = '![\t ]*[\r\n]+[\t ]*!';
302 * method to compile a Smarty template
304 * @param mixed $_content template source
306 * @return bool true if compiling succeeded, false if it failed
308 abstract protected function doCompile($_content);
311 * Initialize compiler
313 public function __construct()
315 $this->nocache_hash
= str_replace(array('.', ','), '_', uniqid(rand(), true));
319 * Method to compile a Smarty template
321 * @param Smarty_Internal_Template $template template object to compile
322 * @param bool $nocache true is shall be compiled in nocache mode
323 * @param null|Smarty_Internal_TemplateCompilerBase $parent_compiler
325 * @return bool true if compiling succeeded, false if it failed
327 public function compileTemplate(Smarty_Internal_Template
$template, $nocache = null, $parent_compiler = null)
329 // save template object in compiler class
330 $this->template
= $template;
331 if (isset($this->template
->smarty
->security_policy
)) {
332 $this->php_handling
= $this->template
->smarty
->security_policy
->php_handling
;
334 $this->php_handling
= $this->template
->smarty
->php_handling
;
336 $this->parent_compiler
= $parent_compiler ?
$parent_compiler : $this;
337 $nocache = isset($nocache) ?
$nocache : false;
338 if (empty($template->properties
['nocache_hash'])) {
339 $template->properties
['nocache_hash'] = $this->nocache_hash
;
341 $this->nocache_hash
= $template->properties
['nocache_hash'];
343 // flag for nochache sections
344 $this->nocache
= $nocache;
345 $this->tag_nocache
= false;
346 // reset has nocache code flag
347 $this->template
->has_nocache_code
= false;
348 $save_source = $this->template
->source
;
349 // template header code
350 $template_header = '';
351 if (!$this->suppressHeader
) {
352 $template_header .= "<?php /* Smarty version " . Smarty
::SMARTY_VERSION
. ", created on " . strftime("%Y-%m-%d %H:%M:%S") . "\n";
353 $template_header .= " compiled from \"" . $this->template
->source
->filepath
. "\" */ ?>\n";
356 if (empty($this->template
->source
->components
)) {
357 $this->sources
= array($template->source
);
359 // we have array of inheritance templates by extends: resource
360 $this->sources
= array_reverse($template->source
->components
);
363 // the $this->sources array can get additional elements while compiling by the {extends} tag
364 while ($this->template
->source
= array_shift($this->sources
)) {
365 $this->smarty
->_current_file
= $this->template
->source
->filepath
;
366 if ($this->smarty
->debugging
) {
367 Smarty_Internal_Debug
::start_compile($this->template
);
369 $no_sources = count($this->sources
);
370 $this->parent_compiler
->template
->properties
['file_dependency'][$this->template
->source
->uid
] = array($this->template
->source
->filepath
, $this->template
->source
->timestamp
, $this->template
->source
->type
);
373 $this->inheritance_child
= true;
375 $this->inheritance_child
= false;
378 // flag for nochache sections
379 $this->nocache
= $nocache;
380 $this->tag_nocache
= false;
381 // reset has nocache code flag
382 $this->template
->has_nocache_code
= false;
383 $this->has_variable_string
= false;
384 $this->prefix_code
= array();
385 $_compiled_code = '';
386 // flag for aborting current and start recompile
387 $this->abort_and_recompile
= false;
388 // get template source
389 $_content = $this->template
->source
->content
;
390 if ($_content != '') {
391 // run prefilter if required
392 if ((isset($this->smarty
->autoload_filters
['pre']) ||
isset($this->smarty
->registered_filters
['pre'])) && !$this->suppressFilter
) {
393 $_content = Smarty_Internal_Filter_Handler
::runFilter('pre', $_content, $template);
396 $_compiled_code = $this->doCompile($_content, true);
398 } while ($this->abort_and_recompile
);
399 if ($this->smarty
->debugging
) {
400 Smarty_Internal_Debug
::end_compile($this->template
);
404 $this->template
->source
= $save_source;
406 $this->smarty
->_current_file
= $this->template
->source
->filepath
;
408 unset($this->parser
->root_buffer
, $this->parser
->current_buffer
, $this->parser
, $this->lex
);
409 self
::$_tag_objects = array();
410 // return compiled code to template object
412 if (!empty($this->mergedSubTemplatesCode
)) {
413 foreach ($this->mergedSubTemplatesCode
as $code) {
414 $merged_code .= $code;
417 // run postfilter if required on compiled template code
418 if ((isset($this->smarty
->autoload_filters
['post']) ||
isset($this->smarty
->registered_filters
['post'])) && !$this->suppressFilter
&& $_compiled_code != '') {
419 $_compiled_code = Smarty_Internal_Filter_Handler
::runFilter('post', $_compiled_code, $template);
421 if ($this->suppressTemplatePropertyHeader
) {
422 $_compiled_code .= $merged_code;
424 $_compiled_code = $template_header . Smarty_Internal_Extension_CodeFrame
::create($template, $_compiled_code) . $merged_code;
426 if (!empty($this->templateFunctionCode
)) {
427 // run postfilter if required on compiled template code
428 if ((isset($this->smarty
->autoload_filters
['post']) ||
isset($this->smarty
->registered_filters
['post'])) && !$this->suppressFilter
) {
429 $_compiled_code .= Smarty_Internal_Filter_Handler
::runFilter('post', $this->templateFunctionCode
, $template);
431 $_compiled_code .= $this->templateFunctionCode
;
434 // unset content because template inheritance could have replace source with parent code
435 unset ($template->source
->content
);
436 $this->parent_compiler
= null;
437 $this->template
= null;
438 return $_compiled_code;
443 * This is a call back from the lexer/parser
445 * Save current prefix code
447 * Merge tag prefix code with saved one
448 * (required nested tags in attributes)
450 * @param string $tag tag name
451 * @param array $args array with tag attributes
452 * @param array $parameter array with compilation parameter
454 * @throws SmartyCompilerException
455 * @throws SmartyException
456 * @return string compiled code
458 public function compileTag($tag, $args, $parameter = array())
460 $this->prefixCodeStack
[] = $this->prefix_code
;
461 $this->prefix_code
= array();
462 $result = $this->compileTag2($tag, $args, $parameter);
463 $this->prefix_code
= array_merge($this->prefix_code
, array_pop($this->prefixCodeStack
));
470 * @param string $tag tag name
471 * @param array $args array with tag attributes
472 * @param array $parameter array with compilation parameter
474 * @throws SmartyCompilerException
475 * @throws SmartyException
476 * @return string compiled code
478 private function compileTag2($tag, $args, $parameter)
481 // $args contains the attributes parsed and compiled by the lexer/parser
482 // assume that tag does compile into code, but creates no HTML output
483 $this->has_code
= true;
484 $this->has_output
= false;
485 // log tag/attributes
486 if (isset($this->smarty
->get_used_tags
) && $this->smarty
->get_used_tags
) {
487 $this->template
->used_tags
[] = array($tag, $args);
489 // check nocache option flag
490 if (in_array("'nocache'", $args) ||
in_array(array('nocache' => 'true'), $args) ||
in_array(array('nocache' => '"true"'), $args) ||
in_array(array('nocache' => "'true'"), $args)
492 $this->tag_nocache
= true;
494 // compile the smarty tag (required compile classes to compile the tag are autoloaded)
495 if (($_output = $this->callTagCompiler($tag, $args, $parameter)) === false) {
496 if (isset($this->parent_compiler
->templateProperties
['tpl_function'][$tag])) {
497 // template defined by {template} tag
498 $args['_attr']['name'] = "'" . $tag . "'";
499 $_output = $this->callTagCompiler('call', $args, $parameter);
502 if ($_output !== false) {
503 if ($_output !== true) {
504 // did we get compiled code
505 if ($this->has_code
) {
506 // Does it create output?
507 if ($this->has_output
) {
510 // return compiled code
514 // tag did not produce compiled code
517 // map_named attributes
518 if (isset($args['_attr'])) {
519 foreach ($args['_attr'] as $key => $attribute) {
520 if (is_array($attribute)) {
521 $args = array_merge($args, $attribute);
525 // not an internal compiler tag
526 if (strlen($tag) < 6 ||
substr($tag, - 5) != 'close') {
527 // check if tag is a registered object
528 if (isset($this->smarty
->registered_objects
[$tag]) && isset($parameter['object_method'])) {
529 $method = $parameter['object_method'];
530 if (!in_array($method, $this->smarty
->registered_objects
[$tag][3]) && (empty($this->smarty
->registered_objects
[$tag][1]) ||
in_array($method, $this->smarty
->registered_objects
[$tag][1]))
532 return $this->callTagCompiler('private_object_function', $args, $parameter, $tag, $method);
533 } elseif (in_array($method, $this->smarty
->registered_objects
[$tag][3])) {
534 return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $method);
537 $this->trigger_template_error('not allowed method "' . $method . '" in registered object "' . $tag . '"', $this->lex
->taglineno
);
540 // check if tag is registered
541 foreach (array(Smarty
::PLUGIN_COMPILER
, Smarty
::PLUGIN_FUNCTION
, Smarty
::PLUGIN_BLOCK
) as $plugin_type) {
542 if (isset($this->smarty
->registered_plugins
[$plugin_type][$tag])) {
543 // if compiler function plugin call it now
544 if ($plugin_type == Smarty
::PLUGIN_COMPILER
) {
546 foreach ($args as $key => $mixed) {
547 if (is_array($mixed)) {
548 $new_args = array_merge($new_args, $mixed);
550 $new_args[$key] = $mixed;
553 if (!$this->smarty
->registered_plugins
[$plugin_type][$tag][1]) {
554 $this->tag_nocache
= true;
556 $function = $this->smarty
->registered_plugins
[$plugin_type][$tag][0];
557 if (!is_array($function)) {
558 return $function($new_args, $this);
559 } elseif (is_object($function[0])) {
560 return $this->smarty
->registered_plugins
[$plugin_type][$tag][0][0]->$function[1]($new_args, $this);
562 return call_user_func_array($function, array($new_args, $this));
565 // compile registered function or block function
566 if ($plugin_type == Smarty
::PLUGIN_FUNCTION ||
$plugin_type == Smarty
::PLUGIN_BLOCK
) {
567 return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter, $tag);
571 // check plugins from plugins folder
572 foreach ($this->smarty
->plugin_search_order
as $plugin_type) {
573 if ($plugin_type == Smarty
::PLUGIN_COMPILER
&& $this->smarty
->loadPlugin('smarty_compiler_' . $tag) && (!isset($this->smarty
->security_policy
) ||
$this->smarty
->security_policy
->isTrustedTag($tag, $this))) {
574 $plugin = 'smarty_compiler_' . $tag;
575 if (is_callable($plugin)) {
576 // convert arguments format for old compiler plugins
578 foreach ($args as $key => $mixed) {
579 if (is_array($mixed)) {
580 $new_args = array_merge($new_args, $mixed);
582 $new_args[$key] = $mixed;
586 return $plugin($new_args, $this->smarty
);
588 if (class_exists($plugin, false)) {
589 $plugin_object = new $plugin;
590 if (method_exists($plugin_object, 'compile')) {
591 return $plugin_object->compile($args, $this);
594 throw new SmartyException("Plugin \"{$tag}\" not callable");
596 if ($function = $this->getPlugin($tag, $plugin_type)) {
597 if (!isset($this->smarty
->security_policy
) ||
$this->smarty
->security_policy
->isTrustedTag($tag, $this)) {
598 return $this->callTagCompiler('private_' . $plugin_type . '_plugin', $args, $parameter, $tag, $function);
603 if (is_callable($this->smarty
->default_plugin_handler_func
)) {
605 // look for already resolved tags
606 foreach ($this->smarty
->plugin_search_order
as $plugin_type) {
607 if (isset($this->default_handler_plugins
[$plugin_type][$tag])) {
613 // call default handler
614 foreach ($this->smarty
->plugin_search_order
as $plugin_type) {
615 if ($this->getPluginFromDefaultHandler($tag, $plugin_type)) {
622 // if compiler function plugin call it now
623 if ($plugin_type == Smarty
::PLUGIN_COMPILER
) {
625 foreach ($args as $mixed) {
626 $new_args = array_merge($new_args, $mixed);
628 $function = $this->default_handler_plugins
[$plugin_type][$tag][0];
629 if (!is_array($function)) {
630 return $function($new_args, $this);
631 } elseif (is_object($function[0])) {
632 return $this->default_handler_plugins
[$plugin_type][$tag][0][0]->$function[1]($new_args, $this);
634 return call_user_func_array($function, array($new_args, $this));
637 return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter, $tag);
642 // compile closing tag of block function
643 $base_tag = substr($tag, 0, - 5);
644 // check if closing tag is a registered object
645 if (isset($this->smarty
->registered_objects
[$base_tag]) && isset($parameter['object_method'])) {
646 $method = $parameter['object_method'];
647 if (in_array($method, $this->smarty
->registered_objects
[$base_tag][3])) {
648 return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $method);
651 $this->trigger_template_error('not allowed closing tag method "' . $method . '" in registered object "' . $base_tag . '"', $this->lex
->taglineno
);
654 // registered block tag ?
655 if (isset($this->smarty
->registered_plugins
[Smarty
::PLUGIN_BLOCK
][$base_tag]) ||
isset($this->default_handler_plugins
[Smarty
::PLUGIN_BLOCK
][$base_tag])) {
656 return $this->callTagCompiler('private_registered_block', $args, $parameter, $tag);
659 if ($function = $this->getPlugin($base_tag, Smarty
::PLUGIN_BLOCK
)) {
660 return $this->callTagCompiler('private_block_plugin', $args, $parameter, $tag, $function);
662 // registered compiler plugin ?
663 if (isset($this->smarty
->registered_plugins
[Smarty
::PLUGIN_COMPILER
][$tag])) {
664 // if compiler function plugin call it now
666 if (!$this->smarty
->registered_plugins
[Smarty
::PLUGIN_COMPILER
][$tag][1]) {
667 $this->tag_nocache
= true;
669 $function = $this->smarty
->registered_plugins
[Smarty
::PLUGIN_COMPILER
][$tag][0];
670 if (!is_array($function)) {
671 return $function($args, $this);
672 } elseif (is_object($function[0])) {
673 return $this->smarty
->registered_plugins
[Smarty
::PLUGIN_COMPILER
][$tag][0][0]->$function[1]($args, $this);
675 return call_user_func_array($function, array($args, $this));
678 if ($this->smarty
->loadPlugin('smarty_compiler_' . $tag)) {
679 $plugin = 'smarty_compiler_' . $tag;
680 if (is_callable($plugin)) {
681 return $plugin($args, $this->smarty
);
683 if (class_exists($plugin, false)) {
684 $plugin_object = new $plugin;
685 if (method_exists($plugin_object, 'compile')) {
686 return $plugin_object->compile($args, $this);
689 throw new SmartyException("Plugin \"{$tag}\" not callable");
692 $this->trigger_template_error("unknown tag \"" . $tag . "\"", $this->lex
->taglineno
);
699 * @param string $variable
703 public function compileVariable($variable)
705 if (strpos($variable, '(') == 0) {
706 // not a variable variable
707 $var = trim($variable, '\'');
708 $this->tag_nocache
= $this->tag_nocache |
$this->template
->getVariable($var, null, true, false)->nocache
;
709 $this->template
->properties
['variables'][$var] = $this->tag_nocache |
$this->nocache
;
711 return '$_smarty_tpl->tpl_vars[' . $variable . ']->value';
715 * This method is called from parser to process a text content section
716 * - remove text from inheritance child templates as they may generate output
717 * - strip text if strip is enabled
719 * @param string $text
721 * @return null|\Smarty_Internal_ParseTree_Text
723 public function processText($text)
725 if ($this->parser
->strip
) {
726 return new Smarty_Internal_ParseTree_Text($this->parser
, preg_replace($this->stripRegEx
, '', $text));
728 return new Smarty_Internal_ParseTree_Text($this->parser
, $text);
733 * lazy loads internal compile plugin for tag and calls the compile method
734 * compile objects cached for reuse.
735 * class name format: Smarty_Internal_Compile_TagName
736 * plugin filename format: Smarty_Internal_Tagname.php
738 * @param string $tag tag name
739 * @param array $args list of tag attributes
740 * @param mixed $param1 optional parameter
741 * @param mixed $param2 optional parameter
742 * @param mixed $param3 optional parameter
744 * @return string compiled code
746 public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null)
748 // check if tag allowed by security
749 if (!isset($this->smarty
->security_policy
) ||
$this->smarty
->security_policy
->isTrustedTag($tag, $this)) {
750 // re-use object if already exists
751 if (!isset(self
::$_tag_objects[$tag])) {
752 // lazy load internal compiler plugin
753 $class_name = 'Smarty_Internal_Compile_' . $tag;
754 if ($this->smarty
->loadPlugin($class_name)) {
755 self
::$_tag_objects[$tag] = new $class_name;
761 return self
::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3);
763 // no internal compile plugin for this tag
768 * Check for plugins and return function name
770 * @param $plugin_name
771 * @param string $plugin_type type of plugin
773 * @return string call name of function
775 public function getPlugin($plugin_name, $plugin_type)
778 if ($this->template
->caching
&& ($this->nocache ||
$this->tag_nocache
)) {
779 if (isset($this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type])) {
780 $function = $this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type]['function'];
781 } elseif (isset($this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type])) {
782 $this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type] = $this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type];
783 $function = $this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type]['function'];
786 if (isset($this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type])) {
787 $function = $this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type]['function'];
788 } elseif (isset($this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type])) {
789 $this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type] = $this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type];
790 $function = $this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type]['function'];
793 if (isset($function)) {
794 if ($plugin_type == 'modifier') {
795 $this->modifier_plugins
[$plugin_name] = true;
800 // loop through plugin dirs and find the plugin
801 $function = 'smarty_' . $plugin_type . '_' . $plugin_name;
802 $file = $this->smarty
->loadPlugin($function, false);
804 if (is_string($file)) {
805 if ($this->template
->caching
&& ($this->nocache ||
$this->tag_nocache
)) {
806 $this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type]['file'] = $file;
807 $this->template
->required_plugins
['nocache'][$plugin_name][$plugin_type]['function'] = $function;
809 $this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type]['file'] = $file;
810 $this->template
->required_plugins
['compiled'][$plugin_name][$plugin_type]['function'] = $function;
812 if ($plugin_type == 'modifier') {
813 $this->modifier_plugins
[$plugin_name] = true;
818 if (is_callable($function)) {
819 // plugin function is defined in the script
827 * Check for plugins by default plugin handler
829 * @param string $tag name of tag
830 * @param string $plugin_type type of plugin
832 * @return boolean true if found
834 public function getPluginFromDefaultHandler($tag, $plugin_type)
839 $result = call_user_func_array($this->smarty
->default_plugin_handler_func
, array($tag, $plugin_type, $this->template
, &$callback, &$script, &$cacheable));
841 $this->tag_nocache
= $this->tag_nocache ||
!$cacheable;
842 if ($script !== null) {
843 if (is_file($script)) {
844 if ($this->template
->caching
&& ($this->nocache ||
$this->tag_nocache
)) {
845 $this->template
->required_plugins
['nocache'][$tag][$plugin_type]['file'] = $script;
846 $this->template
->required_plugins
['nocache'][$tag][$plugin_type]['function'] = $callback;
848 $this->template
->required_plugins
['compiled'][$tag][$plugin_type]['file'] = $script;
849 $this->template
->required_plugins
['compiled'][$tag][$plugin_type]['function'] = $callback;
851 require_once $script;
853 $this->trigger_template_error("Default plugin handler: Returned script file \"{$script}\" for \"{$tag}\" not found");
856 if (!is_string($callback) && !(is_array($callback) && is_string($callback[0]) && is_string($callback[1]))) {
857 $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" must be a static function name or array of class and function name");
859 if (is_callable($callback)) {
860 $this->default_handler_plugins
[$plugin_type][$tag] = array($callback, true, array());
864 $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" not callable");
872 * Append code segments and remove unneeded ?> <?php transitions
874 * @param string $left
875 * @param string $right
879 public function appendCode($left, $right)
881 if (preg_match('/\s*\?>\s*$/', $left) && preg_match('/^\s*<\?php\s+/', $right)) {
882 $left = preg_replace('/\s*\?>\s*$/', "\n", $left);
883 $left .= preg_replace('/^\s*<\?php\s+/', '', $right);
891 * Inject inline code for nocache template sections
892 * This method gets the content of each template element from the parser.
893 * If the content is compiled code and it should be not cached the code is injected
894 * into the rendered output.
896 * @param string $content content of template element
897 * @param boolean $is_code true if content is compiled code
899 * @return string content
901 public function processNocacheCode($content, $is_code)
903 // If the template is not evaluated and we have a nocache section and or a nocache tag
904 if ($is_code && !empty($content)) {
905 // generate replacement code
906 if ((!($this->template
->source
->recompiled
) ||
$this->forceNocache
) && $this->template
->caching
&& !$this->suppressNocacheProcessing
&& ($this->nocache ||
$this->tag_nocache
)
908 $this->template
->has_nocache_code
= true;
909 $_output = addcslashes($content, '\'\\');
910 $_output = str_replace("^#^", "'", $_output);
911 $_output = "<?php echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/" . $_output . "/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>\n";
912 // make sure we include modifier plugins for nocache code
913 foreach ($this->modifier_plugins
as $plugin_name => $dummy) {
914 if (isset($this->template
->required_plugins
['compiled'][$plugin_name]['modifier'])) {
915 $this->template
->required_plugins
['nocache'][$plugin_name]['modifier'] = $this->template
->required_plugins
['compiled'][$plugin_name]['modifier'];
924 $this->modifier_plugins
= array();
925 $this->suppressNocacheProcessing
= false;
926 $this->tag_nocache
= false;
932 * Generate nocache code string
934 * @param string $code PHP code
938 public function makeNocacheCode($code)
940 return "echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/<?php " . str_replace("^#^", "'", addcslashes($code, '\'\\')) . "?>/*/%%SmartyNocache:{$this->nocache_hash}%%*/';\n";
944 * push current file and line offset on stack for tracing {block} source lines
946 * @param string $file new filename
947 * @param string $uid uid of file
948 * @param int $line line offset to source
949 * @param bool $debug false debug end_compile shall not be called
951 public function pushTrace($file, $uid, $line, $debug = true)
953 if ($this->smarty
->debugging
&& $debug) {
954 Smarty_Internal_Debug
::end_compile($this->template
);
956 array_push($this->trace_stack
, array($this->smarty
->_current_file
, $this->trace_filepath
, $this->trace_uid
, $this->trace_line_offset
));
957 $this->trace_filepath
= $this->smarty
->_current_file
= $file;
958 $this->trace_uid
= $uid;
959 $this->trace_line_offset
= $line;
960 if ($this->smarty
->debugging
) {
961 Smarty_Internal_Debug
::start_compile($this->template
);
966 * restore file and line offset
968 public function popTrace()
970 if ($this->smarty
->debugging
) {
971 Smarty_Internal_Debug
::end_compile($this->template
);
973 $r = array_pop($this->trace_stack
);
974 $this->smarty
->_current_file
= $r[0];
975 $this->trace_filepath
= $r[1];
976 $this->trace_uid
= $r[2];
977 $this->trace_line_offset
= $r[3];
978 if ($this->smarty
->debugging
) {
979 Smarty_Internal_Debug
::start_compile($this->template
);
984 * display compiler error messages without dying
985 * If parameter $args is empty it is a parser detected syntax error.
986 * In this case the parser is called to obtain information about expected tokens.
987 * If parameter $args contains a string this is used as error message
989 * @param string $args individual error message or null
990 * @param string $line line-number
992 * @throws SmartyCompilerException when an unexpected token is found
994 public function trigger_template_error($args = null, $line = null)
996 // get template source line which has error
998 $line = $this->lex
->line
;
1000 // $line += $this->trace_line_offset;
1001 $match = preg_split("/\n/", $this->lex
->data
);
1002 $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])) . '" ';
1004 // individual error message
1005 $error_text .= $args;
1008 // expected token from parser
1009 $error_text .= ' - Unexpected "' . $this->lex
->value
. '"';
1010 if (count($this->parser
->yy_get_expected_tokens($this->parser
->yymajor
)) <= 4) {
1011 foreach ($this->parser
->yy_get_expected_tokens($this->parser
->yymajor
) as $token) {
1012 $exp_token = $this->parser
->yyTokenName
[$token];
1013 if (isset($this->lex
->smarty_token_names
[$exp_token])) {
1014 // token type from lexer
1015 $expect[] = '"' . $this->lex
->smarty_token_names
[$exp_token] . '"';
1017 // otherwise internal token name
1018 $expect[] = $this->parser
->yyTokenName
[$token];
1021 $error_text .= ', expected one of: ' . implode(' , ', $expect);
1024 $e = new SmartyCompilerException($error_text);
1026 $e->source
= trim(preg_replace('![\t\r\n]+!', ' ', $match[$line - 1]));
1028 $e->template
= $this->template
->source
->filepath
;