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