|
Smarty
WARNING: All discussion is moving to https://reddit.com/r/smarty, please go there! This forum will be closing soon. |
|
View previous topic :: View next topic |
Author |
Message |
brettz9 Smarty Regular
Joined: 07 Jul 2006 Posts: 93
|
Posted: Sun Aug 20, 2006 3:01 am Post subject: Switch control structures |
|
|
Not essential of course, but it might be nice to have a switch control structure added...
e.g., with {/case} being optionally insertable as equivalent to "break;"
Code: |
{switch $var}
{case 'greeting'}
Hello
{/case}
{case 'farewell'}
Goodbye and
{case 'night'}
Good night
{/case}
{default}
Hi
{/switch} |
I think switch may be even more useful for Smarty than for regular PHP in that Smarty is supposed to generally be accepting simpler input....So this might also be useful as an alternative to setting a number of independent flags (i.e., one flag could be given a different value within the script---e.g., usertype_flag which could have the value of admin, user, etc., and then tested within the template via switch).
This would also simplify the PHP side as one did not need to think of new flag names--just the values. |
|
Back to top |
|
cowboystyle Smarty Rookie
Joined: 02 Oct 2006 Posts: 5 Location: New York, NY
|
Posted: Mon Oct 02, 2006 4:07 pm Post subject: |
|
|
throwing my support for this feature, wondering whether mulitple {if}{elseif}{/if} statements are slower than an implementation of {switch}. |
|
Back to top |
|
boots Administrator
Joined: 16 Apr 2003 Posts: 5611 Location: Toronto, Canada
|
Posted: Wed Oct 04, 2006 7:31 pm Post subject: |
|
|
Long ago, messju posted a "page" plugin that does this. Maybe search the forums to find it. |
|
Back to top |
|
brettz9 Smarty Regular
Joined: 07 Jul 2006 Posts: 93
|
Posted: Thu Oct 05, 2006 5:04 am Post subject: |
|
|
Thanks... I found it here: http://www.phpinsider.com/smarty-forum/viewtopic.php?t=296&highlight=switch+plugin
I presume tigger_error in the code should be trigger_error.
I haven't tested it yet for omitting the closing {/page} tags to see if one can nest them and thus allow brevity in the code.
However, it seems that by having to repeat the variable, some of the point of using the structure (brevity) is rendered moot. |
|
Back to top |
|
boots Administrator
Joined: 16 Apr 2003 Posts: 5611 Location: Toronto, Canada
|
Posted: Thu Oct 05, 2006 2:11 pm Post subject: |
|
|
You can probably rewrite it as a compiler plugin to avoid the "brevity" issue -- but I'm not much a fun of plainly replicating every control structure found in GP languages. |
|
Back to top |
|
brettz9 Smarty Regular
Joined: 07 Jul 2006 Posts: 93
|
Posted: Fri Feb 09, 2007 10:49 am Post subject: |
|
|
Howdy,
In response to boots' last post (now a good while ago), I should say that I've seen several requests in the forums for a switch structure (including one in German too). I think it's not just having it to have one...A switch can not only be shorter but also make things easier to read, and I think it really is suitable for Smarty where the often simple logic only would require a 'case' statement (e.g., going through flags depending on access).
One idea I was thinking about (which is not in any language that I'm familiar with--what's GP by the way?) is to allow an if-else to work like a switch-case in regards to allowing the code to continue into the next loop whenever there is not a break of sorts. Although this would be nice in PHP too (e.g., if you let out a '}'), I would imagine it could also conceivably be done in Smarty too...
e.g.,
Code: |
{if $num < 2}
That's a little number!
{elseif $num < 10}
Your number is too small.
{/elseif}
{else}
Ok
{/else}
|
If the number were "1", it would thus print both "That's a little number!" and "Your number is too small" (and then stop).
I think this could make less redundant code. If people find switches useful, why not this too? (Though I'm pretty sure it would mess people up to use the same names and suddenly change on them.) Just sharing the idea (and I bet someone somewhere's already done this in some language or other), but it is the switch that I'm really interested in (and don't think I'll find enough time to try to hash it out on my own). |
|
Back to top |
|
pynej Smarty Rookie
Joined: 07 Mar 2008 Posts: 8
|
Posted: Fri Mar 07, 2008 5:21 pm Post subject: Working Smarty Switch Plugin: UPDATED |
|
|
There is a complete and working switch plugin. It works exactly as a php switch and you can even use variables and modifiers for the conditions. Feel free to use it and let me know if you have and problems.
03/08/2008 - Updated to version 2
This update changes the break attribute to work how you would expect. That is, setting the break attribute will cause smarty to automatically render a {break} tag before it starts the NEXT case or default section. I strongly recommend updating to this version of the switch plugin, as the older version was very counter intuitive in this aspect.
02/09/2010 - Updated to version 3
An updated version of my switch plugin for Smarty 3 is available here. (The Smarty 3 version is not backward compatible so I will leave this post in-tacked. The new version can be downloaded from the above link.)
(Also, this does work with nested switches, witch is why you see it accessing the _switchData variable. Be sure to not alter this variable in smarty code, as it will make the switches behave incorrectly.)
* Both of these blocks will produce identical switch logic.
Code: |
{case 1 break}
Code 1
{case 2}
Code 2
{default break}
Code 3
|
Code: |
{case 1}
Code 1
{break}
{case 2}
Code 2
{default}
Code 3
{break}
|
03/08/2008 - Updated to version 2.1
Added {/case} tag, this is identical to {break}.
compiler.switch.php
Code: |
<?php
/**
* Switch statement plugin for smarty.
* This smarty plugin provides php switch statement functionality in smarty tags.
* To install this plugin just drop it into your smarty plugins folder.
*
* @author Jeremy Pyne <jeremy.pyne@gmail.com>
* - Donations accepted via PayPal at the above address.
* - Updated: 03/08/2008 - Version 2
* - File: smarty/plugins/compiler.switch.php
* - Updates
* Version 2:
* Changed the break attribute to cause a break to be printed before the next case, instead of before this
* case. This way makes more sense and simplifies the code. This change in incompatible with code in
* from version one. This is written to support nested switches and will work as expected.
* Version 2.1:
* Added {/case} tag, this is identical to {break}.
* - Bugs/Notes:
* If you are using the short form, you must case condition before the break option. In long hand this is
* not necessary.
*
* @package Smarty
* @subpackage plugins
*
* Sample usage:
* <code>
* {foreach item=$debugItem from=$debugData}
* // Switch on $debugItem.type
* {switch $debugItem.type}
* {case 1}
* {case "invalid_field"}
* // Case checks for string and numbers.
* {/case}
* {case $postError}
* {case $getError|cat:"_ajax"|lower}
* // Case checks can also use variables and modifiers.
* {break}
* {default}
* // Default case is supported.
* {/switch}
* {/foreach}
* </code>
*
* Note in the above example that the break statements work exactly as expected. Also the switch and default
* tags can take the break attribute. If set they will break automatically before the next case is printed.
*
* Both blocks produce the same switch logic:
* <code>
* {case 1 break}
* Code 1
* {case 2}
* Code 2
* {default break}
* Code 3
* </code>
*
* <code>
* {case 1}
* Code 1
* {break}
* {case 2}
* Code 2
* {default}
* Code 3
* {break}
* </code>
*
* Finally, there is an alternate long hand style for the switch statments that you may need to use in some cases.
*
* <code>
* {switch var=$type}
* {case value="box" break=true}
* {case value="line"}
* {break}
* {default}
* {/switch}
*/
// Register the other smarty methods in this file.
// smarty_compiler_switch is automatically registered.
$this->register_compiler_function('case', 'smarty_compiler_case');
$this->register_compiler_function('default', 'smarty_compiler_default');
$this->register_compiler_function('break', 'smarty_compiler_break');
$this->register_compiler_function('/case', 'smarty_compiler_break');
$this->register_compiler_function('/switch', 'smarty_compiler_endswitch');
$this->register_postfilter('smarty_postfilter_switch');
/**
* Start a new switch statement.
* A variable must be passed to switch on.
* Also, the switch can only directly contain {case} and {default} tags.
*
* @param string $tag_arg
* @param Smarty_Compiler $smarty
* @return string
*/
function smarty_compiler_switch($tag_arg, &$smarty) {
// Add var= if needed.
if(strpos($tag_arg, 'var=') === false)
$tag_arg = 'var='.$tag_arg;
// Run the smarty code passed in.
$_params = $smarty->_parse_attrs($tag_arg);
// Make sure we have a var.
if (!isset($_params['var'])) {
$smarty->_syntax_error("switch: missing 'var' parameter", E_USER_WARNING);
return;
}
// Get the switch data.
$switchData =& $smarty->get_template_vars("_switchData");
// Add a new switch data array.
if(is_null($switchData)) {
$switchData = array();
$smarty->assign_by_ref("_switchData", $switchData);
}
// Turn auto-break off.
array_unshift($switchData, false);
// Return the switch.
return "switch ({$_params['var']}) {";
}
/**
* Print out a case line for this switch.
* A condition must be passed to match on.
* This can only go in {switch} tags.
* If break is passed, a {break} will be rendered before the next case.
*
* @param string $tag_arg
* @param Smarty_Compiler $smarty
* @return string
*/
function smarty_compiler_case($tag_arg, &$smarty) {
// Add value= if needed.
if(strpos($tag_arg, 'value=') === false)
$tag_arg = 'value='.$tag_arg;
// Change break to break=true
$tag_arg = preg_replace('/ break$/', ' break=true', $tag_arg);
// Run the smarty code passed in.
$_params = $smarty->_parse_attrs($tag_arg);
// Make sure we have a value.
if (!isset($_params['value'])) {
$smarty->_syntax_error("switch: missing 'value' parameter", E_USER_WARNING);
return;
}
// Get the switch data, and fetch the current auto-break value.
$switchData =& $smarty->get_template_vars("_switchData");
$break =& $switchData[0];
// If auto-break is on, break before the new case.
$return = ($break ? 'break; ' :'') . "case {$_params['value']}:";
// If the break attribute was passed, set the auto-break for the next case.
$break = (array_key_exists('break', $_params) && $_params['break'] == 'true');
return $return;
}
/**
* Print out a default line for this switch.
* This can only go in {switch} tags.
* If break is passed, a {break} will be rendered before the next case.
*
* @param string $tag_arg
* @param Smarty_Compiler $smarty
* @return string
*/
function smarty_compiler_default($tag_arg, &$smarty) {
// Change break to break=true
$tag_arg = preg_replace('/break$/', ' break=true', $tag_arg);
// Run the smarty code passed in.
$_params = $smarty->_parse_attrs($tag_arg);
// Get the switch data, and fetch the current auto-break value.
$switchData =& $smarty->get_template_vars("_switchData");
$break =& $switchData[0];
// If auto-break is on, break before the new case.
$return = ($break ? 'break; ' :'') . 'default;';
// If the break attribute was passed, set the auto-break for the next case.
$break = (array_key_exists('break', $_params) && $_params['break'] == 'true');
return $return;
}
/**
* Print out a break command for the switch.
* This can only go inside of {case} tags.
*
* @param string $tag_arg
* @param Smarty_Compiler $smarty
* @return string
*/
function smarty_compiler_break($tag_arg, &$smarty) {
return "break;";
}
/**
* End a switch statement.
*
* @param string $tag_arg
* @param Smarty_Compiler $smarty
* @return string
*/
function smarty_compiler_endswitch($tag_arg, &$smarty) {
$switchData =& $smarty->get_template_vars("_switchData");
array_shift($switchData);
return "}";
}
/**
* Filter the template after it is generated to fix switch bugs.
* Remove any spaces after the 'switch () {' code and before the first switch. Any tabs or spaces
* for layout would cause php errors witch this reged will fix.
*
* @param string $compiled
* @param Smarty_Compiler $smarty
* @return string
*/
function smarty_postfilter_switch($compiled, &$smarty) {
// Remove the extra spaces after the start of the switch tag and before the first case statement.
return preg_replace('/({ \?>)\s+(<\?php case)/', "$1\n$2", $compiled);
}
?>
|
Last edited by pynej on Tue Feb 09, 2010 4:59 pm; edited 6 times in total |
|
Back to top |
|
brettz9 Smarty Regular
Joined: 07 Jul 2006 Posts: 93
|
Posted: Sat Mar 08, 2008 12:17 am Post subject: |
|
|
I'm eager to check it out, thanks!
Brett |
|
Back to top |
|
brettz9 Smarty Regular
Joined: 07 Jul 2006 Posts: 93
|
Posted: Sat Mar 08, 2008 12:32 am Post subject: |
|
|
In looking at your comments, you had the following which you said were identical:
Code: |
* {case 1}
* {case 2 break}
* {default break}
* {case 1}
* {break}
* {case 2}
* {break}
* {default} |
To really be the same, wouldn't the first need to have "break" inside of it too?
Also, there is this in one example:
Code: | * {case value="line" break=true}
* {break} |
Would it really be necessary to have and also ?
thanks,
Brett |
|
Back to top |
|
brettz9 Smarty Regular
Joined: 07 Jul 2006 Posts: 93
|
Posted: Sat Mar 08, 2008 12:54 am Post subject: |
|
|
Also, I'm not clear on how dumping the file in the plugins directory will cause the file to be found if plugins are only called on demand? |
|
Back to top |
|
pynej Smarty Rookie
Joined: 07 Mar 2008 Posts: 8
|
Posted: Sat Mar 08, 2008 8:52 pm Post subject: Notes: |
|
|
As for the break attribute. Due to how the smarty syntax works, passing the break attribute DOESN'T cause the current case to automatically break, Rather it prints a break tag BEFORE the case take. That is, calling {case X break} will acutely render as the following.
This is something I can look into changing to work in the way you are thinking of, IE to break after this tag but before the next case tag, but I will have to update the code.
A for plugins, I wasn't clear in the initial post You have to save this code into a file named compiler.switch.php in you plugins directory. It will automatically be loaded the first time smarty runs a switch tag. |
|
Back to top |
|
pynej Smarty Rookie
Joined: 07 Mar 2008 Posts: 8
|
Posted: Sat Mar 08, 2008 10:13 pm Post subject: |
|
|
Ignore the last message. I have updated the code so that
Code: |
{case logic break}
Code
|
will render as
Code: |
{case logic}
Code
{break}
|
The changes can be found in my original code, and I strongly recommend upgrading. |
|
Back to top |
|
brettz9 Smarty Regular
Joined: 07 Jul 2006 Posts: 93
|
Posted: Sun Mar 09, 2008 3:00 am Post subject: |
|
|
Now, that is awesome, thank you! I hope that can make it into a new release for sure... (and messju's "macro" for hierarchical recursion as well)
Brett |
|
Back to top |
|
pynej Smarty Rookie
Joined: 07 Mar 2008 Posts: 8
|
Posted: Sun Mar 09, 2008 4:53 am Post subject: |
|
|
Added a {/case} tag. This is the same as {break} |
|
Back to top |
|
brettz9 Smarty Regular
Joined: 07 Jul 2006 Posts: 93
|
Posted: Sun Mar 30, 2008 3:04 am Post subject: |
|
|
Just letting you know I've been using the switch and it works like a charm... Nice and elegant...
One other convenience feature I can think of is to allow the switch to specify a default behavior for its cases (break or not to break)
thanks,
Brett |
|
Back to top |
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|
|