Changeset View
Changeset View
Standalone View
Standalone View
src/applications/maniphest/editor/ManiphestTransactionEditor.php
| Show First 20 Lines • Show All 194 Lines • ▼ Show 20 Lines | switch ($xaction->getTransactionType()) { | ||||
| $new_phids = idx($xaction->getNewValue(), 'columnPHIDs', array()); | $new_phids = idx($xaction->getNewValue(), 'columnPHIDs', array()); | ||||
| if (count($new_phids) !== 1) { | if (count($new_phids) !== 1) { | ||||
| throw new Exception( | throw new Exception( | ||||
| pht( | pht( | ||||
| "Expected exactly one '%s' in column transaction.", | "Expected exactly one '%s' in column transaction.", | ||||
| 'columnPHIDs')); | 'columnPHIDs')); | ||||
| } | } | ||||
| $columns = id(new PhabricatorProjectColumnQuery()) | |||||
| ->setViewer($this->requireActor()) | |||||
| ->withPHIDs($new_phids) | |||||
| ->execute(); | |||||
| $columns = mpull($columns, null, 'getPHID'); | |||||
| $positions = id(new PhabricatorProjectColumnPositionQuery()) | |||||
| ->setViewer($this->requireActor()) | |||||
| ->withObjectPHIDs(array($object->getPHID())) | |||||
| ->withBoardPHIDs(array($board_phid)) | |||||
| ->execute(); | |||||
| $before_phid = idx($xaction->getNewValue(), 'beforePHID'); | $before_phid = idx($xaction->getNewValue(), 'beforePHID'); | ||||
| $after_phid = idx($xaction->getNewValue(), 'afterPHID'); | $after_phid = idx($xaction->getNewValue(), 'afterPHID'); | ||||
| if (!$before_phid && !$after_phid && ($old_phids == $new_phids)) { | if (!$before_phid && !$after_phid && ($old_phids == $new_phids)) { | ||||
| // If we are not moving the object between columns and also not | // If we are not moving the object between columns and also not | ||||
| // reordering the position, this is a move on some other order | // reordering the position, this is a move on some other order | ||||
| // (like priority). We can leave the positions untouched and just | // (like priority). We can leave the positions untouched and just | ||||
| // bail, there's no work to be done. | // bail, there's no work to be done. | ||||
| return; | return; | ||||
| } | } | ||||
| // Otherwise, we're either moving between columns or adjusting the | // Otherwise, we're either moving between columns or adjusting the | ||||
| // object's position in the "natural" ordering, so we do need to update | // object's position in the "natural" ordering, so we do need to update | ||||
| // some rows. | // some rows. | ||||
| // Remove all existing column positions on the board. | $object_phid = $object->getPHID(); | ||||
| foreach ($positions as $position) { | |||||
| $position->delete(); | |||||
| } | |||||
| // Add the new column positions. | |||||
| foreach ($new_phids as $phid) { | |||||
| $column = idx($columns, $phid); | |||||
| if (!$column) { | |||||
| throw new Exception( | |||||
| pht('No such column "%s" exists!', $phid)); | |||||
| } | |||||
| // Load the other object positions in the column. Note that we must | // We're doing layout with the ominpotent viewer to make sure we don't | ||||
| // skip implicit column creation to avoid generating a new position | // remove positions in columns that exist, but which the actual actor | ||||
| // if the target column is a backlog column. | // can't see. | ||||
| $omnipotent_viewer = PhabricatorUser::getOmnipotentUser(); | |||||
| $other_positions = id(new PhabricatorProjectColumnPositionQuery()) | |||||
| ->setViewer($this->requireActor()) | $board_tasks = id(new ManiphestTaskQuery()) | ||||
| ->withColumns(array($column)) | ->setViewer($omnipotent_viewer) | ||||
| ->withBoardPHIDs(array($board_phid)) | ->withEdgeLogicPHIDs( | ||||
| ->setSkipImplicitCreate(true) | PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, | ||||
| PhabricatorQueryConstraint::OPERATOR_AND, | |||||
| array($board_phid)) | |||||
| ->execute(); | ->execute(); | ||||
| $other_positions = msort($other_positions, 'getOrderingKey'); | |||||
| // Set up the new position object. We're going to figure out the | |||||
| // right sequence number and then persist this object with that | |||||
| // sequence number. | |||||
| $new_position = id(new PhabricatorProjectColumnPosition()) | |||||
| ->setBoardPHID($board_phid) | |||||
| ->setColumnPHID($column->getPHID()) | |||||
| ->setObjectPHID($object->getPHID()); | |||||
| $updates = array(); | |||||
| $sequence = 0; | |||||
| // If we're just dropping this into the column without any specific | $object_phids = mpull($board_tasks, 'getPHID'); | ||||
| // position information, put it at the top. | $object_phids[] = $object_phid; | ||||
| if (!$before_phid && !$after_phid) { | |||||
| $new_position->setSequence($sequence)->save(); | |||||
| $sequence++; | |||||
| } | |||||
| foreach ($other_positions as $position) { | |||||
| $object_phid = $position->getObjectPHID(); | |||||
| // If this is the object we're moving before and we haven't | $engine = id(new PhabricatorBoardLayoutEngine()) | ||||
| // saved yet, insert here. | ->setViewer($omnipotent_viewer) | ||||
| if (($before_phid == $object_phid) && !$new_position->getID()) { | ->setBoardPHIDs(array($board_phid)) | ||||
| $new_position->setSequence($sequence)->save(); | ->setObjectPHIDs($object_phids) | ||||
| $sequence++; | ->executeLayout(); | ||||
| // TODO: This logic needs to be revised if we legitimately support | |||||
| // multiple column positions. | |||||
| // NOTE: When a task is newly created, it's implicitly added to the | |||||
| // backlog but we don't currently record that in the "$old_phids". Just | |||||
| // clean it up for now. | |||||
| $columns = $engine->getObjectColumns($board_phid, $object_phid); | |||||
| foreach ($columns as $column) { | |||||
| $engine->queueRemovePosition( | |||||
| $board_phid, | |||||
| $column->getPHID(), | |||||
| $object_phid); | |||||
| } | } | ||||
| // This object goes here in the sequence; we might need to update | // Remove all existing column positions on the board. | ||||
| // the row. | foreach ($old_phids as $column_phid) { | ||||
| if ($sequence != $position->getSequence()) { | $engine->queueRemovePosition( | ||||
| $updates[$position->getID()] = $sequence; | $board_phid, | ||||
| } | $column_phid, | ||||
| $sequence++; | $object_phid); | ||||
| } | |||||
| // If this is the object we're moving after and we haven't saved | |||||
| // yet, insert here. | // Add new positions. | ||||
| if (($after_phid == $object_phid) && !$new_position->getID()) { | foreach ($new_phids as $column_phid) { | ||||
| $new_position->setSequence($sequence)->save(); | if ($before_phid) { | ||||
| $sequence++; | $engine->queueAddPositionBefore( | ||||
| } | $board_phid, | ||||
| $column_phid, | |||||
| $object_phid, | |||||
| $before_phid); | |||||
| } else if ($after_phid) { | |||||
| $engine->queueAddPositionAfter( | |||||
| $board_phid, | |||||
| $column_phid, | |||||
| $object_phid, | |||||
| $after_phid); | |||||
| } else { | |||||
| $engine->queueAddPosition( | |||||
| $board_phid, | |||||
| $column_phid, | |||||
| $object_phid); | |||||
| } | } | ||||
| // We should have found a place to put it. | |||||
| if (!$new_position->getID()) { | |||||
| throw new Exception( | |||||
| pht('Unable to find a place to insert object on column!')); | |||||
| } | } | ||||
| // If we changed other objects' column positions, bulk reorder them. | $engine->applyPositionUpdates(); | ||||
| if ($updates) { | |||||
| $position = new PhabricatorProjectColumnPosition(); | |||||
| $conn_w = $position->establishConnection('w'); | |||||
| $pairs = array(); | |||||
| foreach ($updates as $id => $sequence) { | |||||
| // This is ugly because MySQL gets upset with us if it is | |||||
| // configured strictly and we attempt inserts which can't work. | |||||
| // We'll never actually do these inserts since they'll always | |||||
| // collide (triggering the ON DUPLICATE KEY logic), so we just | |||||
| // provide dummy values in order to get there. | |||||
| $pairs[] = qsprintf( | |||||
| $conn_w, | |||||
| '(%d, %d, "", "", "")', | |||||
| $id, | |||||
| $sequence); | |||||
| } | |||||
| queryfx( | |||||
| $conn_w, | |||||
| 'INSERT INTO %T (id, sequence, boardPHID, columnPHID, objectPHID) | |||||
| VALUES %Q ON DUPLICATE KEY UPDATE sequence = VALUES(sequence)', | |||||
| $position->getTableName(), | |||||
| implode(', ', $pairs)); | |||||
| } | |||||
| } | |||||
| break; | break; | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| protected function applyFinalEffects( | protected function applyFinalEffects( | ||||
| PhabricatorLiskDAO $object, | PhabricatorLiskDAO $object, | ||||
| ▲ Show 20 Lines • Show All 640 Lines • Show Last 20 Lines | |||||