View previous topic :: View next topic |
Author |
Message |
cablehead Smarty Rookie
Joined: 09 Jul 2003 Posts: 23
|
Posted: Mon Sep 15, 2003 2:09 am Post subject: Sorting arrays inside templates |
|
|
I did a few searches for this in the forum and everyone seems to agree that its bad idea.
Just a bit curious as to why - the order of say a list of users seems like a pretty arbitary thing. I've always thought it was a presentation issue?
I've been thinking about creating a modifier that would work something like:
<table>
<tr><td>Name</td><td>Address</td></tr>
{foreach from=$users|sortby:lastName item=user}
<tr>
<td>{$user.lastName}, {$user.firstName}</td>
<td>{$user.address}</td>
</tr>
{/foreach}
</table>
Is this a bad way to go?
Thanks !
Andy. |
|
Back to top |
|
cablehead Smarty Rookie
Joined: 09 Jul 2003 Posts: 23
|
Posted: Tue Sep 16, 2003 7:02 am Post subject: |
|
|
Damn .. the sortby modifier seems to be called for each iteration of the foreach loop. Is this the expected behaviour?
Here's the code for the modifier so far. Hoping someone else is interested in this sort of thing as well.
Code: |
#
# sorts an array of named arrays by the supplied fields
# code by dholmes at jccc d0t net
# taken from http://au.php.net/function.uasort
#
function array_sort_by_fields(&$data, $sortby){
if(is_array($sortby)) {
$sortby = join(',', $sortby);
}
uasort( $data,
create_function( '$a, $b', '
$skeys = split(\',\',\''.$sortby.'\');
foreach($skeys as $key){
if( ($c = strcasecmp($a[$key],$b[$key])) != 0 ){
return($c);
}
}
return($c); '));
}
#
# Modifier: sortby - allows arrays of named arrays to be sorted by a given field
#
function smarty_modifier_sortby($arrData,$sortfields) {
return(array_sort_by_fields($arrData,$sortfields));
}
$smarty->register_modifier( "sortby", "smarty_modifier_sortby" );
|
Any feedback is greatly appreciated !
Andy. |
|
Back to top |
|
messju Administrator
Joined: 16 Apr 2003 Posts: 3336 Location: Oldenburg, Germany
|
Posted: Tue Sep 16, 2003 7:44 am Post subject: |
|
|
read http://smarty.php.net/manual/en/language.modifiers.php
it has to be Code: | {foreach from=$users|@sortby:lastName item=user}... |
(note the @) if you want to supply modifiers to arrays.
but then the modifier is still called twice (not once as would be sufficient). i don't consider this a severe bug, but i will see if this could be made leaner.
greetings
messju
(BTW to your overall question: sort order is on the borderline between display-logic and application-logic IMHO. i think it's fully valid to do this in the template like you do here.) |
|
Back to top |
|
cablehead Smarty Rookie
Joined: 09 Jul 2003 Posts: 23
|
Posted: Tue Sep 16, 2003 8:44 am Post subject: |
|
|
>> (note the @) if you want to supply modifiers to arrays.
Sorry messju. I should read the damn documentation
I also made a mistake in the modifier. Should be:
Code: |
function smarty_modifier_sortby($arrData, $sortfields) {
array_sort_by_fields($arrData, $sortfields);
return $arrData;
}
|
With messju's correction to the template code its working nicely if others were interested. I haven't tested yet but it should also allow:
Code: |
{foreach from=$users|@sortby:"lastName,firstName" item=user}
|
Thanks to the clever function by dholmes at jccc d0t net .. who ever you may be
>> i don't consider this a severe bug, but i will see if this could be made leaner.
Thank you for whatever you can do ...
Quote: |
(BTW to your overall question: sort order is on the borderline between display-logic and application-logic IMHO. i think it's fully valid to do this in the template like you do here.)
|
I agree. It's a very grey area. Sort order could be a user perference stored in a database somewhere. Or dynamicly handled by client side javascript when the user clicks on a table header.
It is handy for the template designer to quickly take control of sorting without bugging the php coder in some cases though. Allowing easy to add modifiers like the above is a good compromise I think.
mmm smarty ... you are so sweet |
|
Back to top |
|
messju Administrator
Joined: 16 Apr 2003 Posts: 3336 Location: Oldenburg, Germany
|
Posted: Tue Sep 16, 2003 12:13 pm Post subject: |
|
|
nice sort-function but i see room for optimizations in it:
- with every call to array_sort_by_fields() there is a new function created. this is only necessary if the supplied $sortby was not already used before
- the split/foreach is done with every comparason. this loop can be unrolled when creating the function. so the split/foreach has only be done once per sort and not once per comparason.
(i hope phpBB doesn't not screw up my quoting:)
[php:1:f05af6d082]function array_sort_by_fields(&$data, $sortby)
{
static $sort_funcs = array();
if (empty($sort_funcs[$sortby])) {
$code = "\$c=0;";
foreach (split(',', $sortby) as $key) {
$code .= "if ( (\$c = strcasecmp(\$a['$key'],\$b['$key'])) != 0 ) return \$c;\n";
}
$code .= 'return $c;';
$sort_func = $sort_funcs[$sortby] = create_function('$a, $b', $code);
} else {
$sort_func = $sort_funcs[$sortby];
}
uasort($data, $sort_func);
}
[/php:1:f05af6d082]
with 1000 times sorting and 8-element array by 1 or 2 keys this one is about three times faster on my test-machine. of course the performance gain is not that big by only one or two calls per page.
greetings
messju
[EDIT: removed one redundant "$sort_func = $sort_funcs[$sortby];" ]
Last edited by messju on Fri Sep 19, 2003 7:48 am; edited 1 time in total |
|
Back to top |
|
cablehead Smarty Rookie
Joined: 09 Jul 2003 Posts: 23
|
Posted: Tue Sep 16, 2003 12:40 pm Post subject: |
|
|
cheers messju.
Unrolling the split and loop is a cool idea. For large arrays that would have been getting called a lot of times.
Do you mind if I post it back to http://au.php.net/function.uasort ? Its been a year since the original author posted it there, but there might be a slim chance of them getting the update. |
|
Back to top |
|
messju Administrator
Joined: 16 Apr 2003 Posts: 3336 Location: Oldenburg, Germany
|
Posted: Tue Sep 16, 2003 12:55 pm Post subject: |
|
|
feel free |
|
Back to top |
|
pscsuk Smarty n00b
Joined: 19 Aug 2005 Posts: 2
|
Posted: Fri Aug 19, 2005 9:39 am Post subject: |
|
|
I know this is a bit 'late', but here's my modification of this. Now, you can specify
Code: | {foreach from=$users|sortby"-name, #age" item=user} |
The '-' lets you sort in reverse order, and the # lets you sort numerically rather than as a string (you can have '-#age' as well to sort numerically in reverse order)
Code: | <?php
#
# sorts an array of named arrays by the supplied fields
# code by dholmes at jccc d0t net
# taken from http://au.php.net/function.uasort
# modified by cablehead, messju and pscs at http://www.phpinsider.com/smarty-forum
function array_sort_by_fields(&$data, $sortby){
static $sort_funcs = array();
if (empty($sort_funcs[$sortby]))
{
$code = "\$c=0;";
foreach (split(',', $sortby) as $key)
{
$d = '1';
if (substr($key, 0, 1) == '-')
{
$d = '-1';
$key = substr($key, 1);
}
if (substr($key, 0, 1) == '#')
{
$key = substr($key, 1);
$code .= "if ( ( \$c = (\$a['$key'] - \$b['$key'])) != 0 ) return $d * \$c;\n";
}
else
{
$code .= "if ( (\$c = strcasecmp(\$a['$key'],\$b['$key'])) != 0 ) return $d * \$c;\n";
}
}
$code .= 'return $c;';
$sort_func = $sort_funcs[$sortby] = create_function('$a, $b', $code);
}
else
{
$sort_func = $sort_funcs[$sortby];
}
uasort($data, $sort_func);
}
#
# Modifier: sortby - allows arrays of named arrays to be sorted by a given field
#
function smarty_modifier_sortby($arrData,$sortfields) {
array_sort_by_fields($arrData,$sortfields);
return $arrData;
}
$smarty->register_modifier( "sortby", "smarty_modifier_sortby" );
?> |
Have fun. |
|
Back to top |
|
pscsuk Smarty n00b
Joined: 19 Aug 2005 Posts: 2
|
Posted: Fri Aug 19, 2005 9:51 am Post subject: |
|
|
Slight modification - change
Code: | $code .= "if ( ( \$c = (\$a['$key'] - \$b['$key'])) != 0 ) return $d * \$c;\n";
|
to
Code: | $code .= "if ( \$a['$key'] > \$b['$key']) return $d * 1;\n";
$code .= "if ( \$a['$key'] < \$b['$key']) return $d * -1;\n";
|
The original version didn't work well if the numbers were floating point and within '1' of each other - they were treated as equal. The new version works whatever. |
|
Back to top |
|
Alpha_Numeric Smarty Rookie
Joined: 18 Aug 2008 Posts: 6
|
Posted: Mon Sep 08, 2008 12:34 am Post subject: |
|
|
Hi
I am trying to use this function on a non associative array contain associative arrays, e.g.,
Code: | 0 => Array (12)
ticketsid => "1301231460"
eventid => "715574"
event => "25th Annual Putnam County Spelling Bee"
section => "BALC"
row => "D"
quantity => 4
split => Array (2)
0 => "4"
1 => "2"
saleprice => 125
listprice => 90
sellingbrokerid => 1031
non_real_time => false
notes => "BALCONY 4TH ROW SEATING" |
I just get errors and am otherwise lost. I would like to figure out how to sort based both on strings and numeric values. e.g., sort on 'event' as well as 'quantity'.
If it is something that I am doing in the install of the files I will feel much better than if the function just doesn't like data in this fashion.
Any help, greatly appreciated. |
|
Back to top |
|
Celeb Administrator
Joined: 17 Apr 2007 Posts: 1025 Location: Vienna
|
Posted: Mon Sep 08, 2008 8:32 am Post subject: |
|
|
This should work for your array:
Code: | {foreach from=$foo|@sortby:"event,#quantity"} |
_________________ Darn computers always do what I tell them to instead of what I want them to do. |
|
Back to top |
|
blackhawkmx Smarty Regular
Joined: 20 May 2005 Posts: 76
|
Posted: Mon Sep 29, 2008 6:37 pm Post subject: |
|
|
for the function above that labeled....
Code: |
function array_sort_by_fields
|
what is the name of that .php page? and is it suppose to be placed in the smarty pluggins directory?
thanks!
bh _________________ Bring it back to basics. You and I can make it right! |
|
Back to top |
|
Celeb Administrator
Joined: 17 Apr 2007 Posts: 1025 Location: Vienna
|
Posted: Mon Sep 29, 2008 11:05 pm Post subject: |
|
|
It should be in a file named modifier.sortby.php in your plugins directory. _________________ Darn computers always do what I tell them to instead of what I want them to do.
Last edited by Celeb on Fri Oct 17, 2008 7:25 am; edited 1 time in total |
|
Back to top |
|
Alpha_Numeric Smarty Rookie
Joined: 18 Aug 2008 Posts: 6
|
Posted: Thu Oct 16, 2008 3:50 pm Post subject: |
|
|
It just doesn't work for me at all. I have placed this code, verbatim in a file called modifier.sortby.php, w/ the same permissions and ownership as all the other similar files in the ..libs/plugins directory:
Code: | <?php
#
# sorts an array of named arrays by the supplied fields
# code by dholmes at jccc d0t net
# taken from http://au.php.net/function.uasort
# modified by cablehead, messju and pscs at http://www.phpinsider.com/smarty-forum
function array_sort_by_fields(&$data, $sortby){
static $sort_funcs = array();
if (empty($sort_funcs[$sortby]))
{
$code = "\$c=0;";
foreach (split(',', $sortby) as $key)
{
$d = '1';
if (substr($key, 0, 1) == '-')
{
$d = '-1';
$key = substr($key, 1);
}
if (substr($key, 0, 1) == '#')
{
$key = substr($key, 1);
$code .= "if ( \$a['$key'] > \$b['$key']) return $d * 1;\n";
$code .= "if ( \$a['$key'] < \$b['$key']) return $d * -1;\n";
}
else
{
$code .= "if ( (\$c = strcasecmp(\$a['$key'],\$b['$key'])) != 0 ) return $d * \$c;\n";
}
}
$code .= 'return $c;';
$sort_func = $sort_funcs[$sortby] = create_function('$a, $b', $code);
}
else
{
$sort_func = $sort_funcs[$sortby];
}
uasort($data, $sort_func);
}
#
# Modifier: sortby - allows arrays of named arrays to be sorted by a given field
#
function smarty_modifier_sortby($arrData,$sortfields) {
array_sort_by_fields($arrData,$sortfields);
return $arrData;
}
$smarty->register_modifier( "sortby", "smarty_modifier_sortby" );
?> |
The dump in Smarty debug tells me the array of arrays assigned to the Smarty variable $Tickets has these values:
Code: | Array (7)
0 => Array (13)
ticketsid => "1309823576"
eventid => "728896"
event => "Nine Inch Nails"
section => "103"
row => "E"
quantity => 2
rawsplit => "2"
split => Array (1)
0 => "2"
saleprice => 170
listprice => 124.95
sellingbrokerid => 1022
non_real_time => false
notes => "AISLE SEATS--CENTER-STAGE VIEW!"
1 => Array (13)
ticketsid => "1309823575"
eventid => "728896"
event => "Nine Inch Nails"
section => "103"
row => "G"
quantity => 4
rawsplit => "4,2"
split => Array (2)
0 => "4"
1 => "2"
saleprice => 160
listprice => 119
sellingbrokerid => 1022
non_real_time => false
notes => "CENTER-STAGE VIEW!"
2 => Array (13)
ticketsid => "1309873207"
eventid => "728896"
event => "Nine Inch Nails"
section => "107"
row => "A"
quantity => 2
rawsplit => "2"
split => Array (1)
0 => "2"
saleprice => 240
listprice => 175
sellingbrokerid => 982
non_real_time => false
notes => "E Tickets - Lower level"
3 => Array (13)
ticketsid => "1309872734"
eventid => "728896"
event => "Nine Inch Nails"
section => "120"
row => "R"
quantity => 8
rawsplit => "8,6,4,2"
split => Array (4)
0 => "8"
1 => "6"
2 => "4"
3 => "2"
saleprice => 135
listprice => 99
sellingbrokerid => 1011
non_real_time => false
notes => "Tickets will ship on or before: 10/2..."
4 => Array (13)
ticketsid => "1309865017"
eventid => "728896"
event => "Nine Inch Nails"
section => "204"
row => "N"
quantity => 2
rawsplit => "2"
split => Array (1)
0 => "2"
saleprice => 120
listprice => 89
sellingbrokerid => 407
non_real_time => false
notes => "Upper Level Tickets."
5 => Array (13)
ticketsid => "1309993523"
eventid => "728896"
event => "Nine Inch Nails"
section => "Main Floor"
row => "GA"
quantity => 4
rawsplit => "4,2"
split => Array (2)
0 => "4"
1 => "2"
saleprice => 165
listprice => 120
sellingbrokerid => 810
non_real_time => false
notes => "Main Floor right in front of the stage"
6 => Array (13)
ticketsid => "1309993524"
eventid => "728896"
event => "Nine Inch Nails"
section => "Main Floor"
row => "GA"
quantity => 4
rawsplit => "4,2"
split => Array (2)
0 => "4"
1 => "2"
saleprice => 135
listprice => 97.5
sellingbrokerid => 810
non_real_time => false
notes => "Main Floor right in front of the stage" |
...and this is the foreach loop in my .tpl file:
Code: | {foreach from=$Tickets|@sortby:"#saleprice" item="row" name="Tickets"}
{assign var=id value=$smarty.foreach.Tickets.index}
{assign var=ticket value=$Tickets.$id}
<tr{if $smarty.foreach.Tickets.index % 2 != 0} class="alt_color"{/if}>
{* ticketsid *}
<input name="ticketsid[]" type="hidden" value="{$ticket.ticketsid}"/>
<td>
<input name="index[]" type="checkbox" value="{$smarty.foreach.Tickets.index}"/>
</td>
<td>
<input name="section[]" type="hidden" value="{$ticket.section}"/>
{$ticket.section}
</td>
<td>
<input name="row[]" type="hidden" value="{$ticket.row}"/>
{$ticket.row}
</td>
<td class="price">
<input name="saleprice[]" type="hidden" value="{$ticket.saleprice}"/>
${$ticket.saleprice}
</td>
<td>
<input name="split[]" type="hidden" value="{$ticket.rawsplit}"/>
<select name="qty[]">
{foreach from=$ticket.split item="qty" name="qty"}
<option value="{$qty}" {if $smarty.foreach.qty.last} selected{/if}>{$qty}</option>
{/foreach}
</select>
</td>
<td class="last-child"><input name="ticket" type="image" value="submit" src="/images/button_buy_1.gif"/></td>
</tr>
{/foreach} |
If I am doing something wrong, I cannot see what it is.
Please, any help greatly appreciated. |
|
Back to top |
|
Celeb Administrator
Joined: 17 Apr 2007 Posts: 1025 Location: Vienna
|
Posted: Fri Oct 17, 2008 7:27 am Post subject: |
|
|
When you put the file in your plugins directory you shouldn't need the last line:
Code: | $smarty->register_modifier( "sortby", "smarty_modifier_sortby" ); |
How exactly does it not work? Do you get any errors or is the order wrong/not changed at all? _________________ Darn computers always do what I tell them to instead of what I want them to do. |
|
Back to top |
|
|