|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * Functions to aid in the creation of sortable tables. |
|
6 * |
|
7 * All tables created with a call to theme('table') have the option of having |
|
8 * column headers that the user can click on to sort the table by that column. |
|
9 */ |
|
10 |
|
11 |
|
12 /** |
|
13 * Query extender class for tablesort queries. |
|
14 */ |
|
15 class TableSort extends SelectQueryExtender { |
|
16 |
|
17 /** |
|
18 * The array of fields that can be sorted by. |
|
19 * |
|
20 * @var array |
|
21 */ |
|
22 protected $header = array(); |
|
23 |
|
24 public function __construct(SelectQueryInterface $query, DatabaseConnection $connection) { |
|
25 parent::__construct($query, $connection); |
|
26 |
|
27 // Add convenience tag to mark that this is an extended query. We have to |
|
28 // do this in the constructor to ensure that it is set before preExecute() |
|
29 // gets called. |
|
30 $this->addTag('tablesort'); |
|
31 } |
|
32 |
|
33 /** |
|
34 * Order the query based on a header array. |
|
35 * |
|
36 * @see theme_table() |
|
37 * @param $header |
|
38 * Table header array. |
|
39 * @return SelectQueryInterface |
|
40 * The called object. |
|
41 */ |
|
42 public function orderByHeader(Array $header) { |
|
43 $this->header = $header; |
|
44 $ts = $this->init(); |
|
45 if (!empty($ts['sql'])) { |
|
46 // Based on code from db_escape_table(), but this can also contain a dot. |
|
47 $field = preg_replace('/[^A-Za-z0-9_.]+/', '', $ts['sql']); |
|
48 |
|
49 // orderBy() will ensure that only ASC/DESC values are accepted, so we |
|
50 // don't need to sanitize that here. |
|
51 $this->orderBy($field, $ts['sort']); |
|
52 } |
|
53 return $this; |
|
54 } |
|
55 |
|
56 /** |
|
57 * Initializes the table sort context. |
|
58 */ |
|
59 protected function init() { |
|
60 $ts = $this->order(); |
|
61 $ts['sort'] = $this->getSort(); |
|
62 $ts['query'] = $this->getQueryParameters(); |
|
63 return $ts; |
|
64 } |
|
65 |
|
66 /** |
|
67 * Determine the current sort direction. |
|
68 * |
|
69 * @param $headers |
|
70 * An array of column headers in the format described in theme_table(). |
|
71 * @return |
|
72 * The current sort direction ("asc" or "desc"). |
|
73 */ |
|
74 protected function getSort() { |
|
75 return tablesort_get_sort($this->header); |
|
76 } |
|
77 |
|
78 /** |
|
79 * Compose a URL query parameter array to append to table sorting requests. |
|
80 * |
|
81 * @return |
|
82 * A URL query parameter array that consists of all components of the current |
|
83 * page request except for those pertaining to table sorting. |
|
84 * |
|
85 * @see tablesort_get_query_parameters() |
|
86 */ |
|
87 protected function getQueryParameters() { |
|
88 return tablesort_get_query_parameters(); |
|
89 } |
|
90 |
|
91 /** |
|
92 * Determine the current sort criterion. |
|
93 * |
|
94 * @param $headers |
|
95 * An array of column headers in the format described in theme_table(). |
|
96 * @return |
|
97 * An associative array describing the criterion, containing the keys: |
|
98 * - "name": The localized title of the table column. |
|
99 * - "sql": The name of the database field to sort on. |
|
100 */ |
|
101 protected function order() { |
|
102 return tablesort_get_order($this->header); |
|
103 } |
|
104 } |
|
105 |
|
106 /** |
|
107 * Initialize the table sort context. |
|
108 */ |
|
109 function tablesort_init($header) { |
|
110 $ts = tablesort_get_order($header); |
|
111 $ts['sort'] = tablesort_get_sort($header); |
|
112 $ts['query'] = tablesort_get_query_parameters(); |
|
113 return $ts; |
|
114 } |
|
115 |
|
116 /** |
|
117 * Formats a column header. |
|
118 * |
|
119 * If the cell in question is the column header for the current sort criterion, |
|
120 * it gets special formatting. All possible sort criteria become links. |
|
121 * |
|
122 * @param $cell |
|
123 * The cell to format. |
|
124 * @param $header |
|
125 * An array of column headers in the format described in theme_table(). |
|
126 * @param $ts |
|
127 * The current table sort context as returned from tablesort_init(). |
|
128 * |
|
129 * @return |
|
130 * A properly formatted cell, ready for _theme_table_cell(). |
|
131 */ |
|
132 function tablesort_header($cell, $header, $ts) { |
|
133 // Special formatting for the currently sorted column header. |
|
134 if (is_array($cell) && isset($cell['field'])) { |
|
135 $title = t('sort by @s', array('@s' => $cell['data'])); |
|
136 if ($cell['data'] == $ts['name']) { |
|
137 $ts['sort'] = (($ts['sort'] == 'asc') ? 'desc' : 'asc'); |
|
138 $cell['class'][] = 'active'; |
|
139 $image = theme('tablesort_indicator', array('style' => $ts['sort'])); |
|
140 } |
|
141 else { |
|
142 // If the user clicks a different header, we want to sort ascending initially. |
|
143 $ts['sort'] = 'asc'; |
|
144 $image = ''; |
|
145 } |
|
146 $cell['data'] = l($cell['data'] . $image, $_GET['q'], array('attributes' => array('title' => $title), 'query' => array_merge($ts['query'], array('sort' => $ts['sort'], 'order' => $cell['data'])), 'html' => TRUE)); |
|
147 |
|
148 unset($cell['field'], $cell['sort']); |
|
149 } |
|
150 return $cell; |
|
151 } |
|
152 |
|
153 /** |
|
154 * Formats a table cell. |
|
155 * |
|
156 * Adds a class attribute to all cells in the currently active column. |
|
157 * |
|
158 * @param $cell |
|
159 * The cell to format. |
|
160 * @param $header |
|
161 * An array of column headers in the format described in theme_table(). |
|
162 * @param $ts |
|
163 * The current table sort context as returned from tablesort_init(). |
|
164 * @param $i |
|
165 * The index of the cell's table column. |
|
166 * |
|
167 * @return |
|
168 * A properly formatted cell, ready for _theme_table_cell(). |
|
169 */ |
|
170 function tablesort_cell($cell, $header, $ts, $i) { |
|
171 if (isset($header[$i]['data']) && $header[$i]['data'] == $ts['name'] && !empty($header[$i]['field'])) { |
|
172 if (is_array($cell)) { |
|
173 $cell['class'][] = 'active'; |
|
174 } |
|
175 else { |
|
176 $cell = array('data' => $cell, 'class' => array('active')); |
|
177 } |
|
178 } |
|
179 return $cell; |
|
180 } |
|
181 |
|
182 /** |
|
183 * Composes a URL query parameter array for table sorting links. |
|
184 * |
|
185 * @return |
|
186 * A URL query parameter array that consists of all components of the current |
|
187 * page request except for those pertaining to table sorting. |
|
188 */ |
|
189 function tablesort_get_query_parameters() { |
|
190 return drupal_get_query_parameters($_GET, array('q', 'sort', 'order')); |
|
191 } |
|
192 |
|
193 /** |
|
194 * Determines the current sort criterion. |
|
195 * |
|
196 * @param $headers |
|
197 * An array of column headers in the format described in theme_table(). |
|
198 * |
|
199 * @return |
|
200 * An associative array describing the criterion, containing the keys: |
|
201 * - "name": The localized title of the table column. |
|
202 * - "sql": The name of the database field to sort on. |
|
203 */ |
|
204 function tablesort_get_order($headers) { |
|
205 $order = isset($_GET['order']) ? $_GET['order'] : ''; |
|
206 foreach ($headers as $header) { |
|
207 if (is_array($header)) { |
|
208 if (isset($header['data']) && $order == $header['data']) { |
|
209 $default = $header; |
|
210 break; |
|
211 } |
|
212 |
|
213 if (empty($default) && isset($header['sort']) && ($header['sort'] == 'asc' || $header['sort'] == 'desc')) { |
|
214 $default = $header; |
|
215 } |
|
216 } |
|
217 } |
|
218 |
|
219 if (!isset($default)) { |
|
220 $default = reset($headers); |
|
221 if (!is_array($default)) { |
|
222 $default = array('data' => $default); |
|
223 } |
|
224 } |
|
225 |
|
226 $default += array('data' => NULL, 'field' => NULL); |
|
227 return array('name' => $default['data'], 'sql' => $default['field']); |
|
228 } |
|
229 |
|
230 /** |
|
231 * Determines the current sort direction. |
|
232 * |
|
233 * @param $headers |
|
234 * An array of column headers in the format described in theme_table(). |
|
235 * |
|
236 * @return |
|
237 * The current sort direction ("asc" or "desc"). |
|
238 */ |
|
239 function tablesort_get_sort($headers) { |
|
240 if (isset($_GET['sort'])) { |
|
241 return (strtolower($_GET['sort']) == 'desc') ? 'desc' : 'asc'; |
|
242 } |
|
243 // The user has not specified a sort. Use the default for the currently sorted |
|
244 // header if specified; otherwise use "asc". |
|
245 else { |
|
246 // Find out which header is currently being sorted. |
|
247 $ts = tablesort_get_order($headers); |
|
248 foreach ($headers as $header) { |
|
249 if (is_array($header) && isset($header['data']) && $header['data'] == $ts['name'] && isset($header['sort'])) { |
|
250 return $header['sort']; |
|
251 } |
|
252 } |
|
253 } |
|
254 return 'asc'; |
|
255 } |