Changeset View
Changeset View
Standalone View
Standalone View
src/applications/project/engine/PhabricatorBoardLayoutEngine.php
<?php | <?php | ||||
final class PhabricatorBoardLayoutEngine extends Phobject { | final class PhabricatorBoardLayoutEngine extends Phobject { | ||||
private $viewer; | private $viewer; | ||||
private $boardPHIDs; | private $boardPHIDs; | ||||
private $objectPHIDs; | private $objectPHIDs; | ||||
private $boards; | private $boards; | ||||
private $columnMap; | private $columnMap; | ||||
private $objectColumnMap = array(); | private $objectColumnMap = array(); | ||||
private $boardLayout = array(); | private $boardLayout = array(); | ||||
private $remQueue = array(); | |||||
private $addQueue = array(); | |||||
public function setViewer(PhabricatorUser $viewer) { | public function setViewer(PhabricatorUser $viewer) { | ||||
$this->viewer = $viewer; | $this->viewer = $viewer; | ||||
return $this; | return $this; | ||||
} | } | ||||
public function getViewer() { | public function getViewer() { | ||||
return $this->viewer; | return $this->viewer; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | public function getObjectColumns($board_phid, $object_phid) { | ||||
$column_phids = idx($board_map, $object_phid); | $column_phids = idx($board_map, $object_phid); | ||||
if (!$column_phids) { | if (!$column_phids) { | ||||
return array(); | return array(); | ||||
} | } | ||||
return array_select_keys($this->columnMap, $column_phids); | return array_select_keys($this->columnMap, $column_phids); | ||||
} | } | ||||
public function queueRemovePosition( | |||||
$board_phid, | |||||
$column_phid, | |||||
$object_phid) { | |||||
$board_layout = idx($this->boardLayout, $board_phid, array()); | |||||
$positions = idx($board_layout, $column_phid, array()); | |||||
$position = idx($positions, $object_phid); | |||||
if ($position) { | |||||
$this->remQueue[] = $position; | |||||
// If this position hasn't been saved yet, get it out of the add queue. | |||||
if (!$position->getID()) { | |||||
foreach ($this->addQueue as $key => $add_position) { | |||||
if ($add_position === $position) { | |||||
unset($this->addQueue[$key]); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
unset($this->boardLayout[$board_phid][$column_phid][$object_phid]); | |||||
return $this; | |||||
} | |||||
public function queueAddPositionBefore( | |||||
$board_phid, | |||||
$column_phid, | |||||
$object_phid, | |||||
$before_phid) { | |||||
return $this->queueAddPositionRelative( | |||||
$board_phid, | |||||
$column_phid, | |||||
$object_phid, | |||||
$before_phid, | |||||
true); | |||||
} | |||||
public function queueAddPositionAfter( | |||||
$board_phid, | |||||
$column_phid, | |||||
$object_phid, | |||||
$after_phid) { | |||||
return $this->queueAddPositionRelative( | |||||
$board_phid, | |||||
$column_phid, | |||||
$object_phid, | |||||
$after_phid, | |||||
false); | |||||
} | |||||
public function queueAddPosition( | |||||
$board_phid, | |||||
$column_phid, | |||||
$object_phid) { | |||||
return $this->queueAddPositionRelative( | |||||
$board_phid, | |||||
$column_phid, | |||||
$object_phid, | |||||
null, | |||||
true); | |||||
} | |||||
private function queueAddPositionRelative( | |||||
$board_phid, | |||||
$column_phid, | |||||
$object_phid, | |||||
$relative_phid, | |||||
$is_before) { | |||||
$board_layout = idx($this->boardLayout, $board_phid, array()); | |||||
$positions = idx($board_layout, $column_phid, array()); | |||||
// Check if the object is already in the column, and remove it if it is. | |||||
$object_position = idx($positions, $object_phid); | |||||
unset($positions[$object_phid]); | |||||
if (!$object_position) { | |||||
$object_position = id(new PhabricatorProjectColumnPosition()) | |||||
->setBoardPHID($board_phid) | |||||
->setColumnPHID($column_phid) | |||||
->setObjectPHID($object_phid); | |||||
} | |||||
$found = false; | |||||
if (!$positions) { | |||||
$object_position->setSequence(0); | |||||
} else { | |||||
foreach ($positions as $position) { | |||||
if (!$found) { | |||||
if ($relative_phid === null) { | |||||
$is_match = true; | |||||
} else { | |||||
$position_phid = $position->getObjectPHID(); | |||||
$is_match = ($relative_phid == $position_phid); | |||||
} | |||||
if ($is_match) { | |||||
$found = true; | |||||
$sequence = $position->getSequence(); | |||||
if (!$is_before) { | |||||
$sequence++; | |||||
} | |||||
$object_position->setSequence($sequence++); | |||||
if (!$is_before) { | |||||
// If we're inserting after this position, continue the loop so | |||||
// we don't update it. | |||||
continue; | |||||
} | |||||
} | |||||
} | |||||
if ($found) { | |||||
$position->setSequence($sequence++); | |||||
$this->addQueue[] = $position; | |||||
} | |||||
} | |||||
} | |||||
if ($relative_phid && !$found) { | |||||
throw new Exception( | |||||
pht( | |||||
'Unable to find object "%s" in column "%s" on board "%s".', | |||||
$relative_phid, | |||||
$column_phid, | |||||
$board_phid)); | |||||
} | |||||
$this->addQueue[] = $object_position; | |||||
$positions[$object_phid] = $object_position; | |||||
$positions = msort($positions, 'getOrderingKey'); | |||||
$this->boardLayout[$board_phid][$column_phid] = $positions; | |||||
return $this; | |||||
} | |||||
public function applyPositionUpdates() { | |||||
foreach ($this->remQueue as $position) { | |||||
if ($position->getID()) { | |||||
$position->delete(); | |||||
} | |||||
} | |||||
$this->remQueue = array(); | |||||
$adds = array(); | |||||
$updates = array(); | |||||
foreach ($this->addQueue as $position) { | |||||
$id = $position->getID(); | |||||
if ($id) { | |||||
$updates[$id] = $position; | |||||
} else { | |||||
$adds[] = $position; | |||||
} | |||||
} | |||||
$this->addQueue = array(); | |||||
$table = new PhabricatorProjectColumnPosition(); | |||||
$conn_w = $table->establishConnection('w'); | |||||
$pairs = array(); | |||||
foreach ($updates as $id => $position) { | |||||
// 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, | |||||
$position->getSequence()); | |||||
} | |||||
if ($pairs) { | |||||
queryfx( | |||||
$conn_w, | |||||
'INSERT INTO %T (id, sequence, boardPHID, columnPHID, objectPHID) | |||||
VALUES %Q ON DUPLICATE KEY UPDATE sequence = VALUES(sequence)', | |||||
$table->getTableName(), | |||||
implode(', ', $pairs)); | |||||
} | |||||
foreach ($adds as $position) { | |||||
$position->save(); | |||||
} | |||||
return $this; | |||||
} | |||||
private function loadBoards() { | private function loadBoards() { | ||||
$viewer = $this->getViewer(); | $viewer = $this->getViewer(); | ||||
$board_phids = $this->getBoardPHIDs(); | $board_phids = $this->getBoardPHIDs(); | ||||
$boards = id(new PhabricatorObjectQuery()) | $boards = id(new PhabricatorObjectQuery()) | ||||
->setViewer($viewer) | ->setViewer($viewer) | ||||
->withPHIDs($board_phids) | ->withPHIDs($board_phids) | ||||
->execute(); | ->execute(); | ||||
Show All 22 Lines | private function loadColumns(array $boards) { | ||||
$columns = mgroup($columns, 'getProjectPHID'); | $columns = mgroup($columns, 'getProjectPHID'); | ||||
return $columns; | return $columns; | ||||
} | } | ||||
private function loadPositions(array $boards) { | private function loadPositions(array $boards) { | ||||
$viewer = $this->getViewer(); | $viewer = $this->getViewer(); | ||||
$object_phids = $this->getObjectPHIDs(); | |||||
if (!$object_phids) { | |||||
return array(); | |||||
} | |||||
$positions = id(new PhabricatorProjectColumnPositionQuery()) | $positions = id(new PhabricatorProjectColumnPositionQuery()) | ||||
->setViewer($viewer) | ->setViewer($viewer) | ||||
->withBoardPHIDs(array_keys($boards)) | ->withBoardPHIDs(array_keys($boards)) | ||||
->withObjectPHIDs($this->getObjectPHIDs()) | ->withObjectPHIDs($object_phids) | ||||
->execute(); | ->execute(); | ||||
$positions = msort($positions, 'getOrderingKey'); | $positions = msort($positions, 'getOrderingKey'); | ||||
$positions = mgroup($positions, 'getBoardPHID'); | $positions = mgroup($positions, 'getBoardPHID'); | ||||
return $positions; | return $positions; | ||||
} | } | ||||
private function layoutBoard( | private function layoutBoard( | ||||
Show All 16 Lines | private function layoutBoard( | ||||
$object_phids = $this->getObjectPHIDs(); | $object_phids = $this->getObjectPHIDs(); | ||||
foreach ($object_phids as $object_phid) { | foreach ($object_phids as $object_phid) { | ||||
$positions = idx($position_groups, $object_phid, array()); | $positions = idx($position_groups, $object_phid, array()); | ||||
// Remove any positions in columns which no longer exist. | // Remove any positions in columns which no longer exist. | ||||
foreach ($positions as $key => $position) { | foreach ($positions as $key => $position) { | ||||
$column_phid = $position->getColumnPHID(); | $column_phid = $position->getColumnPHID(); | ||||
if (empty($columns[$column_phid])) { | if (empty($columns[$column_phid])) { | ||||
$this->remQueue[] = $position; | |||||
unset($positions[$key]); | unset($positions[$key]); | ||||
} | } | ||||
} | } | ||||
// If the object has no position, put it on the default column. | // If the object has no position, put it on the default column. | ||||
if (!$positions) { | if (!$positions) { | ||||
$new_position = id(new PhabricatorProjectColumnPosition()) | $new_position = id(new PhabricatorProjectColumnPosition()) | ||||
->setBoardPHID($board_phid) | ->setBoardPHID($board_phid) | ||||
->setColumnPHID($default_phid) | ->setColumnPHID($default_phid) | ||||
->setObjectPHID($object_phid) | ->setObjectPHID($object_phid) | ||||
->setSequence(0); | ->setSequence(0); | ||||
$this->addQueue[] = $new_position; | |||||
$positions = array( | $positions = array( | ||||
$new_position, | $new_position, | ||||
); | ); | ||||
} | } | ||||
foreach ($positions as $position) { | foreach ($positions as $position) { | ||||
$column_phid = $position->getColumnPHID(); | $column_phid = $position->getColumnPHID(); | ||||
$layout[$column_phid][$object_phid] = $position; | $layout[$column_phid][$object_phid] = $position; | ||||
Show All 16 Lines |