r1346: - Can now sort by version
[bugdar.git] / includes / class_sort.php
1 <?php
2 /*=====================================================================*\
3 || ###################################################################
4 || # Bugdar [#]version[#]
5 || # Copyright ©2002-[#]year[#] Blue Static
6 || #
7 || # This program is free software; you can redistribute it and/or modify
8 || # it under the terms of the GNU General Public License as published by
9 || # the Free Software Foundation; version [#]gpl[#] of the License.
10 || #
11 || # This program is distributed in the hope that it will be useful, but
12 || # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 || # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 || # more details.
15 || #
16 || # You should have received a copy of the GNU General Public License along
17 || # with this program; if not, write to the Free Software Foundation, Inc.,
18 || # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 || ###################################################################
20 \*=====================================================================*/
21
22 /**
23 * Bug Listing Sorter
24 *
25 * This class is used to sort bugs based on user-sent options and variables.
26 *
27 * @author Blue Static
28 * @copyright Copyright ©2002 - [#]year[#], Blue Static
29 * @version $Revision$
30 * @package Bugdar
31 *
32 */
33 class ListSorter
34 {
35 /**
36 * Bugsys registry
37 * @var object
38 * @access private
39 */
40 var $registry;
41
42 /**
43 * Page name
44 * @var string
45 * @access public
46 */
47 var $page = '';
48
49 /**
50 * Current sort key
51 * @var string
52 * @access private
53 */
54 var $sortkey = '';
55
56 /**
57 * Current sort direction
58 * @var string
59 * @access private
60 */
61 var $direction = '';
62
63 /**
64 * Column array for table heads
65 * @var array
66 */
67 var $columns;
68
69 // ###################################################################
70 /**
71 * Constructor: set the page name
72 *
73 * @access public
74 *
75 * @param string File name without the .php extension
76 */
77 function ListSorter($page)
78 {
79 global $bugsys;
80 $this->registry = $bugsys;
81 $this->page = $page;
82 $this->process_incoming();
83 }
84
85 // ###################################################################
86 /**
87 * Processes the incoming variables and then sets all the sort order
88 * information appropriately
89 *
90 * @access private
91 */
92 function process_incoming()
93 {
94 $this->sortkey = $this->registry->in['by'];
95 if (!$this->fetch_by_text($this->registry->in['by']))
96 {
97 $this->sortkey = (isset($this->registry->userinfo['defaultsortkey']) ? $this->registry->userinfo['defaultsortkey'] : $this->registry->options['defaultsortkey']);
98 }
99
100 $this->direction = $this->registry->in['as'];
101 if (!in_array($this->direction, array('asc', 'desc')))
102 {
103 $this->direction = (isset($this->registry->userinfo['defaultsortas']) ? $this->registry->userinfo['defaultsortas'] : $this->registry->options['defaultsortas']);
104 }
105 }
106
107 // ###################################################################
108 /**
109 * Fetch a SQL query to gather bugs with the sort filters applied
110 *
111 * @access public
112 *
113 * @param string Additional WHERE clauses in an array
114 * @param string A LIMIT clause
115 *
116 * @return string Compiled SQL query
117 */
118 function fetch_sql_query($where = null, $limit = null)
119 {
120 // this WHERE clause is used for all the queries
121 $basewhere = "bug.product IN (" . fetch_on_bits('canviewbugs') . ")
122 AND (!bug.hidden OR (bug.hidden AND bug.product IN (" . fetch_on_bits('canviewhidden') . "))" . (can_perform('canviewownhidden') ? " OR (bug.hidden AND bug.userid = " . $this->registry->userinfo['userid'] . " AND bug.product IN (" . fetch_on_bits('canviewownhidden') . "))" : "") . ")" .
123 (($this->registry->options['hidestatuses'] OR isset($this->registry->userinfo['hidestatuses'])) ? "
124 AND bug.status NOT IN (" . ($this->registry->userinfo['hidestatuses'] != '' ? $this->registry->userinfo['hidestatuses'] : $this->registry->options['hidestatuses']) . ")" : "");
125
126 // remap the sort keys to be actual SQL fields
127 $querykeys = array(
128 'bugid' => 'bugid',
129 'summary' => 'summary',
130 'reporter' => 'userid',
131 'lastpost' => (can_perform('canviewhidden') ? "lastposttime" : "hiddenlastposttime")
132 );
133
134 switch ($this->sortkey)
135 {
136 case 'bugid':
137 case 'summary':
138 case 'reporter':
139 case 'lastpost':
140 $query = "
141 SELECT * FROM " . TABLE_PREFIX . "bug AS bug
142 WHERE $basewhere" .
143 (is_array($where) ? "
144 AND " . implode("\nAND ", $where) : "") . "
145 ORDER BY " . $querykeys[ $this->sortkey ] . " " . strtoupper($this->direction) . ($this->sortkey != 'lastpost' ? ", " . $querykeys['lastpost'] . " " . strtoupper($this->direction) : "") . ($limit ? "
146 LIMIT $limit" : "");
147 break;
148 case 'product':
149 case 'component':
150 case 'version':
151 case 'status':
152 case 'resolution':
153 case 'priority':
154 case 'severity':
155 $query = "
156 SELECT * FROM " . TABLE_PREFIX . "{$this->sortkey} AS {$this->sortkey}
157 RIGHT JOIN " . TABLE_PREFIX . "bug AS bug
158 ON (bug.{$this->sortkey} = {$this->sortkey}.{$this->sortkey}id)
159 WHERE $basewhere" .
160 (is_array($where) ? "
161 AND " . implode("\nAND ", $where) : "") . "
162 ORDER BY {$this->sortkey}.displayorder " . strtoupper($this->direction) . ", bug.$querykeys[lastpost] " . strtoupper($this->direction) . ($limit ? "
163 LIMIT $limit" : "");
164 break;
165 }
166
167 return $query;
168 }
169
170 // ###################################################################
171 /**
172 * Returns the display text for a given sort order key
173 *
174 * @access public static
175 *
176 * @param string Sort order key, or FALSE for the array
177 *
178 * @return mixed Display text if param is string, or array of all key=>text if param is NULL
179 */
180 function fetch_by_text($key)
181 {
182 global $lang;
183
184 $keys = array(
185 'lastpost' => _('Last Post Time'),
186 'bugid' => _('Bug ID'),
187 'summary' => _('Summary'),
188 'reporter' => _('Reporter'),
189 'product' => _('Product'),
190 'version' => _('Version'),
191 'status' => _('Status'),
192 'resolution' => _('Resolution'),
193 'priority' => _('Priority'),
194 'severity' => _('Severity')
195 );
196
197 if ($key === false)
198 {
199 return $keys;
200 }
201 else
202 {
203 return $keys["$key"];
204 }
205 }
206
207 // ###################################################################
208 /**
209 * Returns the display text for a given sort order direction
210 *
211 * @access public static
212 *
213 * @param string Sort direction, or FALSE for the array
214 *
215 * @return mixed Display text if param is string, or array of all key=>text if param is NULL
216 */
217 function fetch_as_text($key)
218 {
219 global $lang;
220
221 $keys = array(
222 'desc' => _('Descending'),
223 'asc' => _('Ascending')
224 );
225
226 if ($key === false)
227 {
228 return $keys;
229 }
230 else
231 {
232 return $keys["$key"];
233 }
234 }
235
236 // ###################################################################
237 /**
238 * Returns a multi-dimensional array with sort by keys indexing arrays
239 * with 'image' and 'href' keys that store the values from
240 * fetch_sort_image() and fetch_sort_link(), respectively
241 *
242 * @access public
243 *
244 * @param string Extra GET parameters to pass to fetch_sort_link()
245 *
246 * @return array Array as described above
247 */
248 function fetch_display_array($params = null)
249 {
250 $return = $this->fetch_by_text(false);
251
252 foreach ($return AS $key => $nil)
253 {
254 $return["$key"] = array('image' => ($this->sortkey == $key ? $this->fetch_sort_image() : ''), 'href' => $this->fetch_sort_link($key, $params, true));
255 }
256
257 return $return;
258 }
259
260 // ###################################################################
261 /**
262 * Returns the entire <img> tag for the sort arrow
263 *
264 * @access public
265 *
266 * @return string HTML <img> tag
267 */
268 function fetch_sort_image()
269 {
270 return '<img src="templates/images/arrow_' . $this->fetch_sort_direction() . '.gif" alt="" style="vertical-align: top; border: none" />';
271 }
272
273 // ###################################################################
274 /**
275 * Returns the href value for an <a> tag by generating all the necessary
276 * bits and concat'ing it onto an extra string of GETs (optional)
277 *
278 * @access public
279 *
280 * @param string Sorting key
281 * @param string Additional GET parameters
282 * @param bool Highlight the current sortkey if that's passed?
283 *
284 * @return string HREF
285 */
286 function fetch_sort_link($key, $params = null, $highlight = false)
287 {
288 if ($params)
289 {
290 $params .= '&amp;';
291 }
292
293 return $this->page . '.php?' . $params . 'by=' . $key . '&amp;as=' . (($this->sortkey == $key AND $highlight) ? $this->fetch_opposite_sort_direction() . '" class="select' : $this->fetch_sort_direction());
294 }
295
296 // ###################################################################
297 /**
298 * Returns the OPPOSITE direction to sort when you click on a link
299 *
300 * @access public
301 *
302 * @return string Either asc or desc
303 */
304 function fetch_opposite_sort_direction()
305 {
306 if ($this->direction == 'asc')
307 {
308 return 'desc';
309 }
310 else
311 {
312 return 'asc';
313 }
314 }
315
316 // ###################################################################
317 /**
318 * Returns the current sorted direction for the image path
319 *
320 * @access public
321 *
322 * @return string Either asc or desc
323 */
324 function fetch_sort_direction()
325 {
326 return $this->direction;
327 }
328
329 // ###################################################################
330 /**
331 * Returns the HTML code for bug listing table column headers
332 *
333 * @param bool Include the sort links/image?
334 * @param string Additional GET params to pass to fetch_sort_link()
335 *
336 * @return string HTML code
337 */
338 function constructColumnHeaders($sortable, $params = null)
339 {
340 $this->_processColumns();
341
342 $output = '';
343 foreach ($this->columns AS $columns)
344 {
345 $build = array();
346 foreach ($columns AS $column)
347 {
348 $build[] = ($sortable ? '<a href="' . $this->fetch_sort_link($column, $params, true) . '">' . $this->registry->columnNames["$column"] . '</a>' : $this->registry->columnNames["$column"]);
349 }
350 $image = (in_array($this->sortkey, $columns) ? $this->fetch_sort_image() : '');
351 $name = implode(' / ', $build);
352 eval('$output .= "' . $this->registry->template->fetch('list_head') . '";');
353 }
354
355 return $output;
356 }
357
358 // ###################################################################
359 /**
360 * Returns the HTML code for a row of data for the bug listing
361 *
362 * @param array Bug data array
363 * @param string Additional link params
364 *
365 * @return string Row HTML
366 */
367 function constructRow($bug, $params = null)
368 {
369 $this->_processColumns();
370
371 foreach ($this->columns AS $columns)
372 {
373 if (sizeof($columns) > 1)
374 {
375 $build = array();
376 foreach ($columns AS $column)
377 {
378 $build[] = '<div>' . $this->_processDataForColumn($bug, $column, $params) . '</div>';
379 }
380 $data = "\n\t\t" . implode("\n\t\t", $build) . "\n\t";
381 }
382 else
383 {
384 $data = $this->_processDataForColumn($bug, $columns[0], $params);
385 }
386 $fields .= "\n\t<td>$data</td>";
387 }
388
389 eval('$output = "' . $this->registry->template->fetch('trackerhome_bits') . '";');
390 return $output;
391 }
392
393 // ###################################################################
394 /**
395 * Handler for special-case column data
396 *
397 * @param array Bug data
398 * @param string Column name
399 * @param string Additional URL params
400 *
401 * @return string Processed column data
402 */
403 function _processDataForColumn($bug, $column, $params = null)
404 {
405 switch ($column)
406 {
407 case 'summary':
408 return '<a href="showreport.php?bugid=' . $bug['bugid'] . $params . '">' . $bug['summary'] . '</a>';
409 case 'userid':
410 return ($bug['userid'] ? $bug['username'] : _('Guest'));
411 case 'lastpost':
412 return $bug['lastposttime'] . "\n\t\t<div>" . _('by') . ' ' . ($bug['lastpost'] ? $bug['lastpost'] : _('Guest'));
413 default:
414 return $bug["$column"];
415 }
416 }
417
418 // ###################################################################
419 /**
420 * Sets up $this->columns so that the data can be processed more
421 * easily
422 */
423 function _processColumns()
424 {
425 if (is_array($this->columns))
426 {
427 return;
428 }
429
430 $array = (($this->registry->userinfo['userid'] AND is_array($this->registry->userinfo['columnoptions'])) ? $this->registry->userinfo['columnoptions'] : $this->registry->options['columnoptions']);
431
432 foreach ($array AS $column => $position)
433 {
434 if ($position > 0)
435 {
436 $this->columns["$position"][] = $column;
437 }
438 }
439
440 ksort($this->columns);
441 }
442 }
443
444 /*=====================================================================*\
445 || ###################################################################
446 || # $HeadURL$
447 || # $Id$
448 || ###################################################################
449 \*=====================================================================*/
450 ?>