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 |