Changeset View
Changeset View
Standalone View
Standalone View
src/applications/maniphest/query/ManiphestTaskQuery.php
Show First 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery { | ||||
const ORDER_PRIORITY = 'order-priority'; | const ORDER_PRIORITY = 'order-priority'; | ||||
const ORDER_CREATED = 'order-created'; | const ORDER_CREATED = 'order-created'; | ||||
const ORDER_MODIFIED = 'order-modified'; | const ORDER_MODIFIED = 'order-modified'; | ||||
const ORDER_TITLE = 'order-title'; | const ORDER_TITLE = 'order-title'; | ||||
private $needSubscriberPHIDs; | private $needSubscriberPHIDs; | ||||
private $needProjectPHIDs; | private $needProjectPHIDs; | ||||
private $blockingTasks; | |||||
private $blockedTasks; | |||||
const DEFAULT_PAGE_SIZE = 1000; | const DEFAULT_PAGE_SIZE = 1000; | ||||
public function withAuthors(array $authors) { | public function withAuthors(array $authors) { | ||||
$this->authorPHIDs = $authors; | $this->authorPHIDs = $authors; | ||||
return $this; | return $this; | ||||
} | } | ||||
public function withIDs(array $ids) { | public function withIDs(array $ids) { | ||||
▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | public function withAnyProjects(array $projects) { | ||||
return $this; | return $this; | ||||
} | } | ||||
public function withAnyUserProjects(array $users) { | public function withAnyUserProjects(array $users) { | ||||
$this->anyUserProjectPHIDs = $users; | $this->anyUserProjectPHIDs = $users; | ||||
return $this; | return $this; | ||||
} | } | ||||
/** | |||||
* True returns tasks that are blocking other tasks only. | |||||
* False returns tasks that are not blocking other tasks only. | |||||
* Null returns tasks regardless of blocking status. | |||||
*/ | |||||
public function withBlockingTasks($mode) { | |||||
$this->blockingTasks = $mode; | |||||
return $this; | |||||
} | |||||
public function shouldJoinBlockingTasks() { | |||||
return $this->blockingTasks !== null; | |||||
} | |||||
/** | |||||
* True returns tasks that are blocked by other tasks only. | |||||
* False returns tasks that are not blocked by other tasks only. | |||||
* Null returns tasks regardless of blocked by status. | |||||
*/ | |||||
public function withBlockedTasks($mode) { | |||||
$this->blockedTasks = $mode; | |||||
return $this; | |||||
} | |||||
public function shouldJoinBlockedTasks() { | |||||
return $this->blockedTasks !== null; | |||||
} | |||||
public function withDateCreatedBefore($date_created_before) { | public function withDateCreatedBefore($date_created_before) { | ||||
$this->dateCreatedBefore = $date_created_before; | $this->dateCreatedBefore = $date_created_before; | ||||
return $this; | return $this; | ||||
} | } | ||||
public function withDateCreatedAfter($date_created_after) { | public function withDateCreatedAfter($date_created_after) { | ||||
$this->dateCreatedAfter = $date_created_after; | $this->dateCreatedAfter = $date_created_after; | ||||
return $this; | return $this; | ||||
Show All 30 Lines | public function loadPage() { | ||||
$conn = $task_dao->establishConnection('r'); | $conn = $task_dao->establishConnection('r'); | ||||
$where = array(); | $where = array(); | ||||
$where[] = $this->buildTaskIDsWhereClause($conn); | $where[] = $this->buildTaskIDsWhereClause($conn); | ||||
$where[] = $this->buildTaskPHIDsWhereClause($conn); | $where[] = $this->buildTaskPHIDsWhereClause($conn); | ||||
$where[] = $this->buildStatusWhereClause($conn); | $where[] = $this->buildStatusWhereClause($conn); | ||||
$where[] = $this->buildStatusesWhereClause($conn); | $where[] = $this->buildStatusesWhereClause($conn); | ||||
$where[] = $this->buildPrioritiesWhereClause($conn); | $where[] = $this->buildPrioritiesWhereClause($conn); | ||||
$where[] = $this->buildDependenciesWhereClause($conn); | |||||
$where[] = $this->buildAuthorWhereClause($conn); | $where[] = $this->buildAuthorWhereClause($conn); | ||||
$where[] = $this->buildOwnerWhereClause($conn); | $where[] = $this->buildOwnerWhereClause($conn); | ||||
$where[] = $this->buildProjectWhereClause($conn); | $where[] = $this->buildProjectWhereClause($conn); | ||||
$where[] = $this->buildAnyProjectWhereClause($conn); | $where[] = $this->buildAnyProjectWhereClause($conn); | ||||
$where[] = $this->buildAnyUserProjectWhereClause($conn); | $where[] = $this->buildAnyUserProjectWhereClause($conn); | ||||
$where[] = $this->buildXProjectWhereClause($conn); | $where[] = $this->buildXProjectWhereClause($conn); | ||||
$where[] = $this->buildFullTextWhereClause($conn); | $where[] = $this->buildFullTextWhereClause($conn); | ||||
▲ Show 20 Lines • Show All 297 Lines • ▼ Show 20 Lines | private function buildFullTextWhereClause(AphrontDatabaseConnection $conn) { | ||||
} | } | ||||
return qsprintf( | return qsprintf( | ||||
$conn, | $conn, | ||||
'phid IN (%Ls)', | 'phid IN (%Ls)', | ||||
$fulltext_results); | $fulltext_results); | ||||
} | } | ||||
private function buildDependenciesWhereClause( | |||||
AphrontDatabaseConnection $conn) { | |||||
if (!$this->shouldJoinBlockedTasks() && | |||||
!$this->shouldJoinBlockingTasks()) { | |||||
return null; | |||||
} | |||||
$parts = array(); | |||||
if ($this->blockingTasks === true) { | |||||
$parts[] = qsprintf( | |||||
$conn, | |||||
'blocking.dst IS NOT NULL'); | |||||
} else if ($this->blockingTasks === false) { | |||||
$parts[] = qsprintf( | |||||
$conn, | |||||
'blocking.dst IS NULL'); | |||||
} | |||||
if ($this->blockedTasks === true) { | |||||
$parts[] = qsprintf( | |||||
$conn, | |||||
'blocked.dst IS NOT NULL'); | |||||
} else if ($this->blockedTasks === false) { | |||||
$parts[] = qsprintf( | |||||
$conn, | |||||
epriestley: Consider making these methods (`shouldJoinBlockingDependencies()`) instead of properties so… | |||||
'blocked.dst IS NULL'); | |||||
} | |||||
return '('.implode(') OR (', $parts).')'; | |||||
} | |||||
private function buildProjectWhereClause(AphrontDatabaseConnection $conn) { | private function buildProjectWhereClause(AphrontDatabaseConnection $conn) { | ||||
if (!$this->projectPHIDs && !$this->includeNoProject) { | if (!$this->projectPHIDs && !$this->includeNoProject) { | ||||
return null; | return null; | ||||
} | } | ||||
$parts = array(); | $parts = array(); | ||||
if ($this->projectPHIDs) { | if ($this->projectPHIDs) { | ||||
$parts[] = qsprintf( | $parts[] = qsprintf( | ||||
Show All 20 Lines | return qsprintf( | ||||
'anyproject.dst IN (%Ls)', | 'anyproject.dst IN (%Ls)', | ||||
$this->anyProjectPHIDs); | $this->anyProjectPHIDs); | ||||
} | } | ||||
private function buildAnyUserProjectWhereClause( | private function buildAnyUserProjectWhereClause( | ||||
AphrontDatabaseConnection $conn) { | AphrontDatabaseConnection $conn) { | ||||
if (!$this->anyUserProjectPHIDs) { | if (!$this->anyUserProjectPHIDs) { | ||||
return null; | return null; | ||||
} | } | ||||
Not Done Inline ActionsStray print_r(). epriestley: Stray `print_r()`. | |||||
$projects = id(new PhabricatorProjectQuery()) | $projects = id(new PhabricatorProjectQuery()) | ||||
->setViewer($this->getViewer()) | ->setViewer($this->getViewer()) | ||||
->withMemberPHIDs($this->anyUserProjectPHIDs) | ->withMemberPHIDs($this->anyUserProjectPHIDs) | ||||
->execute(); | ->execute(); | ||||
$any_user_project_phids = mpull($projects, 'getPHID'); | $any_user_project_phids = mpull($projects, 'getPHID'); | ||||
if (!$any_user_project_phids) { | if (!$any_user_project_phids) { | ||||
throw new PhabricatorEmptyQueryException(); | throw new PhabricatorEmptyQueryException(); | ||||
▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | if ($this->projectPHIDs || $this->includeNoProject) { | ||||
$conn_r, | $conn_r, | ||||
'%Q JOIN %T project ON project.src = task.phid | '%Q JOIN %T project ON project.src = task.phid | ||||
AND project.type = %d', | AND project.type = %d', | ||||
($this->includeNoProject ? 'LEFT' : ''), | ($this->includeNoProject ? 'LEFT' : ''), | ||||
$edge_table, | $edge_table, | ||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); | PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); | ||||
} | } | ||||
if ($this->shouldJoinBlockingTasks()) { | |||||
$joins[] = qsprintf( | |||||
$conn_r, | |||||
'LEFT JOIN %T blocking ON blocking.src = task.phid '. | |||||
'AND blocking.type = %d', | |||||
$edge_table, | |||||
ManiphestTaskDependedOnByTaskEdgeType::EDGECONST); | |||||
} | |||||
if ($this->shouldJoinBlockedTasks()) { | |||||
$joins[] = qsprintf( | |||||
$conn_r, | |||||
'LEFT JOIN %T blocked ON blocked.src = task.phid '. | |||||
'AND blocked.type = %d', | |||||
$edge_table, | |||||
ManiphestTaskDependsOnTaskEdgeType::EDGECONST); | |||||
} | |||||
if ($this->anyProjectPHIDs || $this->anyUserProjectPHIDs) { | if ($this->anyProjectPHIDs || $this->anyUserProjectPHIDs) { | ||||
$joins[] = qsprintf( | $joins[] = qsprintf( | ||||
$conn_r, | $conn_r, | ||||
'JOIN %T anyproject ON anyproject.src = task.phid | 'JOIN %T anyproject ON anyproject.src = task.phid | ||||
AND anyproject.type = %d', | AND anyproject.type = %d', | ||||
$edge_table, | $edge_table, | ||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); | PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | private function buildJoinsClause(AphrontDatabaseConnection $conn_r) { | ||||
} | } | ||||
$joins[] = $this->buildApplicationSearchJoinClause($conn_r); | $joins[] = $this->buildApplicationSearchJoinClause($conn_r); | ||||
return implode(' ', $joins); | return implode(' ', $joins); | ||||
} | } | ||||
private function buildGroupClause(AphrontDatabaseConnection $conn_r) { | private function buildGroupClause(AphrontDatabaseConnection $conn_r) { | ||||
$joined_multiple_rows = (count($this->projectPHIDs) > 1) || | $joined_multiple_rows = (count($this->projectPHIDs) > 1) || | ||||
(count($this->anyProjectPHIDs) > 1) || | (count($this->anyProjectPHIDs) > 1) || | ||||
$this->shouldJoinBlockingTasks() || | |||||
$this->shouldJoinBlockedTasks() || | |||||
($this->getApplicationSearchMayJoinMultipleRows()); | ($this->getApplicationSearchMayJoinMultipleRows()); | ||||
Not Done Inline ActionsThis needs to be updated for the row-matching joins, or we'll get the same tasks back multiple times if, e.g., a task has 50 dependencies. This likely shakes out correctly in the long run for tasks with fewer than 100 dependencies, but at the cost of efficiency (we incidentally de-duplicate in the client instead of in MySQL). epriestley: This needs to be updated for the row-matching joins, or we'll get the same tasks back multiple… | |||||
$joined_project_name = ($this->groupBy == self::GROUP_PROJECT); | $joined_project_name = ($this->groupBy == self::GROUP_PROJECT); | ||||
// If we're joining multiple rows, we need to group the results by the | // If we're joining multiple rows, we need to group the results by the | ||||
// task IDs. | // task IDs. | ||||
if ($joined_multiple_rows) { | if ($joined_multiple_rows) { | ||||
if ($joined_project_name) { | if ($joined_project_name) { | ||||
return 'GROUP BY task.phid, projectGroup.dst'; | return 'GROUP BY task.phid, projectGroup.dst'; | ||||
▲ Show 20 Lines • Show All 237 Lines • Show Last 20 Lines |
Consider making these methods (shouldJoinBlockingDependencies()) instead of properties so they're harder to misuse (e.g., it prevents them from being accessed before they are initialized, if this code gets moved around).