db = BSApp::$db; $this->page = $page; $this->_processIncoming(); } /** * Processes the incoming variables and then sets all the sort order * information appropriately */ private function _processIncoming() { $this->sortkey = BSApp::$input->in['by']; if (!self::fetch_by_text(BSApp::$input->in['by'])) { $this->sortkey = (isset(bugdar::$userinfo['defaultsortkey']) ? bugdar::$userinfo['defaultsortkey'] : bugdar::$options['defaultsortkey']); } $this->direction = BSApp::$input->in['as']; if (!in_array($this->direction, array('asc', 'desc'))) { $this->direction = (isset(bugdar::$userinfo['defaultsortas']) ? bugdar::$userinfo['defaultsortas'] : bugdar::$options['defaultsortas']); } } /** * Fetch a SQL query to gather bugs with the sort filters applied * * @param string Additional WHERE clauses in an array * @param string A LIMIT clause * * @return string Compiled SQL query */ public function fetchSqlQuery($where = null, $limit = null) { // this WHERE clause is used for all the queries $basewhere = "bug.product IN (" . fetch_on_bits('canviewbugs') . ") AND (!bug.hidden OR (bug.hidden AND bug.product IN (" . fetch_on_bits('canviewhidden') . "))" . (can_perform('canviewownhidden') ? " OR (bug.hidden AND bug.userid = " . bugdar::$userinfo['userid'] . " AND bug.product IN (" . fetch_on_bits('canviewownhidden') . "))" : "") . ")" . ((bugdar::$options['hidestatuses'] || isset(bugdar::$userinfo['hidestatuses'])) ? " AND bug.status NOT IN (" . (bugdar::$userinfo['hidestatuses'] != '' ? bugdar::$userinfo['hidestatuses'] : bugdar::$options['hidestatuses']) . ")" : ""); // remap the sort keys to be actual SQL fields $querykeys = array( 'bugid' => 'bugid', 'summary' => 'summary', 'reporter' => 'userid', 'lastpost' => (can_perform('canviewhidden') ? "lastposttime" : "hiddenlastposttime"), 'assignedto'=> 'assignedto' ); switch ($this->sortkey) { case 'bugid': case 'summary': case 'reporter': case 'lastpost': case 'assignedto': $query = " SELECT bug.*, vote.votefor, vote.voteagainst FROM " . TABLE_PREFIX . "bug AS bug LEFT JOIN " . TABLE_PREFIX . "vote AS vote ON (bug.bugid = vote.bugid) WHERE $basewhere" . (is_array($where) ? " AND " . implode("\nAND ", $where) : "") . " ORDER BY " . $querykeys[ $this->sortkey ] . " " . strtoupper($this->direction) . ($this->sortkey != 'lastpost' ? ", " . $querykeys['lastpost'] . " " . strtoupper($this->direction) : "") . ($limit ? " LIMIT $limit" : ""); break; case 'product': case 'component': case 'version': case 'status': case 'resolution': case 'priority': case 'severity': $key = ($this->sortkey != 'component' ? $this->sortkey : 'product'); $query = " SELECT $key.*, bug.*, vote.votefor, vote.voteagainst FROM " . TABLE_PREFIX . "$key AS $key RIGHT JOIN " . TABLE_PREFIX . "bug AS bug ON (bug.$key = $key.{$key}id) LEFT JOIN " . TABLE_PREFIX . "vote AS vote ON (bug.bugid = vote.bugid) WHERE $basewhere" . (is_array($where) ? " AND " . implode("\nAND ", $where) : "") . " ORDER BY $key.displayorder " . strtoupper($this->direction) . ", bug.$querykeys[lastpost] " . strtoupper($this->direction) . ($limit ? " LIMIT $limit" : ""); break; case 'votes': $query = " SELECT bug.*, vote.votefor, vote.voteagainst FROM " . TABLE_PREFIX . "bug AS bug LEFT JOIN " . TABLE_PREFIX . "vote AS vote ON (bug.bugid = vote.bugid) WHERE $basewhere" . (is_array($where) ? " AND " . implode("\nAND ", $where) : "") . " ORDER BY vote.votefor " . strtoupper($this->direction) . ", vote.voteagainst " . strtoupper($this->fetchOppositeSortDirection()) . ", bug.$querykeys[lastpost] " . strtoupper($this->direction) . ($limit ? " LIMIT $limit" : ""); break; default: if (substr($this->sortkey, 0, 6) != 'custom') { return; } $query = " SELECT bug.*, vote.votefor, vote.voteagainst FROM " . TABLE_PREFIX . "bug AS bug LEFT JOIN " . TABLE_PREFIX . "vote AS vote ON (bug.bugid = vote.bugid) WHERE $basewhere" . (is_array($where) ? " AND " . implode("\nAND ", $where) : "") . " ORDER BY {$this->sortkey} " . strtoupper($this->direction) . ", " . $querykeys['lastpost'] . " " . strtoupper($this->direction) . ($limit ? " LIMIT $limit" : ""); } return $query; } /** * Returns the display text for a given sort order key * * @param string Sort order key, or FALSE for the array * @param bool Permission check the custom fields? * * @return mixed Display text if param is string, or array of all key=>text if param is NULL */ public static function fetch_by_text($key, $doPerm = true) { $keys = array( 'lastpost' => T('Last Post Time'), 'bugid' => T('Bug ID'), 'summary' => T('Summary'), 'reporter' => T('Reporter'), 'product' => T('Product'), 'component' => T('Component'), 'version' => T('Version'), 'status' => T('Status'), 'resolution' => T('Resolution'), 'priority' => T('Priority'), 'severity' => T('Severity'), 'votes' => T('Votes'), 'assignedto' => T('Assigned To') ); $fields = self::_fetch_custom_fields($doPerm); foreach ($fields AS $field) { $keys['custom' . $field['fieldid']] = $field['name']; } if ($key === false) { return $keys; } else { return $keys["$key"]; } } /** * Returns the display text for a given sort order direction * * @param string Sort direction, or FALSE for the array * * @return mixed Display text if param is string, or array of all key=>text if param is NULL */ public static function fetch_as_text($key) { $keys = array( 'desc' => T('Descending'), 'asc' => T('Ascending') ); if ($key === false) { return $keys; } else { return $keys["$key"]; } } /** * Returns a multi-dimensional array with sort by keys indexing arrays * with 'image' and 'href' keys that store the values from * fetchSortImage() and fetchSortLink(), respectively * * @param string Extra GET parameters to pass to fetchSortLink() * * @return array Array as described above */ public function fetchDisplayArray($params = null) { $return = self::fetch_by_text(false); foreach ($return as $key => $nil) { $return["$key"] = array('image' => ($this->sortkey == $key ? $this->fetchSortImage() : ''), 'href' => $this->fetchSortLink($key, $params, true)); } return $return; } /** * Returns the entire tag for the sort arrow * * @return string HTML tag */ public function fetchSortImage() { return ''; } /** * Returns the href value for an tag by generating all the necessary * bits and concat'ing it onto an extra string of GETs (optional) * * @param string Sorting key * @param string Additional GET parameters * @param bool Highlight the current sortkey if that's passed? * * @return string HREF */ public function fetchSortLink($key, $params = null, $highlight = false) { if ($params) { $params .= '&'; } return $this->page . '.php?' . $params . 'by=' . $key . '&as=' . (($this->sortkey == $key && $highlight) ? $this->fetchOppositeSortDirection() . '" class="select' : $this->fetchSortDirection()); } /** * Returns the OPPOSITE direction to sort when you click on a link * * @return string Either asc or desc */ public function fetchOppositeSortDirection() { if ($this->direction == 'asc') { return 'desc'; } else { return 'asc'; } } /** * Returns the current sorted direction for the image path * * @return string Either asc or desc */ public function fetchSortDirection() { return $this->direction; } /** * Returns the HTML code for bug listing table column headers * * @param bool Include the sort links/image? * @param string Additional GET params to pass to fetchSortLink() * * @return string HTML code */ public function constructColumnHeaders($sortable, $params = null) { $this->_processColumns(); $names = self::fetch_by_text(false); $output = ''; foreach ($this->columns as $columns) { $build = array(); foreach ($columns as $column) { $build[] = ($sortable ? '' . $names[$column] . '' : $names[$column]); } $image = ((in_array($this->sortkey, $columns) && $sortable) ? $this->fetchSortImage() : ''); $name = implode(' / ', $build); $tpl = new BSTemplate('list_head'); $tpl->vars = array( 'name' => $name, 'image' => $image ); $output .= $tpl->evaluate()->getTemplate(); } return $output; } /** * Returns the HTML code for a row of data for the bug listing * * @param array Bug data array * @param string Additional link params * * @return string Row HTML */ function constructRow($bug, $params = null) { $this->_processColumns(); foreach ($this->columns as $columns) { if (sizeof($columns) > 1) { $build = array(); foreach ($columns as $column) { $build[] = $this->_processDataForColumn($bug, $column, $params, true); } $data = "\n\t\t" . implode("\n\t\t", $build) . "\n\t"; } else { $data = $this->_processDataForColumn($bug, $columns[0], $params, false); } $fields .= "\n\t$data"; } $tpl = new BSTemplate('trackerhome_bits'); $tpl->vars = array( 'bug' => $bug, 'fields'=> $fields ); return $tpl->evaluate()->getTemplate(); } /** * Handler for special-case column data * * @param array Bug data * @param string Column name * @param string Additional URL params * @param bool Will this column have multiple data sets? * * @return string Processed column data */ private function _processDataForColumn($bug, $column, $params = null, $multi = false) { $open = ($multi ? '
' : ''); $close = ($multi ? '
' : ''); switch ($column) { case 'summary': return $open . '' . $bug['summary'] . '' . $close; case 'reporter': return $open . ($bug['userid'] ? $bug['username'] : T('Guest')) . $close; case 'lastpost': return "\n\t\t
" . $bug['lastposttime'] . "
\n\t\t
" . T('by') . ' ' . ($bug['lastpost'] ? $bug['lastpost'] : T('Guest')) . "
\n\t"; case 'votes': return "\n\t\t
" . T('For:') . ' ' . $bug['votefor'] . "
\n\t\t
" . T('Against:') . ' ' . $bug['voteagainst'] . "
\n\t"; default: return $open . $bug["$column"] . $close; } } /** * Sets up $this->columns so that the data can be processed more * easily */ private function _processColumns() { if (is_array($this->columns)) { return; } $columns = self::fetch_by_text(false); $array = ((bugdar::$userinfo['userid'] && is_array(bugdar::$userinfo['columnoptions'])) ? bugdar::$userinfo['columnoptions'] : bugdar::$options['columnoptions']); foreach ($array as $column => $position) { // the column doesn't exist, or more likely, we don't have permission to view it if (!isset($columns[$column])) { continue; } if ($position > 0) { $this->columns["$position"][] = $column; } } ksort($this->columns); } /** * Returns an array of all the custom fields that the current user * has permission to use * * @param boolean Ignore permissions? * * @return array */ private static function _fetch_custom_fields($doPerm = true) { static $fields = array(), $fieldsPerm = array(); if ($doPerm && !empty($fieldsPerm)) { return $fieldsPerm; } else if (!$doPerm && !empty($fields)) { return $fields; } if ($doPerm) { $fields_fetch = BSApp::$db->query(" SELECT bugfield.*, MAX(permission.mask) AS mask FROM " . TABLE_PREFIX . "bugfield AS bugfield LEFT JOIN " . TABLE_PREFIX . "bugfieldpermission AS permission ON (bugfield.fieldid = permission.fieldid) WHERE (permission.mask = 2 OR permission.mask = 1) AND permission.usergroupid IN (" . bugdar::$userinfo['usergroupid'] . (sizeof(bugdar::$userinfo['groupids']) != 0 ? ',' . implode(',', bugdar::$userinfo['groupids']) : '') . ") GROUP BY (bugfield.fieldid) "); } else { $fields_fetch = BSApp::$db->query("SELECT * FROM " . TABLE_PREFIX . "bugfield"); } foreach ($fields_fetch as $field) { if ($doPerm) { $fieldsPerm[$field['fieldid']] = $field; } else { $fields[$field['fieldid']] = $field; } } return $fields; } } ?>