2011-06-30 01:16:33 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
2012-02-29 06:08:02 +01:00
|
|
|
* Copyright 2012 Facebook, Inc.
|
2011-06-30 01:16:33 +02:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Query tasks by specific criteria. This class uses the higher-performance
|
|
|
|
* but less-general Maniphest indexes to satisfy queries.
|
2011-07-04 22:04:22 +02:00
|
|
|
*
|
|
|
|
* @group maniphest
|
2011-06-30 01:16:33 +02:00
|
|
|
*/
|
|
|
|
final class ManiphestTaskQuery {
|
|
|
|
|
2011-12-02 16:30:20 +01:00
|
|
|
private $taskIDs = array();
|
2011-06-30 01:16:33 +02:00
|
|
|
private $authorPHIDs = array();
|
|
|
|
private $ownerPHIDs = array();
|
|
|
|
private $includeUnowned = null;
|
|
|
|
private $projectPHIDs = array();
|
2012-02-29 06:08:02 +01:00
|
|
|
private $xprojectPHIDs = array();
|
2011-07-07 19:24:49 +02:00
|
|
|
private $subscriberPHIDs = array();
|
2011-07-07 22:50:56 +02:00
|
|
|
private $anyProject = false;
|
2012-02-29 06:08:02 +01:00
|
|
|
private $includeNoProject = null;
|
2011-06-30 01:16:33 +02:00
|
|
|
|
|
|
|
private $status = 'status-any';
|
|
|
|
const STATUS_ANY = 'status-any';
|
|
|
|
const STATUS_OPEN = 'status-open';
|
|
|
|
const STATUS_CLOSED = 'status-closed';
|
|
|
|
|
|
|
|
private $priority = null;
|
|
|
|
|
|
|
|
private $groupBy = 'group-none';
|
|
|
|
const GROUP_NONE = 'group-none';
|
|
|
|
const GROUP_PRIORITY = 'group-priority';
|
|
|
|
const GROUP_OWNER = 'group-owner';
|
|
|
|
const GROUP_STATUS = 'group-status';
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-20 03:47:34 +01:00
|
|
|
const GROUP_PROJECT = 'group-project';
|
2011-06-30 01:16:33 +02:00
|
|
|
|
|
|
|
private $orderBy = 'order-modified';
|
|
|
|
const ORDER_PRIORITY = 'order-priority';
|
|
|
|
const ORDER_CREATED = 'order-created';
|
|
|
|
const ORDER_MODIFIED = 'order-modified';
|
|
|
|
|
|
|
|
private $limit = null;
|
|
|
|
const DEFAULT_PAGE_SIZE = 1000;
|
|
|
|
|
|
|
|
private $offset = 0;
|
|
|
|
private $calculateRows = false;
|
|
|
|
|
|
|
|
private $rowCount = null;
|
|
|
|
|
|
|
|
|
|
|
|
public function withAuthors(array $authors) {
|
|
|
|
$this->authorPHIDs = $authors;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-12-02 16:30:20 +01:00
|
|
|
public function withTaskIDs(array $ids) {
|
|
|
|
$this->taskIDs = $ids;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-06-30 01:16:33 +02:00
|
|
|
public function withOwners(array $owners) {
|
|
|
|
$this->includeUnowned = false;
|
|
|
|
foreach ($owners as $k => $phid) {
|
|
|
|
if ($phid == ManiphestTaskOwner::OWNER_UP_FOR_GRABS) {
|
|
|
|
$this->includeUnowned = true;
|
|
|
|
unset($owners[$k]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$this->ownerPHIDs = $owners;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function withProjects(array $projects) {
|
2012-02-29 06:08:02 +01:00
|
|
|
$this->includeNoProject = false;
|
|
|
|
foreach ($projects as $k => $phid) {
|
|
|
|
if ($phid == ManiphestTaskOwner::PROJECT_NO_PROJECT) {
|
|
|
|
$this->includeNoProject = true;
|
|
|
|
unset($projects[$k]);
|
|
|
|
}
|
|
|
|
}
|
2011-06-30 01:16:33 +02:00
|
|
|
$this->projectPHIDs = $projects;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2012-02-29 06:08:02 +01:00
|
|
|
public function withoutProjects(array $projects) {
|
|
|
|
$this->xprojectPHIDs = $projects;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-06-30 01:16:33 +02:00
|
|
|
public function withStatus($status) {
|
|
|
|
$this->status = $status;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function withPriority($priority) {
|
|
|
|
$this->priority = $priority;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-07-07 19:24:49 +02:00
|
|
|
public function withSubscribers(array $subscribers) {
|
|
|
|
$this->subscriberPHIDs = $subscribers;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-06-30 01:16:33 +02:00
|
|
|
public function setGroupBy($group) {
|
|
|
|
$this->groupBy = $group;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setOrderBy($order) {
|
|
|
|
$this->orderBy = $order;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setLimit($limit) {
|
|
|
|
$this->limit = $limit;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setOffset($offset) {
|
|
|
|
$this->offset = $offset;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setCalculateRows($calculate_rows) {
|
|
|
|
$this->calculateRows = $calculate_rows;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getRowCount() {
|
|
|
|
if ($this->rowCount === null) {
|
|
|
|
throw new Exception(
|
|
|
|
"You must execute a query with setCalculateRows() before you can ".
|
|
|
|
"retrieve a row count.");
|
|
|
|
}
|
|
|
|
return $this->rowCount;
|
|
|
|
}
|
|
|
|
|
2011-07-07 22:50:56 +02:00
|
|
|
public function withAnyProject($any_project) {
|
|
|
|
$this->anyProject = $any_project;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-06-30 01:16:33 +02:00
|
|
|
public function execute() {
|
|
|
|
|
|
|
|
$task_dao = new ManiphestTask();
|
|
|
|
$conn = $task_dao->establishConnection('r');
|
|
|
|
|
|
|
|
if ($this->calculateRows) {
|
|
|
|
$calc = 'SQL_CALC_FOUND_ROWS';
|
|
|
|
} else {
|
|
|
|
$calc = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
$where = array();
|
2011-12-02 16:30:20 +01:00
|
|
|
$where[] = $this->buildTaskIDsWhereClause($conn);
|
2011-06-30 01:16:33 +02:00
|
|
|
$where[] = $this->buildStatusWhereClause($conn);
|
|
|
|
$where[] = $this->buildPriorityWhereClause($conn);
|
|
|
|
$where[] = $this->buildAuthorWhereClause($conn);
|
|
|
|
$where[] = $this->buildOwnerWhereClause($conn);
|
2011-07-07 19:24:49 +02:00
|
|
|
$where[] = $this->buildSubscriberWhereClause($conn);
|
2011-06-30 01:16:33 +02:00
|
|
|
$where[] = $this->buildProjectWhereClause($conn);
|
2012-02-29 06:08:02 +01:00
|
|
|
$where[] = $this->buildXProjectWhereClause($conn);
|
2011-06-30 01:16:33 +02:00
|
|
|
|
|
|
|
$where = array_filter($where);
|
|
|
|
if ($where) {
|
|
|
|
$where = 'WHERE ('.implode(') AND (', $where).')';
|
|
|
|
} else {
|
|
|
|
$where = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
$join = array();
|
|
|
|
$join[] = $this->buildProjectJoinClause($conn);
|
2012-02-29 06:08:02 +01:00
|
|
|
$join[] = $this->buildXProjectJoinClause($conn);
|
2011-07-07 19:24:49 +02:00
|
|
|
$join[] = $this->buildSubscriberJoinClause($conn);
|
2011-06-30 01:16:33 +02:00
|
|
|
|
|
|
|
$join = array_filter($join);
|
|
|
|
if ($join) {
|
|
|
|
$join = implode(' ', $join);
|
|
|
|
} else {
|
|
|
|
$join = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
$having = '';
|
|
|
|
$count = '';
|
|
|
|
$group = '';
|
|
|
|
if (count($this->projectPHIDs) > 1) {
|
|
|
|
|
|
|
|
// If we're searching for more than one project:
|
|
|
|
// - We'll get multiple rows for tasks when they join the project table
|
|
|
|
// multiple times. We use GROUP BY to make them distinct again.
|
|
|
|
// - We want to treat the query as an intersection query, not a union
|
|
|
|
// query. We sum the project count and require it be the same as the
|
2011-07-07 22:50:56 +02:00
|
|
|
// number of projects we're searching for. (If 'anyProject' is set,
|
|
|
|
// we do union instead.)
|
2011-06-30 01:16:33 +02:00
|
|
|
|
|
|
|
$group = 'GROUP BY task.id';
|
2011-07-07 22:50:56 +02:00
|
|
|
|
|
|
|
if (!$this->anyProject) {
|
2012-02-29 06:08:02 +01:00
|
|
|
$count = ', COUNT(project.projectPHID) projectCount';
|
2011-07-07 22:50:56 +02:00
|
|
|
$having = qsprintf(
|
|
|
|
$conn,
|
|
|
|
'HAVING projectCount = %d',
|
|
|
|
count($this->projectPHIDs));
|
|
|
|
}
|
2011-06-30 01:16:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$order = $this->buildOrderClause($conn);
|
|
|
|
|
|
|
|
$offset = (int)nonempty($this->offset, 0);
|
|
|
|
$limit = (int)nonempty($this->limit, self::DEFAULT_PAGE_SIZE);
|
|
|
|
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-20 03:47:34 +01:00
|
|
|
if ($this->groupBy == self::GROUP_PROJECT) {
|
|
|
|
$limit = PHP_INT_MAX;
|
|
|
|
$offset = 0;
|
|
|
|
}
|
|
|
|
|
2011-06-30 01:16:33 +02:00
|
|
|
$data = queryfx_all(
|
|
|
|
$conn,
|
|
|
|
'SELECT %Q * %Q FROM %T task %Q %Q %Q %Q %Q LIMIT %d, %d',
|
|
|
|
$calc,
|
|
|
|
$count,
|
|
|
|
$task_dao->getTableName(),
|
|
|
|
$join,
|
|
|
|
$where,
|
|
|
|
$group,
|
|
|
|
$having,
|
|
|
|
$order,
|
|
|
|
$offset,
|
|
|
|
$limit);
|
|
|
|
|
|
|
|
if ($this->calculateRows) {
|
|
|
|
$count = queryfx_one(
|
|
|
|
$conn,
|
|
|
|
'SELECT FOUND_ROWS() N');
|
|
|
|
$this->rowCount = $count['N'];
|
|
|
|
} else {
|
|
|
|
$this->rowCount = null;
|
|
|
|
}
|
|
|
|
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-20 03:47:34 +01:00
|
|
|
$tasks = $task_dao->loadAllFromArray($data);
|
|
|
|
|
|
|
|
if ($this->groupBy == self::GROUP_PROJECT) {
|
|
|
|
$tasks = $this->applyGroupByProject($tasks);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $tasks;
|
2011-06-30 01:16:33 +02:00
|
|
|
}
|
|
|
|
|
2011-12-02 16:30:20 +01:00
|
|
|
private function buildTaskIDsWhereClause($conn) {
|
|
|
|
if (!$this->taskIDs) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return qsprintf(
|
|
|
|
$conn,
|
|
|
|
'id in (%Ld)',
|
|
|
|
$this->taskIDs);
|
|
|
|
}
|
|
|
|
|
2011-06-30 01:16:33 +02:00
|
|
|
private function buildStatusWhereClause($conn) {
|
|
|
|
switch ($this->status) {
|
|
|
|
case self::STATUS_ANY:
|
|
|
|
return null;
|
|
|
|
case self::STATUS_OPEN:
|
|
|
|
return 'status = 0';
|
|
|
|
case self::STATUS_CLOSED:
|
|
|
|
return 'status > 0';
|
|
|
|
default:
|
|
|
|
throw new Exception("Unknown status query '{$this->status}'!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildPriorityWhereClause($conn) {
|
|
|
|
if ($this->priority === null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return qsprintf(
|
|
|
|
$conn,
|
|
|
|
'priority = %d',
|
|
|
|
$this->priority);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildAuthorWhereClause($conn) {
|
|
|
|
if (!$this->authorPHIDs) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return qsprintf(
|
|
|
|
$conn,
|
|
|
|
'authorPHID in (%Ls)',
|
|
|
|
$this->authorPHIDs);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildOwnerWhereClause($conn) {
|
|
|
|
if (!$this->ownerPHIDs) {
|
|
|
|
if ($this->includeUnowned === null) {
|
|
|
|
return null;
|
|
|
|
} else if ($this->includeUnowned) {
|
|
|
|
return qsprintf(
|
|
|
|
$conn,
|
|
|
|
'ownerPHID IS NULL');
|
|
|
|
} else {
|
|
|
|
return qsprintf(
|
|
|
|
$conn,
|
|
|
|
'ownerPHID IS NOT NULL');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->includeUnowned) {
|
|
|
|
return qsprintf(
|
|
|
|
$conn,
|
|
|
|
'ownerPHID IN (%Ls) OR ownerPHID IS NULL',
|
|
|
|
$this->ownerPHIDs);
|
|
|
|
} else {
|
|
|
|
return qsprintf(
|
|
|
|
$conn,
|
|
|
|
'ownerPHID IN (%Ls)',
|
|
|
|
$this->ownerPHIDs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-07 19:24:49 +02:00
|
|
|
private function buildSubscriberWhereClause($conn) {
|
|
|
|
if (!$this->subscriberPHIDs) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return qsprintf(
|
|
|
|
$conn,
|
|
|
|
'subscriber.subscriberPHID IN (%Ls)',
|
|
|
|
$this->subscriberPHIDs);
|
|
|
|
}
|
|
|
|
|
2011-06-30 01:16:33 +02:00
|
|
|
private function buildProjectWhereClause($conn) {
|
2012-02-29 06:08:02 +01:00
|
|
|
if (!$this->projectPHIDs && !$this->includeNoProject) {
|
2011-06-30 01:16:33 +02:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2012-02-29 06:08:02 +01:00
|
|
|
$parts = array();
|
|
|
|
if ($this->projectPHIDs) {
|
|
|
|
$parts[] = qsprintf(
|
|
|
|
$conn,
|
|
|
|
'project.projectPHID in (%Ls)',
|
|
|
|
$this->projectPHIDs);
|
|
|
|
}
|
|
|
|
if ($this->includeNoProject) {
|
|
|
|
$parts[] = qsprintf(
|
|
|
|
$conn,
|
|
|
|
'project.projectPHID IS NULL');
|
|
|
|
}
|
|
|
|
|
|
|
|
return '('.implode(') OR (', $parts).')';
|
2011-06-30 01:16:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private function buildProjectJoinClause($conn) {
|
2012-02-29 06:08:02 +01:00
|
|
|
if (!$this->projectPHIDs && !$this->includeNoProject) {
|
2011-06-30 01:16:33 +02:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$project_dao = new ManiphestTaskProject();
|
|
|
|
return qsprintf(
|
|
|
|
$conn,
|
2012-02-29 06:08:02 +01:00
|
|
|
'%Q JOIN %T project ON project.taskPHID = task.phid',
|
|
|
|
($this->includeNoProject ? 'LEFT' : ''),
|
2011-06-30 01:16:33 +02:00
|
|
|
$project_dao->getTableName());
|
|
|
|
}
|
|
|
|
|
2012-02-29 06:08:02 +01:00
|
|
|
private function buildXProjectWhereClause($conn) {
|
|
|
|
if (!$this->xprojectPHIDs) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return qsprintf(
|
|
|
|
$conn,
|
|
|
|
'xproject.projectPHID IS NULL');
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildXProjectJoinClause($conn) {
|
|
|
|
if (!$this->xprojectPHIDs) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$project_dao = new ManiphestTaskProject();
|
|
|
|
return qsprintf(
|
|
|
|
$conn,
|
|
|
|
'LEFT JOIN %T xproject ON xproject.taskPHID = task.phid
|
|
|
|
AND xproject.projectPHID IN (%Ls)',
|
|
|
|
$project_dao->getTableName(),
|
|
|
|
$this->xprojectPHIDs);
|
|
|
|
}
|
|
|
|
|
2011-07-07 19:24:49 +02:00
|
|
|
private function buildSubscriberJoinClause($conn) {
|
|
|
|
if (!$this->subscriberPHIDs) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$subscriber_dao = new ManiphestTaskSubscriber();
|
|
|
|
return qsprintf(
|
|
|
|
$conn,
|
|
|
|
'JOIN %T subscriber ON subscriber.taskPHID = task.phid',
|
|
|
|
$subscriber_dao->getTableName());
|
|
|
|
}
|
|
|
|
|
2011-06-30 01:16:33 +02:00
|
|
|
private function buildOrderClause($conn) {
|
|
|
|
$order = array();
|
|
|
|
|
|
|
|
switch ($this->groupBy) {
|
|
|
|
case self::GROUP_NONE:
|
|
|
|
break;
|
|
|
|
case self::GROUP_PRIORITY:
|
|
|
|
$order[] = 'priority';
|
|
|
|
break;
|
|
|
|
case self::GROUP_OWNER:
|
|
|
|
$order[] = 'ownerOrdering';
|
|
|
|
break;
|
|
|
|
case self::GROUP_STATUS:
|
|
|
|
$order[] = 'status';
|
|
|
|
break;
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-20 03:47:34 +01:00
|
|
|
case self::GROUP_PROJECT:
|
|
|
|
// NOTE: We have to load the entire result set and apply this grouping
|
|
|
|
// in the PHP process for now.
|
|
|
|
break;
|
2011-06-30 01:16:33 +02:00
|
|
|
default:
|
|
|
|
throw new Exception("Unknown group query '{$this->groupBy}'!");
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ($this->orderBy) {
|
|
|
|
case self::ORDER_PRIORITY:
|
|
|
|
$order[] = 'priority';
|
2012-04-02 21:12:04 +02:00
|
|
|
$order[] = 'subpriority';
|
2011-06-30 01:16:33 +02:00
|
|
|
$order[] = 'dateModified';
|
|
|
|
break;
|
|
|
|
case self::ORDER_CREATED:
|
|
|
|
$order[] = 'id';
|
|
|
|
break;
|
|
|
|
case self::ORDER_MODIFIED:
|
|
|
|
$order[] = 'dateModified';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new Exception("Unknown order query '{$this->orderBy}'!");
|
|
|
|
}
|
|
|
|
|
|
|
|
$order = array_unique($order);
|
|
|
|
|
|
|
|
if (empty($order)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($order as $k => $column) {
|
|
|
|
switch ($column) {
|
2012-04-02 21:12:04 +02:00
|
|
|
case 'subpriority':
|
2011-06-30 01:16:33 +02:00
|
|
|
case 'ownerOrdering':
|
|
|
|
$order[$k] = "task.{$column} ASC";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
$order[$k] = "task.{$column} DESC";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 'ORDER BY '.implode(', ', $order);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-20 03:47:34 +01:00
|
|
|
/**
|
|
|
|
* To get paging to work for "group by project", we need to do a bunch of
|
|
|
|
* server-side magic since there's currently no way to sort by project name on
|
|
|
|
* the database.
|
|
|
|
*
|
|
|
|
* TODO: Move this all to the database.
|
|
|
|
*/
|
|
|
|
private function applyGroupByProject(array $tasks) {
|
|
|
|
|
|
|
|
$project_phids = array();
|
|
|
|
foreach ($tasks as $task) {
|
|
|
|
foreach ($task->getProjectPHIDs() as $phid) {
|
|
|
|
$project_phids[$phid] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$handles = id(new PhabricatorObjectHandleData(array_keys($project_phids)))
|
|
|
|
->loadHandles();
|
|
|
|
|
|
|
|
$max = 1;
|
|
|
|
foreach ($handles as $handle) {
|
|
|
|
$max = max($max, strlen($handle->getName()));
|
|
|
|
}
|
|
|
|
|
|
|
|
$items = array();
|
|
|
|
$ii = 0;
|
|
|
|
foreach ($tasks as $key => $task) {
|
|
|
|
$phids = $task->getProjectPHIDs();
|
2012-03-30 19:55:18 +02:00
|
|
|
if (!$this->anyProject && $this->projectPHIDs) {
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-20 03:47:34 +01:00
|
|
|
$phids = array_diff($phids, $this->projectPHIDs);
|
|
|
|
}
|
|
|
|
if ($phids) {
|
|
|
|
foreach ($phids as $phid) {
|
|
|
|
$items[] = array(
|
|
|
|
'key' => $key,
|
|
|
|
'seq' => sprintf(
|
|
|
|
'%'.$max.'s%d',
|
|
|
|
$handles[$phid]->getName(),
|
|
|
|
$ii),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Sort "no project" tasks first.
|
|
|
|
$items[] = array(
|
|
|
|
'key' => $key,
|
|
|
|
'seq' => '',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
++$ii;
|
|
|
|
}
|
|
|
|
|
|
|
|
$items = isort($items, 'seq');
|
|
|
|
$items = array_slice(
|
|
|
|
$items,
|
|
|
|
nonempty($this->offset),
|
|
|
|
nonempty($this->limit, self::DEFAULT_PAGE_SIZE));
|
|
|
|
|
|
|
|
$result = array();
|
|
|
|
foreach ($items as $item) {
|
|
|
|
$result[] = $tasks[$item['key']];
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2011-06-30 01:16:33 +02:00
|
|
|
}
|