Package home | Report new bug | New search | Development Roadmap Status: Open | Feedback | All | Closed Since Version 1.3.13

Request #4405 Patch to allow overriding variable names in included templates
Submitted: 2005-05-22 12:13 UTC
From: rshaull at gmail dot com Assigned:
Status: Open Package: HTML_Template_Flexy
PHP Version: 4.3.11 OS: Slackware Linux 10
Roadmaps: (Not assigned)    
Subscription  


 [2005-05-22 12:13 UTC] rshaull at gmail dot com
Description: ------------ Using HTML_Template_Flexy 1.2.1 installed through Pear. The Flexy Compiler automatically passes variables defined in the scope of the current template into the scope of a template included with <flexy:include>. I have patched the code to allow variable names to be changed before being passed to the included template (without changing them in the calling template). This makes it easier to combine templates without have to change variable names in an included template to match the variable names in the calling template. It also makes template recursion possible. In the patched code, you can add child elements named <flexy:variableOverride> to the <flexy:include> element. This allows you to override the name of a variable being passed to the included template. For example, this _snippet_ from "element.html" (used to format the output of single elements in a form) will result in an infinite loop: ----------------------------------------------------- {foreach:elem.elements,grouped_elem} <flexy:include src="element.html" /> {end:} ----------------------------------------------------- But <flexy:variableOverride> allows you to do this: ----------------------------------------------------- {foreach:elem.elements,grouped_elem} <flexy:include src="element.html"> <flexy:variableOverride name="grouped_elem" newName="elem" /> </flexy:include> {end:} ----------------------------------------------------- ... which allows the recursive call to handle the elements from the element group. I added some comments to the function includeToString in the patch I sent to you by email, so I will not reproduce them here. The PHP code that needs to be added to function includeToString in Compiler/Flexy/Flexy.php is reproduced in this bug report. Thanks, -Ross Reproduce code: --------------- in Compiler/Flexy/Flexy.php, around line 125, add this: ----------------------------------------------------- $variableOverrides = ''; foreach($element->children as $child) { if($child->tag == 'FLEXY:VARIABLEOVERRIDE') { $current_name = $child->getAttribute('NAME'); $new_name = $child->getAttribute('NEWNAME'); if(!$current_name || !$new_name) { return $this->compiler->appendHTML("<B>Flexy:variableOverride without a new="current-name" and newName="new-name"</B>"); } $variableOverrides .= "\$_t->$new_name = \$$current_name;\n"; } } ----------------------------------------------------- Then adjust lines 143-145 to look like this: ----------------------------------------------------- "}\n" . $variableOverrides . "\$x->outputObject(\$_t, \$this->elements);\n" ----------------------------------------------------- ... note that this concatenates the $variableOverrides variable into the php code that gets stored into the template. The important point is that it happens after the assignments in lines 141-143. Expected result: ---------------- Without the patch, recursive calls to <flexy:include> can result in an infinite loop. With the patch and proper use of <flexy:variableOverride> tag(s) inside the <flexy:include> tag, an infinite loop is not generated and useful behavior can be achieved.

Comments

 [2005-05-22 20:41 UTC] rshaull at gmail dot com
I made an error in my initial report. If there is no clone function available, then the variable overrides will also apply in the calling template as well as in the child template. To solve this, I added a little code to track the variable overrides and restore the original values in the template after the child template is included. I am just going to paste the entire fixed includeToString method here. If anybody wants a proper patch file, just drop me an email. -Ross ---------------------------------------- /** * include handler * <flexy:include src="test.html"> * * May include one or more child tags: * <flexy:variableOverride name="current-name" newName="new-name"> * * Use the flexy:variableOverride tags to change the value of variables that * are passed into the scope of the included template. This overrides the * default behavior of passing all the variables in the current scope into * the template scope with their same names. The name attribute contains the * name of the variable in the current scope; attribute newName specifies the * name you want to assign the variable to in the include template's scope. * The new name can override the name of a variable that would otherwise be * passed to the include template's scope from the current template's scope. * * flexy:variableOverride makes it possible to have templates that call * themselves recursively. * * flexy:variableOverride added 19 May 2005 Ross Shaull (rshaull@gmail.com) * * @see parent::toString() */ function includeToString($element) { // // Variable Overrides // // Ross Shaull // rshaull@gmail.com // Added 19 May 2005 // // If <Flexy:Include> contains any <flexy:variableOverride> child // elements, interpret their name and newname attributes to set up a // variable override string. // // Track overridden values so that they can be replaced in the template. // This is critical because if there is no clone() function, the // overrides will be done in the current template. We restore the // overridden values after we are done with the include template. // $initVariableOverrideSystem = "\$oldValues = array();\n"; $variableOverrides = ''; $restoreOverriddenVariables = ''; foreach($element->children as $child) { if($child->tag == 'FLEXY:VARIABLEOVERRIDE') { $current_name = $child->getAttribute('NAME'); $new_name = $child->getAttribute('NEWNAME'); if(!$current_name || !$new_name) { return $this->compiler->appendHTML("<B>Flexy:variableOverride without a new="current-name" and newName="new-name"</B>"); } $variableOverrides .= "\$oldValues['$new_name'] = \$_t->$new_name;\n" . "\$_t->$new_name = \$$current_name;\n"; $restoreOverriddenVariables .= "\$_t->$new_name = \$oldValues['$new_name'];\n"; } } // this is disabled by default... // we ignore modifier pre/suffix $arg = $element->getAttribute('SRC'); if (!$arg) { return $this->compiler->appendHTML("<B>Flexy:Include without a src=filename</B>"); } // ideally it would be nice to embed the results of one template into another. // however that would involve some complex test which would have to stat // the child templates anyway.. // compile the child template.... // output... include $this->options['compiled_templates'] . $arg . $this->options['locale'] . '.php' return $this->compiler->appendPHP( "\n". "\$x = new HTML_Template_Flexy(\$this->options);\n". "\$x->compile('{$arg}');\n". "\$_t = function_exists('clone') ? clone(\$t) : \$t;\n". "foreach(get_defined_vars() as \$k=>\$v) {\n" . " if (\$k != 't') { \$_t->\$k = \$v; }\n" . "}\n" . $initVariableOverrideSystem . $variableOverrides . "\$x->outputObject(\$_t, \$this->elements);\n" . $restoreOverriddenVariables ); }