Changeset View
Changeset View
Standalone View
Standalone View
src/applications/project/engine/PhabricatorBoardLayoutEngine.php
Show First 20 Lines • Show All 314 Lines • ▼ Show 20 Lines | private function loadColumns(array $boards) { | ||||
$columns = id(new PhabricatorProjectColumnQuery()) | $columns = id(new PhabricatorProjectColumnQuery()) | ||||
->setViewer($viewer) | ->setViewer($viewer) | ||||
->withProjectPHIDs(array_keys($boards)) | ->withProjectPHIDs(array_keys($boards)) | ||||
->execute(); | ->execute(); | ||||
$columns = msort($columns, 'getSequence'); | $columns = msort($columns, 'getSequence'); | ||||
$columns = mpull($columns, null, 'getPHID'); | $columns = mpull($columns, null, 'getPHID'); | ||||
$this->columnMap = $columns; | $need_children = array(); | ||||
foreach ($boards as $phid => $board) { | |||||
if ($board->getHasMilestones() || $board->getHasSubprojects()) { | |||||
$need_children[] = $phid; | |||||
} | |||||
} | |||||
if ($need_children) { | |||||
$children = id(new PhabricatorProjectQuery()) | |||||
->setViewer($viewer) | |||||
->withParentProjectPHIDs($need_children) | |||||
->execute(); | |||||
$children = mpull($children, null, 'getPHID'); | |||||
$children = mgroup($children, 'getParentProjectPHID'); | |||||
} else { | |||||
$children = array(); | |||||
} | |||||
$columns = mgroup($columns, 'getProjectPHID'); | $columns = mgroup($columns, 'getProjectPHID'); | ||||
foreach ($boards as $board_phid => $board) { | |||||
$board_columns = idx($columns, $board_phid, array()); | |||||
// If the project has milestones, create any missing columns. | |||||
if ($board->getHasMilestones() || $board->getHasSubprojects()) { | |||||
$child_projects = idx($children, $board_phid, array()); | |||||
$next_sequence = last($board_columns)->getSequence() + 1; | |||||
$proxy_columns = mpull($board_columns, null, 'getProxyPHID'); | |||||
foreach ($child_projects as $child_phid => $child) { | |||||
if (isset($proxy_columns[$child_phid])) { | |||||
continue; | |||||
} | |||||
$new_column = PhabricatorProjectColumn::initializeNewColumn($viewer) | |||||
->attachProject($board) | |||||
->attachProxy($child) | |||||
->setSequence($next_sequence++) | |||||
->setProjectPHID($board_phid) | |||||
->setProxyPHID($child_phid); | |||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); | |||||
$new_column->save(); | |||||
unset($unguarded); | |||||
$board_columns[$new_column->getPHID()] = $new_column; | |||||
} | |||||
} | |||||
$columns[$board_phid] = $board_columns; | |||||
} | |||||
foreach ($columns as $board_phid => $board_columns) { | |||||
foreach ($board_columns as $board_column) { | |||||
$column_phid = $board_column->getPHID(); | |||||
$this->columnMap[$column_phid] = $board_column; | |||||
} | |||||
} | |||||
return $columns; | return $columns; | ||||
} | } | ||||
private function loadPositions(array $boards) { | private function loadPositions(array $boards) { | ||||
$viewer = $this->getViewer(); | $viewer = $this->getViewer(); | ||||
$object_phids = $this->getObjectPHIDs(); | $object_phids = $this->getObjectPHIDs(); | ||||
Show All 12 Lines | private function loadPositions(array $boards) { | ||||
return $positions; | return $positions; | ||||
} | } | ||||
private function layoutBoard( | private function layoutBoard( | ||||
$board, | $board, | ||||
array $columns, | array $columns, | ||||
array $positions) { | array $positions) { | ||||
$viewer = $this->getViewer(); | |||||
$board_phid = $board->getPHID(); | $board_phid = $board->getPHID(); | ||||
$position_groups = mgroup($positions, 'getObjectPHID'); | $position_groups = mgroup($positions, 'getObjectPHID'); | ||||
$layout = array(); | $layout = array(); | ||||
foreach ($columns as $column) { | foreach ($columns as $column) { | ||||
$column_phid = $column->getPHID(); | $column_phid = $column->getPHID(); | ||||
$layout[$column_phid] = array(); | $layout[$column_phid] = array(); | ||||
if ($column->isDefaultColumn()) { | if ($column->isDefaultColumn()) { | ||||
$default_phid = $column_phid; | $default_phid = $column_phid; | ||||
} | } | ||||
} | } | ||||
// Find all the columns which are proxies for other objects. | |||||
$proxy_map = array(); | |||||
foreach ($columns as $column) { | |||||
$proxy_phid = $column->getProxyPHID(); | |||||
if ($proxy_phid) { | |||||
$proxy_map[$proxy_phid] = $column->getPHID(); | |||||
} | |||||
} | |||||
$object_phids = $this->getObjectPHIDs(); | $object_phids = $this->getObjectPHIDs(); | ||||
// If we have proxies, we need to force cards into the correct proxy | |||||
// columns. | |||||
if ($proxy_map) { | |||||
$edge_query = id(new PhabricatorEdgeQuery()) | |||||
->withSourcePHIDs($object_phids) | |||||
->withEdgeTypes( | |||||
array( | |||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, | |||||
)); | |||||
$edge_query->execute(); | |||||
$project_phids = $edge_query->getDestinationPHIDs(); | |||||
$project_phids = array_fuse($project_phids); | |||||
} else { | |||||
$project_phids = array(); | |||||
} | |||||
if ($project_phids) { | |||||
$projects = id(new PhabricatorProjectQuery()) | |||||
->setViewer($viewer) | |||||
->withPHIDs($project_phids) | |||||
->execute(); | |||||
$projects = mpull($projects, null, 'getPHID'); | |||||
} else { | |||||
$projects = array(); | |||||
} | |||||
// Build a map from every project that any task is tagged with to the | |||||
// ancestor project which has a column on this board, if one exists. | |||||
$ancestor_map = array(); | |||||
foreach ($projects as $phid => $project) { | |||||
if (isset($proxy_map[$phid])) { | |||||
$ancestor_map[$phid] = $proxy_map[$phid]; | |||||
} else { | |||||
$seen = array($phid); | |||||
foreach ($project->getAncestorProjects() as $ancestor) { | |||||
$ancestor_phid = $ancestor->getPHID(); | |||||
$seen[] = $ancestor_phid; | |||||
if (isset($proxy_map[$ancestor_phid])) { | |||||
foreach ($seen as $project_phid) { | |||||
$ancestor_map[$project_phid] = $proxy_map[$ancestor_phid]; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
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. | // First, check for objects that have corresponding proxy columns. We're | ||||
// going to overwrite normal column positions if a tag belongs to a proxy | |||||
// column, since you can't be in normal columns if you're in proxy | |||||
// columns. | |||||
$proxy_hits = array(); | |||||
if ($proxy_map) { | |||||
$object_project_phids = $edge_query->getDestinationPHIDs( | |||||
array( | |||||
$object_phid, | |||||
)); | |||||
foreach ($object_project_phids as $project_phid) { | |||||
if (isset($ancestor_map[$project_phid])) { | |||||
$proxy_hits[] = $ancestor_map[$project_phid]; | |||||
} | |||||
} | |||||
} | |||||
if ($proxy_hits) { | |||||
// TODO: For now, only one column hit is permissible. | |||||
$proxy_hits = array_slice($proxy_hits, 0, 1); | |||||
$proxy_hits = array_fuse($proxy_hits); | |||||
// Check the object positions: we hope to find a position in each | |||||
// column the object should be part of. We're going to drop any | |||||
// invalid positions and create new positions where positions are | |||||
// missing. | |||||
foreach ($positions as $key => $position) { | |||||
$column_phid = $position->getColumnPHID(); | |||||
if (isset($proxy_hits[$column_phid])) { | |||||
// Valid column, mark the position as found. | |||||
unset($proxy_hits[$column_phid]); | |||||
} else { | |||||
// Invalid column, ignore the position. | |||||
unset($positions[$key]); | |||||
} | |||||
} | |||||
// Create new positions for anything we haven't found. | |||||
foreach ($proxy_hits as $proxy_hit) { | |||||
$new_position = id(new PhabricatorProjectColumnPosition()) | |||||
->setBoardPHID($board_phid) | |||||
->setColumnPHID($proxy_hit) | |||||
->setObjectPHID($object_phid) | |||||
->setSequence(0); | |||||
$this->addQueue[] = $new_position; | |||||
$positions[] = $new_position; | |||||
} | |||||
} else { | |||||
// Ignore any positions in columns which no longer exist. We don't | |||||
// actively destory them because the rest of the code ignores them and | |||||
// there's no real need to destroy the data. | |||||
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; | $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; | ||||
} | } | ||||
} | } | ||||
foreach ($layout as $column_phid => $map) { | foreach ($layout as $column_phid => $map) { | ||||
Show All 12 Lines |