Steps to Reproduce
Create an array of column headers as described in theme_table() with one sort parameter to indicate the default sort column and order and then call a sort function that depends on tablesort_get_order() such as tablesort_sql().
I found the problem while trying to figure out why the Workspace module did not have a default sort order. It turned out it does, but the core drupal sort function was not working as anticipated. Here's a code snippet from that module to help show usage.
...
$header = array(
array('data' => t('Type'), 'field' => 'type'),
array('data' => t('Title'), 'field' => 'title'),
array('data' => t('Owner'), 'field' => 'uid'),
array('data' => t('Published'), 'field' => 'status'),
array('data' => t('Modified'), 'field' => 'changed', 'sort' => 'desc'),
$comments_enabled ? array('data' => t('Replies'), 'field' => 'comment_count') : array('data' => ''),
array('data' => t('Operations'), 'colspan' => 2)
);
$result = pager_query($sql . <strong>tablesort_sql($header)</strong>, $maxnodes, 0, $count_sql);
...
Expected Behaviour
Based on the passed array I would expect the return of the tablesort_sql() call to be "ORDER BY changed DESC".
Actual Results
The tablesort_sql() call results in an empty string.
My Suspect
I traced the problem back to the tablesort_get_order function. From my testing it almost appeared as if a scope issue. It was definitely detecting the default order and setting the $default variable, however, the variable would vanish outside of the loop. I've never run into this kind of behavior before and it looks like it should work but just wasn't for me.
Version Information
I created a little test script and ran it on a couple of other computers to make sure it wasn't behavior specific to my version of PHP but got the same results. Here are the systems I've tried it on:
Dreamhost (PHP 4.4.8 and Apache).
Ubuntu Gutsy (PHP 5.2.4-2ubuntu5.2 and Apache 2)
Mac OS X 10.5.3 (PHP 5.2.5 (CLI) and Apache 2.2.8)
I'm running the official Drupal 5.9 release. I just took a peek at the 5.10 source and the function has not changed.
A Possible Solution
I made a small modification that fixes the problem and I haven't noticed any side affects yet. I have attached the patch for review. I'm not exactly sure why a return wasn't originally used, perhaps there is a special case that I'm not aware of?
| Comment | File | Size | Author |
|---|---|---|---|
| #13 | drupal_tablesort_order-295430-13.patch | 4.31 KB | jrchamp |
| #11 | drupal_295430_11_tablesort.patch | 3.66 KB | miro_dietiker |
| #8 | 295430-8-tablesort-order-broken.patch | 1.94 KB | carlos8f |
| #6 | drupal_295430_6_tablesort.patch | 1.73 KB | miro_dietiker |
| tablesort_default_order_fix.patch | 1.13 KB | jmstacey |
Comments
Comment #1
mariusilie commentedI don't know why but I found the same problem in drupal 6. The funny thing is that this only happend with "sort" => "desc". When I set "sort" => "asc", everything goes well.
This is weird...
[LATER EDIT]
I found out that this only happens when at least one of the table header data is an empty string
Comment #2
drummComment #3
miro_dietikerThis also affects Drupal 7.
The source of the issue is that the tablesort_init calls both tablesort_get_order and tablesort_get_sort.
http://api.drupal.org/api/drupal/includes--tablesort.inc/function/tables...
Here: tablesort_get_sort returns the FIRST match in the header while tablesort_get_order returns the LAST match.
I consider this as a fatal broken UI API for both present 7.x and 6.x.
To make sure those two functions correspond to each other, we should make them acually build on identical logical checks / structure.
Comment #5
miro_dietikerMoving this to D7 queue as we should fix issues there first.
Comment #6
miro_dietikerSubmitting a first try for the issue from my side.
I think this is much more consistent, although we should rework the API. However it's too late for 7.x.
Comment #7
bojanz commentedThere's a good cleanup patch in #97293: Tablesort cleanup.
Sadly, it didn't get in 7.x.
The change makes sense.
I don't like this comment though:
A comment shouldn't make the code followed by it less understandable ;)
Either lose it (don't see a particular need for it), or reword the "Use first if specified; (same as sort)." part (maybe to something like "Use the first 'sort' specified.")
Comment #8
carlos8f commentedDidn't test the patch, but rerolled to improve comments:
Comment #9
bojanz commentedGreat! The comments are now awesome.
Forgot to mention that we should probably put in a few tests, the fact that we are fixing a bug as stupid as this proves that we need them.
Comment #10
jrchamp commented#839556: Fix isset regression in tablesort, add tests, and cleanup theme_process_registry() fixes the sorting, with tests. This is probably duplicate. Please test with that patch to see if it resolves your issue.
Comment #11
miro_dietikerI tried to produce a reliable sample. Pity i don't have time now to produce a test.
This is what i setup as header in simplenews module to test:
As of my understanding, if no sort provided, the first column providing a sort should be considered with the right sort order.
Original core takes the SECOND (status) column, ordered by the FIRST (asc) sort order.
Patch #839556 still takes the SECOND (status) column, ordered by the SECOND (desc) sort order. This is better already.
Our patch changes to the first column with the right order.
To my surprise all this code is existing at two locations in the file and i needed to adjust it at a second location to make my sample work.
Update attached.
Comment #13
jrchamp commented#11 fails when the sort column is status because it picks mail. I have attached a patch which contains the patch from #985836: tablesort.inc contains a load of duplicated code to remove duplicated code from tablesort and the tablesort portions from #839556: Fix isset regression in tablesort, add tests, and cleanup theme_process_registry(). Once #839556 goes in, #985836 can go and this patch will simply be reduced to a cleanup/bugfix. The problem here is the default is being overridden. Returning immediately is not the correct solution because it skips over the possibility that another header has been chosen to sort by.
Setting to needs review so that the testbot can play.
Comment #14
miro_dietikerRight. I did miss that...
Looks fine to me, untested.
Comment #15
jrchamp commented@miro_dietiker: Patch #839556 went in over the weekend with the changes from this issue included (as the patches on both issues were related to the sorting brokenness and adding tests). Please let me know if this issue is now resolved for you in git (both 7.x and 8.x head).
Comment #17
Blooniverse commented... default sorting tables still doesn't work as supposed. Please see #1833746: Undefined index: form_build_id in ajax_get_form()
Comment #18
Blooniverse commented... changing status due to #97293: Tablesort cleanup
Comment #19
David_Rothstein commentedThe original issue here is actually fixed, per #15. Reopen with details if that's not the case.