r1342: Process special case columns so we can now look exactly like we did previously
[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 'id' => 'bugid',
129 'summary' => 'summary',
130 'reporter' => 'userid',
131 'lastpost' => (can_perform('canviewhidden') ? "lastposttime" : "hiddenlastposttime")
132 );
133
134 switch ($this->sortkey)
135 {
136 case 'id':
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 'status':
150 case 'resolution':
151 case 'priority':
152 case 'severity':
153 $query = "
154 SELECT * FROM " . TABLE_PREFIX . "{$this->sortkey} AS {$this->sortkey}
155 RIGHT JOIN " . TABLE_PREFIX . "bug AS bug
156 ON (bug.{$this->sortkey} = {$this->sortkey}.{$this->sortkey}id)
157 WHERE $basewhere" .
158 (is_array($where) ? "
159 AND " . implode("\nAND ", $where) : "") . "
160 ORDER BY {$this->sortkey}.displayorder " . strtoupper($this->direction) . ", bug.$querykeys[lastpost] " . strtoupper($this->direction) . ($limit ? "
161 LIMIT $limit" : "");
162 break;
163 }
164
165 return $query;
166 }
167
168 // ###################################################################
169 /**
170 * Returns the display text for a given sort order key
171 *
172 * @access public static
173 *
174 * @param string Sort order key, or FALSE for the array
175 *
176 * @return mixed Display text if param is string, or array of all key=>text if param is NULL
177 */
178 function fetch_by_text($key)
179 {
180 global $lang;
181
182 $keys = array(
183 'lastpost' => _('Last Post Time'),
184 'id' => _('Bug ID'),
185 'summary' => _('Summary'),
186 'reporter' => _('Reporter'),
187 'product' => _('Product'),
188 'status' => _('Status'),
189 'resolution' => _('Resolution'),
190 'priority' => _('Priority'),
191 'severity' => _('Severity')
192 );
193
194 if ($key === false)
195 {
196 return $keys;
197 }
198 else
199 {
200 return $keys["$key"];
201 }
202 }
203
204 // ###################################################################
205 /**
206 * Returns the display text for a given sort order direction
207 *
208 * @access public static
209 *
210 * @param string Sort direction, or FALSE for the array
211 *
212 * @return mixed Display text if param is string, or array of all key=>text if param is NULL
213 */
214 function fetch_as_text($key)
215 {
216 global $lang;
217
218 $keys = array(
219 'desc' => _('Descending'),
220 'asc' => _('Ascending')
221 );
222
223 if ($key === false)
224 {
225 return $keys;
226 }
227 else
228 {
229 return $keys["$key"];
230 }
231 }
232
233 // ###################################################################
234 /**
235 * Returns a multi-dimensional array with sort by keys indexing arrays
236 * with 'image' and 'href' keys that store the values from
237 * fetch_sort_image() and fetch_sort_link(), respectively
238 *
239 * @access public
240 *
241 * @param string Extra GET parameters to pass to fetch_sort_link()
242 *
243 * @return array Array as described above
244 */
245 function fetch_display_array($params = null)
246 {
247 $return = $this->fetch_by_text(false);
248
249 foreach ($return AS $key => $nil)
250 {
251 $return["$key"] = array('image' => ($this->sortkey == $key ? $this->fetch_sort_image() : ''), 'href' => $this->fetch_sort_link($key, $params, true));
252 }
253
254 return $return;
255 }
256
257 // ###################################################################
258 /**
259 * Returns the entire <img> tag for the sort arrow
260 *
261 * @access public
262 *
263 * @return string HTML <img> tag
264 */
265 function fetch_sort_image()
266 {
267 return '<img src="templates/images/arrow_' . $this->fetch_sort_direction() . '.gif" alt="" style="vertical-align: top; border: none" />';
268 }
269
270 // ###################################################################
271 /**
272 * Returns the href value for an <a> tag by generating all the necessary
273 * bits and concat'ing it onto an extra string of GETs (optional)
274 *
275 * @access public
276 *
277 * @param string Sorting key
278 * @param string Additional GET parameters
279 * @param bool Highlight the current sortkey if that's passed?
280 *
281 * @return string HREF
282 */
283 function fetch_sort_link($key, $params = null, $highlight = false)
284 {
285 if ($params)
286 {
287 $params .= '&amp;';
288 }
289
290 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());
291 }
292
293 // ###################################################################
294 /**
295 * Returns the OPPOSITE direction to sort when you click on a link
296 *
297 * @access public
298 *
299 * @return string Either asc or desc
300 */
301 function fetch_opposite_sort_direction()
302 {
303 if ($this->direction == 'asc')
304 {
305 return 'desc';
306 }
307 else
308 {
309 return 'asc';
310 }
311 }
312
313 // ###################################################################
314 /**
315 * Returns the current sorted direction for the image path
316 *
317 * @access public
318 *
319 * @return string Either asc or desc
320 */
321 function fetch_sort_direction()
322 {
323 return $this->direction;
324 }
325
326 // ###################################################################
327 /**
328 * Returns the HTML code for bug listing table column headers
329 *
330 * @param bool Include the sort links/image?
331 * @param string Additional GET params to pass to fetch_sort_link()
332 *
333 * @return string HTML code
334 */
335 function constructColumnHeaders($sortable, $params = null)
336 {
337 $this->_processColumns();
338
339 $output = '';
340 foreach ($this->columns AS $columns)
341 {
342 $build = array();
343 foreach ($columns AS $column)
344 {
345 $build[] = ($sortable ? '<a href="' . $this->fetch_sort_link($column, $params, true) . '">' . $this->registry->columnNames["$column"] . '</a>' : $this->registry->columnNames["$column"]);
346 }
347 $image = ($this->sortkey == $column ? $this->fetch_sort_image() : '');
348 $name = implode(' / ', $build);
349 eval('$output .= "' . $this->registry->template->fetch('list_head') . '";');
350 }
351
352 return $output;
353 }
354
355 // ###################################################################
356 /**
357 * Returns the HTML code for a row of data for the bug listing
358 *
359 * @param array Bug data array
360 * @param string Additional link params
361 *
362 * @return string Row HTML
363 */
364 function constructRow($bug, $params = null)
365 {
366 $this->_processColumns();
367
368 foreach ($this->columns AS $columns)
369 {
370 if (sizeof($columns) > 1)
371 {
372 $build = array();
373 foreach ($columns AS $column)
374 {
375 $build[] = '<div>' . $this->_processDataForColumn($bug, $column, $params) . '</div>';
376 }
377 $data = "\n\t\t" . implode("\n\t\t", $build) . "\n\t";
378 }
379 else
380 {
381 $data = $this->_processDataForColumn($bug, $columns[0], $params);
382 }
383 $fields .= "\n\t<td>$data</td>";
384 }
385
386 eval('$output = "' . $this->registry->template->fetch('trackerhome_bits') . '";');
387 return $output;
388 }
389
390 // ###################################################################
391 /**
392 * Handler for special-case column data
393 *
394 * @param array Bug data
395 * @param string Column name
396 * @param string Additional URL params
397 *
398 * @return string Processed column data
399 */
400 function _processDataForColumn($bug, $column, $params = null)
401 {
402 switch ($column)
403 {
404 case 'summary':
405 return '<a href="showreport.php?bugid=' . $bug['bugid'] . $params . '">' . $bug['summary'] . '</a>';
406 case 'userid':
407 return ($bug['userid'] ? $bug['username'] : _('Guest'));
408 case 'lastpost':
409 return $bug['lastposttime'] . "\n\t\t<div>" . ($bug['lastpost'] ? $bug['lastpost'] : _('Guest'));
410 default:
411 return $bug["$column"];
412 }
413 }
414
415 // ###################################################################
416 /**
417 * Sets up $this->columns so that the data can be processed more
418 * easily
419 */
420 function _processColumns()
421 {
422 if (is_array($this->columns))
423 {
424 return;
425 }
426
427 $array = (($this->registry->userinfo['userid'] AND is_array($this->registry->userinfo['columnoptions'])) ? $this->registry->userinfo['columnoptions'] : $this->registry->options['columnoptions']);
428
429 foreach ($array AS $column => $position)
430 {
431 if ($position > 0)
432 {
433 $this->columns["$position"][] = $column;
434 }
435 }
436
437 ksort($this->columns);
438 }
439 }
440
441 /*=====================================================================*\
442 || ###################################################################
443 || # $HeadURL$
444 || # $Id$
445 || ###################################################################
446 \*=====================================================================*/
447 ?>