I noticed that, even though the API supports a "field" element for table columns, the URL will contain the "data" element as a sorting parameter.
As an example, if a header column is defined in the following way:
$header[]=array('data'=>t('Number'),'field'=>'id','sort'=>'asc');
The column head in the table is titled 'Number'. The query string in the link is "?sort=desc&order=Number".
"Number" is not supposed to be an identifying title of the field, that's what "id" is. In fact, if the site is localized to other languages, "Number" will change to other, unpredictable values.
From the documentation of the table API, it seems that it would make more sense if the query string contained "?sort=desc&order=id".
Comment | File | Size | Author |
---|---|---|---|
#84 | 97293-84.patch | 8.79 KB | voleger |
Comments
Comment #1
isaac77 CreditAttribution: isaac77 commentedThis also seems to be a problem in 4.7, unless I'm misunderstanding something. Currently, sorting of tables on my 4.7-based site breaks as soon as the column titles are translated.
These tables are generated by Views module, so just figuring out a way to apply t() to the column titles required a bit of work... and now sorting seems to break.
The following code from tablesort_header seems relevant:
As a workaround, I may have to incorporate this code -- with slight modifications that will generate the link based on the field name rather than the translated label -- into a theme override.
Anyone with more in-depth understanding of the whole system have thoughts?
Comment #2
ukdg_phil CreditAttribution: ukdg_phil commentedI'm not sure how others feel, but I'm not always too keen on letting my database field names be viewed by the public, as its a potentially (although pretty small) security risk (IMOH).
I may be too paranoid here, & in most situations it may be ok to use, but I can see circumstances where it could be an issue & this is possibly why the title was chosen as the sort parameter id? (just a guess)
Perhaps it could default to using either the 'field' (as Arancaytar suggests) or the 'data' (current default behaviour) info by default, and add an optional argument along the lines of 'sort_var' that could be used to force a specific value to use in the 'order=' clause.
Comment #3
cburschkaAdmittedly, my argument about localization doesn't really apply - if the page internally uses t("Number") to compare the get parameter to, that will work. Well, unless the site is localized to two different languages and one user tries to send someone with the other language setting a URL.
Perhaps sort_var really is the way to go.
Comment #4
cburschkaThe sort_var addition still strikes me as a good idea. However, this would be an API change, so it will probably have to be delayed to 7.x.
------------
In a related issue, I have problems differentiating between "order" and "sort" every time I use this API. Intuitively, I think that you "sort" by the name in descending "order", but in fact "order" contains the field name and "sort" the direction. Since we're already in 7.x territory, perhaps the parameters could be renamed into something more clear - like "order_by" instead of "order", and possibly "d" for direction instead of "sort".
Comment #5
gurubert CreditAttribution: gurubert commentedHi!
This is still open in the 6.2 release. Maybe the API documentation needs a change?
I spent some time walking through the source code to find out why theme ('table', ...) does not work as expected.
Regarding the comments about sort_var and exposing internal database column names:
Is the "field" attribute of the table's $header array used otherwise than being the sort variable for theme_table()?
Comment #6
arthurf CreditAttribution: arthurf commentedAccording to the api docs for theme_table (for D5 & D6):
But if you look at tablesort_header(), we see:
The problem is: urlencode($cell['data']). According to the API docs, that should be: urlencode($cell['field'])- atleast, as far as I can understand it. This seems true for D6 as well.
Supplied patch is for D5.
Comment #7
arthurf CreditAttribution: arthurf commentedAnd here's a patch for D6 head. I haven't tried it out, but should be fine.
Comment #8
Damien Tournoud CreditAttribution: Damien Tournoud commentedI assume the bug is also in Drupal 7.x, so it must be fixed there.
Also:
tablesort_get_order()
in order for it to understand the new meaning of the "order" argumentComment #9
cburschkaYes, indeed. And while we're at it, we could take the opportunity and improve the API in the following ways:
1.) Require an associative key in the
$headers
array. This key will be used as the URL parameter, which solves the problem by neither introducing localized text into the URL nor exposing the database schema.2.) Make
order
determine only the default direction for that field (for example desc for numbers), instead of marking that column as the default sorted field. Instead, the#sort
property in the headers array will contain the key of the field sorted by by default.Does this sound good?
Comment #10
Damien Tournoud CreditAttribution: Damien Tournoud commented@Arancaytar: I agree completely.
Comment #11
cburschkaComment #12
sunPlease do now. :)
Comment #13
sunFirst pass.
Comment #15
sunAnd this time including all changes.
oh boy, someone should have told me how horrible Forum module really is...
Comment #17
sunThis one will pass.
Anyone up for reviewing and RTBC'ing?
Comment #18
c960657 CreditAttribution: c960657 commentedI don't have much experience with the tablesort API, so I'd like somebody else to sign off on this, but here are some comments.
I don't understand the added comment. AFAICT table prefixes are not stripped.
Doesn't this overwrite $default_column in each iteration, so it ends up referring to the last column with a valid sort attribute? If yes, is this intended? The first column would be a better default.
Do we need to check for isset($column['data']) as well?
The return is never reached. Though I personally like that Drupal complains loudly in case it detects a developer mistake, it seems that the current convention is not silently ignore cases like these.
It's a terrible variable name (I know you didn't introduce it).
I think the variable name $column describes the variable better than $header, but if you change it, I think you should change $headers to $columns. AFAICT $headers is an array of $header variables, so a simple plural form seems like the obvious choice.
Some other clean-up ideas (possibly outside the scope of this issue):
How about renaming tablesort_init() to e.g. tablesort_get_parameters() - the function simply returns stuff and does not initialize anything. Likewise for TableSort::init().
How about killing tablesort_get_sort(), tablesort_get_order() as separate functions and instead just move them inside tablesort_init()? It seems that you rarely need these values alone without the rest of the array returned by tablesort_init(). Likewise for their counterpart methods in TableSort, getSort()/order()/init().
tablesort_header() and tablesort_cell() take an array as argument (by value), modifies it and returns it. It seems more in line with Drupal standards to accept the argument by reference and just modify the original array, i.e. change
tablesort_foo($array)
totablesort_foo(&$array)
.Comment #19
sunThat was contained before already. I'm not sure whether it will work without that, but let's see. :)
1) No. As the comment explains, and as explained elsewhere in API docs, only the default sorting column in the table's $header should define 'sort'. All other columns do not specify a sort.
2) Since we explicitly check that the column in $header is an array, 'data' must be set. @see theme_table()
I agree on both, and with the new exceptions, we should start to think about DX. Removed the return.
Nope, $header is documented in theme_table() and follows the structure documented in there. It is the same $header, so we keep that variable name.
The other clean-ups you mentioned we should defer to another issue. This patch is large enough. :)
Comment #20
c960657 CreditAttribution: c960657 commentedI was only referring to the additional comment you added (
// Remove table prefix from sorting field.
), not the code itself. Now that you removed the preg_replace() call, it seems that the user-provided string ends up unescaped in the SQL query.I'm not sure I follow you. The documentation for theme_table() says this about $header:
I'm not sure whether this means that all the mentioned keys are required when passing an array. It doesn't say so very explicitly. At least the code seems to check for "field" and "sort" using isset(), but not for "data".
I still think it's a bad name and I think we should change theme_table() :-) But fair enough, we can deal with that later. It's just an internal variable name, so we can change it without breaking any APIs.
Comment #21
sunThis patch was at 99% and only hold off by nitpicks. :(
Two other issues made me revisit this issue:
#615822: Benchmarking / profiling of D7
#602522: Links in renderable arrays and forms (e.g. "Operations") are not alterable
Due to the latter patch, I suspect that this patch will no longer apply, but let's see what the bot thinks.
Comment #23
effulgentsia CreditAttribution: effulgentsia commentedsubscribing
Comment #24
carlos8f CreditAttribution: carlos8f commentedsubscribing
Comment #25
Anonymous (not verified) CreditAttribution: Anonymous commentedThis is definitely not done. This is simply an attempt to reroll the previous patch since alot has changed in the last month and a half. I'd work some more on it now, but I have to step away for a bit.
Comment #26
Anonymous (not verified) CreditAttribution: Anonymous commentedAnyone that wants to play with it, feel free. I won't be able to for a while.
Comment #27
coltraneFor reference #664042: TableSort order error when no sort set in header affects this issue if it gets in this patch may have to be rerolled.
Comment #28
effulgentsia CreditAttribution: effulgentsia commentedCNR for bot run of #25. Is this still on the table for D7?
Comment #30
sunRe-rolled against HEAD. My main interest is to get includes/tablesort.inc out of the regular full bootstrap request path. It's needlessly loaded, on each and every single page.
Comment #32
bojanz CreditAttribution: bojanz commented#30: drupal.tablesort.30.patch queued for re-testing.
Not sure why the locale test is failing... Let's ask the bot one more time.
Huge +1 for this. I've been looking at the tablesort code while implementing #885014: Add pager and tablesort to EntityFieldQuery, and noticed the problems described...
Reviewed the patch, looks excellent.
Comment #34
sun#30: drupal.tablesort.30.patch queued for re-testing.
Comment #36
sunComment #37
bojanz CreditAttribution: bojanz commentedGave this another review, the fixes are awesome and really needed.
I don't like the fact that we need to require_once tablesort every time we plan on using it, but I guess that's unavoidable (on the other hand, including it on every page even when not used is completely stupid)
Comment #38
sunNote that it's only Forum module that needs to load tablesort.inc manually. As the comment tries to explain, Forum module does not use theme_table(), and on top of that, it tries to output a sortable table also for a forum container, even when there are no topics (since otherwise forum_get_topics() would have been invoked, in which the select query is extended with TableSort, which in turn autoloads tablesort.inc), and therefore Forum module has to load tablesort.inc manually.
That's a total edge-case, and should be fixed in a completely different way: Update Forum module to make sense.
Powered by Dreditor.
Comment #39
bojanz CreditAttribution: bojanz commentedThanks for the clarification. Let's get this in!
Comment #40
sun#30: drupal.tablesort.30.patch queued for re-testing.
Comment #41
sunComment #42
Dave ReidJust because someone is upset doesn't mean we have to mark something as won't fix. Someone else is more than welcome to pick up work on a ticket.
Comment #43
sunAlthough badly needed, this sounds like D8 material to me.
Comment #44
bojanz CreditAttribution: bojanz commentedCan we ask Drieschick first?
If there are parts that are D8, maybe they can be postponed, and the other chunks can get in.
It's a good cleanup and a simple fix to an annoying bug. I actually see nothing controversial about it.
I'm prepared to push this forward (even if it gets moved to D8 in the end).
Comment #45
bojanz CreditAttribution: bojanz commentedAnd... This is definitely off the table :/
Comment #46
miro_dietikerReferencing back to a case addressing 7.x minimal bugfixing for tablesort functions.
#295430: Default sort using tablesort_get_order() is broken.
Comment #47
catch#30: drupal.tablesort.30.patch queued for re-testing.
Comment #49
sunComment #50
jhedstromHere's a re-roll of #30 that applies cleanly, but now has failing unit tests that need to be updated to work with the cleaned up API.
Comment #51
Tengu CreditAttribution: Tengu commentedSubscribing
It's really annoying.
Comment #52
aaronaverill CreditAttribution: aaronaverill commentedThe patch from comment #50 touches a lot of files. Attached is a tighter D7.9 fix isolated to tablesort.inc and entity.inc.
Changelog:
Use field to determine sort order: Rewrite tablesort.inc:tablesort_get_order()
Decorate column header with sort indicator and URL based on field: Rewrite tablesort.inc:tablesort_header()
Decorate cell based on column field: Rewrite tablesort.inc:tablesort_cell()
Determine sort direction based on field: Rewrite tablesort.inc:tablesort_get_sort()
Query database using field: Rewrite TableSort::orderByHeader()
Fix callers
entity.inc: EntityFieldQuery::tableSort()
Please be gentle this is my first patch and I've only been coding in anger w/ Drupal for about 3 weeks.
Comment #53
aaronaverill CreditAttribution: aaronaverill commentedThe are a few issues I needed to handle in addition to using [field] in the sort URL:
I've added support for this with the attached D7.9 patch using two new header column attributes: query_field and query_reverse.
As an example of #1, consider the scenario where a item date is stored in a database datetime column, however you would like to show the date and time in two separate table columns. You might use the following $header definition
For these two columns, the URL will be ?order=date and ?order=time, however on the backend TableSort extension is adding an ORDER BY post_datetime clause to the SQL query.
#2 should be self explanatory, just add 'query_reverse' => TRUE
See attached patch.
Comment #54
NROTC_Webmaster CreditAttribution: NROTC_Webmaster commentedRe-roll.
Comment #55
NROTC_Webmaster CreditAttribution: NROTC_Webmaster commentedFix whitespace.
Comment #57
moshe weitzman CreditAttribution: moshe weitzman commentedAnyone care to revive this for D8? Still worthwhile.
Comment #58
jibranreroll
Comment #60
jibranFixed some tests and docs.
Comment #61
fuzzy76 CreditAttribution: fuzzy76 commentedWhy can't the indexes in $header be used for identifying the columns? That way, we can actually allow sorting on expressions like "CAST(fieldwronglyimplementedastext AS UNSIGNED)", "fielda + fieldb" and other cool stuff.
User submitted field names is a potential security risk since it can expose the order for fields that aren't supposed to be in the query.Comment #62
andypostClosely related #1876718: Allow modules to inject columns into tables more easily
Comment #63
jibran#60: 97293-60.patch queued for re-testing.
Comment #65
joelpittetNeeds reroll
https://drupal.org/patch/reroll
Comment #66
fuzzy76 CreditAttribution: fuzzy76 commentedAs I've said before, that patch (and the current behaviour) is a potential security risk.Example from my elearning experience:
A list of students that shows who has turned in an assignment. If a student figures out the column name for the grades (for example by figuring out which module I use), he/she can manipulate the url to sort by grade!
Never mind, I was mistaken.
Comment #67
danylevskyiComment #68
danylevskyiComment #69
danylevskyiComment #71
andypostComment #72
moshe weitzman CreditAttribution: moshe weitzman commentedComment #73
grisendo CreditAttribution: grisendo commentedRe-rolled
Comment #75
miro_dietikerI wonder if we should have a service that defines how to mangle URLs / queries for sorting (and paging also?)
Comment #82
volegerRerroll
Comment #84
volegerComment #85
andypostThis is serious BC break but it makes sense
Comment #90
rgpublicJust stumbled on this again. I think it's really weird that Drupal introduces the field content into the URL - especially with localization. It can contain weird Chinese letters etc. and in your code you have to check for all those manually. This makes the Drupal sortable table render element far less useful. I was even more surprised to find out that you cannot even override the string that is actually used for the query manually. The code seems to be now in core/lib/Drupal/Core/Utility/TableSort.php. Link::createFromRoute has 'order' => $cell_content which causes the problem.