Implement basic filtering capabilities in the issue search view.
Since IDF's text search component does not allow further restrictions on the result set, we make a second, filtered query to restrict to the item state ('open' or 'closed') and optionally a label. All in all this is all harder than it could be, especially the tag cloud is very monolithic and should be replaced by a data-driven component that is less dependent on a single data / query and link usage, but this would for now require too many changes. Similar questionable is the code duplication for the index, listStatus and listLabel view implementations that all do more or less the same. The search implementation now only uses one implementation for a very similar use case. It also removes the artificial restriction to 100 results we had previously there and does not query a record for each single result (as was done with Pluf_Search_ResultSet previously). On my way through this I tried to generalize a couple of i18n texts and removed smaller issues like the "trailing comma" in label lists. This partially fixes issue 548.
This commit is contained in:
@@ -431,45 +431,142 @@ class IDF_Views_Issue
|
||||
|
||||
public $search_precond = array('IDF_Precondition::accessIssues');
|
||||
public function search($request, $match)
|
||||
{
|
||||
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
|
||||
return $this->doSearch($request, $query, 'open');
|
||||
}
|
||||
|
||||
public $searchStatus_precond = array('IDF_Precondition::accessIssues');
|
||||
public function searchStatus($request, $match)
|
||||
{
|
||||
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
|
||||
$status = in_array($match[2], array('open', 'closed')) ? $match[2] : 'open';
|
||||
return $this->doSearch($request, $query, $status);
|
||||
}
|
||||
|
||||
public $searchLabel_precond = array('IDF_Precondition::accessIssues');
|
||||
public function searchLabel($request, $match)
|
||||
{
|
||||
$query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
|
||||
$tag_id = intval($match[2]);
|
||||
$status = in_array($match[3], array('open', 'closed')) ? $match[3] : 'open';
|
||||
return $this->doSearch($request, $query, $status, $tag_id);
|
||||
}
|
||||
|
||||
private function doSearch($request, $query, $status, $tag_id=null)
|
||||
{
|
||||
$prj = $request->project;
|
||||
if (!isset($request->REQUEST['q']) or trim($request->REQUEST['q']) == '') {
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index',
|
||||
array($prj->shortname));
|
||||
if (trim($query) == '') {
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index', array($prj->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$q = $request->REQUEST['q'];
|
||||
$title = sprintf(__('Search Issues - %s'), $q);
|
||||
$issues = new Pluf_Search_ResultSet(IDF_Search::mySearch($q, $prj, 'IDF_Issue'));
|
||||
if (count($issues) > 100) {
|
||||
// no more than 100 results as we do not care
|
||||
$issues->results = array_slice($issues->results, 0, 100);
|
||||
|
||||
$tag = null;
|
||||
if ($tag_id !== null) {
|
||||
$tag = Pluf_Shortcuts_GetObjectOr404('IDF_Tag', $tag_id);
|
||||
}
|
||||
|
||||
$title = sprintf(__('Search issues - %s'), $query);
|
||||
if ($status === 'closed') {
|
||||
$title = sprintf(__('Search closed issues - %s'), $query);
|
||||
}
|
||||
|
||||
// using Plufs ResultSet implementation here is inefficient, because
|
||||
// it makes a SELECT for each item and does not allow for further
|
||||
// filtering neither, so we just return the ids and filter by them
|
||||
// and other things in the next round
|
||||
$results = IDF_Search::mySearch($query, $prj, 'IDF_Issue');
|
||||
|
||||
$issue_ids = array();
|
||||
foreach ($results as $result) {
|
||||
$issue_ids[] = $result['model_id'];
|
||||
}
|
||||
|
||||
$otags = $prj->getTagIdsByStatus($status);
|
||||
if (count($otags) == 0) $otags[] = 0;
|
||||
$sql = new Pluf_SQL(
|
||||
'id IN ('.implode(',', $issue_ids).') '.
|
||||
'AND status IN ('.implode(', ', $otags).') '.
|
||||
($tag_id !== null ? 'AND idf_tag_id='.$tag_id.' ' : '')
|
||||
);
|
||||
$model = new IDF_Issue();
|
||||
$issues = $model->getList(array('filter' => $sql->gen(), 'view' => 'join_tags'));
|
||||
|
||||
// we unfortunately loose the original sort order,
|
||||
// so we manually have to apply it here again
|
||||
$sorted_issues = new ArrayObject();
|
||||
$filtered_issue_ids = array();
|
||||
foreach ($issue_ids as $issue_id) {
|
||||
foreach ($issues as $issue) {
|
||||
if ($issue->id != $issue_id)
|
||||
continue;
|
||||
if (array_key_exists($issue_id, $sorted_issues))
|
||||
continue;
|
||||
$sorted_issues[$issue_id] = $issue;
|
||||
$filtered_issue_ids[] = $issue_id;
|
||||
}
|
||||
}
|
||||
|
||||
$pag = new Pluf_Paginator();
|
||||
$pag->items = $issues;
|
||||
$pag->class = 'recent-issues';
|
||||
$pag->item_extra_props = array('project_m' => $prj,
|
||||
'shortname' => $prj->shortname,
|
||||
'current_user' => $request->user);
|
||||
$pag->items = $sorted_issues;
|
||||
$pag->item_extra_props = array(
|
||||
'project_m' => $prj,
|
||||
'shortname' => $prj->shortname,
|
||||
'current_user' => $request->user
|
||||
);
|
||||
$pag->summary = __('This table shows the found issues.');
|
||||
$pag->action = array('IDF_Views_Issue::search', array($prj->shortname), array('q'=> $q));
|
||||
$pag->extra_classes = array('a-c', '', 'a-c', '');
|
||||
$list_display = array(
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display);
|
||||
$pag->items_per_page = 100;
|
||||
$pag->configure(array(
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
));
|
||||
// disable paginating
|
||||
$pag->items_per_page = PHP_INT_MAX;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
$params = array('page_title' => $title,
|
||||
'issues' => $pag,
|
||||
'q' => $q,
|
||||
);
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/issues/search.html', $params, $request);
|
||||
|
||||
if ($tag_id === null) {
|
||||
$pag->action = array('IDF_Views_Issue::searchStatus',
|
||||
array($prj->shortname, $status),
|
||||
array('q'=> $query),
|
||||
);
|
||||
} else {
|
||||
$pag->action = array('IDF_Views_Issue::searchLabel',
|
||||
array($prj->shortname, $tag_id, $status),
|
||||
array('q'=> $query),
|
||||
);
|
||||
}
|
||||
|
||||
// get stats about the issues
|
||||
$open = $prj->getIssueCountByStatus('open', $tag, $issue_ids);
|
||||
$closed = $prj->getIssueCountByStatus('closed', $tag, $issue_ids);
|
||||
|
||||
// query the available tags for this search result
|
||||
$all_tags = $prj->getTagsByIssues($filtered_issue_ids);
|
||||
$grouped_tags = array();
|
||||
foreach ($all_tags as $atag) {
|
||||
// group by class
|
||||
if (!array_key_exists($atag->class, $grouped_tags)) {
|
||||
$grouped_tags[$atag->class] = array();
|
||||
}
|
||||
$grouped_tags[$atag->class][] = $atag;
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'page_title' => $title,
|
||||
'issues' => $pag,
|
||||
'query' => $query,
|
||||
'status' => $status,
|
||||
'open' => $open,
|
||||
'closed' => $closed,
|
||||
'tag' => $tag,
|
||||
'all_tags' => $grouped_tags,
|
||||
);
|
||||
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/issues/search.html', $params, $request);
|
||||
}
|
||||
|
||||
public $view_precond = array('IDF_Precondition::accessIssues');
|
||||
|
Reference in New Issue
Block a user