I'm fairly new to drupal and still learning FAPI so perhaps I'm misunderstanding how this *should* work.
I have a query I am running where I need the result set ordered in a certain way (alphabetical by last name).
When I run the query I get the correct result - but when I display it in the tableselect element - the result set is mis-ordered.
I spent several hours trying to figure out what was going on. Finally I went into the code and found this:
// Sort the options by their #weight if they have a #weight.
uasort($element['#options'], 'element_sort');
the problem is that there is no check for the fact that the weight property might not be there.
When the '#weight' property is absent from all the options this uasort totally messes up queries that have an 'ORDER BY' clause in them.
I was able to work-around the issue by adding in the '#weight' property to the options array elements - but this is an undocumented and unexpected result.
If one wants a table ordered in a certain way WITHOUT giving the end-user the ability to select a sort order - one *should* be able to use an 'ORDER BY' clause in their sql query and have the table select element preserve the query result order.
either a check for the '#weight' property should actually be performed around the above listed code (as the code comment suggests) - or the documentation and README file should document that the #weight property is required to preserve query result order.
| Comment | File | Size | Author |
|---|---|---|---|
| #2 | query-misordered-when-weight-property-absent.patch | 966 bytes | letapjar |
Comments
Comment #1
letapjar commentedHere is a potential solution to this issue - a check of the '#weight' property is done on all the '#options' elements - if even one of them has a '#weight' property then the uasort is performed - but if none of them have the weight - the uasort is ignored and the ORDER BY of the original query is preserved.
while this works - it is computationally expensive - looping through every element and doing an array_key_exists could really slow things down for large result sets.
another potential solution would be to add a parameter/property to the table select element such that if set to FALSE the uasort would be skipped.
i.e.
$element['#sort_by_weights'] =>FALSE;
Then the check above could be just:
This would require a default setting and I'm not sure whether the default should be TRUE or FALSE - my leaning is towards FALSE so that the default behavior is to preserve SQL result orders.
Comment #2
letapjar commentedOK so here is the second proposed solution from the post above in the form of a patch.
Apologies for the multiple posts - still learning about how to create patches etc.
--- elements.module 2009-12-02 06:22:11.000000000 -0500
+++ elements2.module 2010-03-23 14:17:28.000000000 -0400
@@ -9,6 +9,7 @@ function elements_elements() {
'#input' => TRUE,
'#js_select' => TRUE,
'#multiple' => TRUE,
+ '#sort_by_weights'=>FALSE,
'#process' => array('form_process_tableselect'),
'#options' => array(),
'#empty' => '',
@@ -78,9 +79,11 @@ function form_process_tableselect($eleme
$element['#default_value'] = array();
}
- // Sort the options by their #weight if they have a #weight.
- uasort($element['#options'], 'element_sort');
-
+ // Sort the options by their #weight if we are supposed to.
+
+ if ($element['#sort_by_weights']){
+ uasort($element['#options'], 'element_sort');
+ }
// Create a checkbox or radio for each item in #options in such a way that
// the value of the tableselect element behaves as if it had been of type
// checkboxes or radios.
Comment #3
letapjar commentedchangin status to needs review for the proposed patch
Comment #4
dave reidelement_sort() does have a check if items don't have a #weight value. Is this something that needs to be fixed in core?
Comment #5
dave reidYeah, this is just something core will have to fix.
If I do this:
I get:
Which re-ordered the elements even though they had the same weight.
Comment #6
dave reidActually, the problem is that form_builder() hasn't run yet on the form when we call element_sort(). The form_builder() assigns a default weight for fields to preserve array ordering, like we want. If we perform the element_sort in the theme function, we got the proper ordering.
Comment #7
dave reidHAH. Tablesorts are broken in D7 because of this as well.
Comment #8
dave reid#700380: Regression: Tableselect sorting is altered if '#weight' is not set is the core issue here.
Comment #9
dave reidThis will wait until a D7 fix then to backport.
Comment #10
dave reidTested the core patch and backported it. Worked for me with multiple cases. Committed the fix to CVS. Please go review the core patch now!
#700380: Regression: Tableselect sorting is altered if '#weight' is not set
http://drupal.org/cvs?commit=345862
Comment #11
letapjar commentedso we can just eliminate the uasort line? - cool.
just tested on my use case - the patch works as expected.
Thanks for jumping on this - it was really driving me nuts on a list that had to have the right order.
Comment #12
jerome72 commentedThank you so much for the tip! I was going mad with the problem of order, and removing the line did the trick!
I just commented it: