scope into smarty template

i’m very much fan of smarty templating. though it has many draw back but it tiny and strait froward for a small project. for smarty the varaible scope within template is very much complex. you cannot change a variable value from outside of the template.

let me explain the senario…

suppose i have a base template. named “main.tpl”

<html>
<head><title>title of the page</title></head>
<body>
<h1>your page head</h1>
{assign var="client_cur_location" value="You are now at home page."}
{include file="products.tpl" scope="global"}
<div id="pagloc">{$client_cur_location}</div>
</body>
</html>

now your products.tpl

{assign var="client_cur_location" value="<a href=\"index.php\">Home</a> &gt;&gt; Product"}
this is product listing page.

so you need to display the current location but from your included page. its not possible by smarty engin through included page. cause included page variable scope is totally local variable. here i found a solution from php mailing list. but unfortunatly it have bug when php function array_marge is changed for PHP 5

following is the complete modified, tested and working code…

/* Smarty_Compiler.class.php [near line # 950 ~ 975] */
 function _compile_include_tag($tag_args)
 {
 $attrs = $this->_parse_attrs($tag_args);

 // ADD NEXT LINE (default value of the param scope = local).
 $scope_action = "\$this->_tpl_vars = array_merge((array)\$_smarty_tpl_vars, (array)\$GLOBALS[\"_smarty_tpl_vars_temp\"]);\n";

 $arg_list = array();

 if (empty($attrs['file'])) {
 $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__);
 }

 foreach ($attrs as $arg_name => $arg_value) {
 if ($arg_name == 'file') {
 $include_file = $arg_value;
 continue;
 } else if ($arg_name == 'assign') {
 $assign_var = $arg_value;
 continue;
 }
 // ADD: Startin block
 else if( $arg_name == 'scope' )
 {
 $scope = @$this->_dequote($arg_value);
 if( $scope != 'local' &&
 $scope != 'parent' &&
 $scope != 'global')
 $this->_syntax_error("invalid 'scope' attribute value");
 if( $scope == 'parent' )
 $scope_action = "";
 if( $scope == 'global' )
 {
 $scope_action = "".
 "\$array_diff = array_diff( array_keys(\$this->_tpl_vars), array_keys(\$_smarty_tpl_vars) );".
 "foreach( \$array_diff as \$key=>\$value ){".
 "\$GLOBALS[\"_smarty_tpl_vars_temp\"][\$value] = \$this->_tpl_vars[\$value];\n".
 "}";
 }
 }
 // Ending block

 if (is_bool($arg_value))
 $arg_value = $arg_value ? 'true' : 'false';
 // REPLACE THIS LINE WITH THE NEXT TWO
 // $arg_list[] = "'$arg_name' => $arg_value";
 if( $arg_name != 'scope' )
 $arg_list[] = "'$arg_name' => $arg_value";

 }

 $output = '<?php ';

 if (isset($assign_var)) {
 $output .= "ob_start();\n";
 }

 $output .=
 "\$_smarty_tpl_vars = \$this->_tpl_vars;\n";

 $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))";
 $output .= "\$this->_smarty_include($_params);\n" .

 // REPLACE THIS LINE WITH THE NEXT ONE
 // "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" .
 $scope_action."\n".

 "unset(\$_smarty_tpl_vars);\n";
/*        original code
 "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" .
 "unset(\$_smarty_tpl_vars);\n";        */

 if (isset($assign_var)) {
 $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n";
 }

 $output .= ' ?>';

 return $output;

 }

The value accepted for the *scope* param are: global|parent|local.
default value is *local*.

please add your valuable comment how can we improve our scope usability into our code.

please note, above php code originally is not mine. i just modified and fix the bug.

Advertisements

Newer entries »