/** * Get priorities for moving a task before or after another task. */ public static function getAdjacentSubpriority(ManiphestTask $dst, $is_after, $allow_recursion = true) { $query = id(new ManiphestTaskQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->setOrder(ManiphestTaskQuery::ORDER_PRIORITY)->withPriorities(array($dst->getPriority()))->setLimit(1); if ($is_after) { $query->setAfterID($dst->getID()); } else { $query->setBeforeID($dst->getID()); } $adjacent = $query->executeOne(); $base = $dst->getSubpriority(); $step = (double) (2 << 32); // If we find an adjacent task, we average the two subpriorities and // return the result. if ($adjacent) { $epsilon = 0.01; // If the adjacent task has a subpriority that is identical or very // close to the task we're looking at, we're going to move it and all // tasks with the same subpriority a little farther down the subpriority // scale. if ($allow_recursion && abs($adjacent->getSubpriority() - $base) < $epsilon) { $conn_w = $adjacent->establishConnection('w'); $min = $adjacent->getSubpriority() - $epsilon; $max = $adjacent->getSubpriority() + $epsilon; // Get all of the tasks with the similar subpriorities to the adjacent // task, including the adjacent task itself. $query = id(new ManiphestTaskQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPriorities(array($adjacent->getPriority()))->withSubpriorityBetween($min, $max); if (!$is_after) { $query->setOrderVector(array('-priority', '-subpriority', '-id')); } else { $query->setOrderVector(array('priority', 'subpriority', 'id')); } $shift_all = $query->execute(); $shift_last = last($shift_all); // Select the most extreme subpriority in the result set as the // base value. $shift_base = head($shift_all)->getSubpriority(); // Find the subpriority before or after the task at the end of the // block. list($shift_pri, $shift_sub) = self::getAdjacentSubpriority($shift_last, $is_after, $allow_recursion = false); $delta = $shift_sub - $shift_base; $count = count($shift_all); $shift = array(); $cursor = 1; foreach ($shift_all as $shift_task) { $shift_target = $shift_base + $cursor / $count * $delta; $cursor++; queryfx($conn_w, 'UPDATE %T SET subpriority = %f WHERE id = %d', $adjacent->getTableName(), $shift_target, $shift_task->getID()); // If we're shifting the adjacent task, update it. if ($shift_task->getID() == $adjacent->getID()) { $adjacent->setSubpriority($shift_target); } // If we're shifting the original target task, update the base // subpriority. if ($shift_task->getID() == $dst->getID()) { $base = $shift_target; } } } $sub = ($adjacent->getSubpriority() + $base) / 2; } else { // Otherwise, we take a step away from the target's subpriority and // use that. if ($is_after) { $sub = $base - $step; } else { $sub = $base + $step; } } return array($dst->getPriority(), $sub); }
private function comparePriorityTo(ManiphestTask $other) { $upri = $this->getPriority(); $vpri = $other->getPriority(); if ($upri != $vpri) { return $upri - $vpri; } $usub = $this->getSubpriority(); $vsub = $other->getSubpriority(); if ($usub != $vsub) { return $usub - $vsub; } $uid = $this->getID(); $vid = $other->getID(); if ($uid != $vid) { return $uid - $vid; } return 0; }