Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php
index 0bc186f94f..4e27479337 100644
--- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php
+++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php
@@ -1,425 +1,438 @@
<?php
final class ManiphestTaskDetailController extends ManiphestController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$id = $request->getURIData('id');
$task = id(new ManiphestTaskQuery())
->setViewer($viewer)
->withIDs(array($id))
->needSubscriberPHIDs(true)
->executeOne();
if (!$task) {
return new Aphront404Response();
}
$field_list = PhabricatorCustomField::getObjectFields(
$task,
PhabricatorCustomField::ROLE_VIEW);
$field_list
->setViewer($viewer)
->readFieldsFromStorage($task);
$edit_engine = id(new ManiphestEditEngine())
->setViewer($viewer)
->setTargetObject($task);
$e_commit = ManiphestTaskHasCommitEdgeType::EDGECONST;
$e_rev = ManiphestTaskHasRevisionEdgeType::EDGECONST;
$e_mock = ManiphestTaskHasMockEdgeType::EDGECONST;
$phid = $task->getPHID();
$query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(array($phid))
->withEdgeTypes(
array(
$e_commit,
$e_rev,
$e_mock,
));
$edges = idx($query->execute(), $phid);
$phids = array_fill_keys($query->getDestinationPHIDs(), true);
if ($task->getOwnerPHID()) {
$phids[$task->getOwnerPHID()] = true;
}
$phids[$task->getAuthorPHID()] = true;
$phids = array_keys($phids);
$handles = $viewer->loadHandles($phids);
$timeline = $this->buildTransactionTimeline(
$task,
new ManiphestTransactionQuery());
$monogram = $task->getMonogram();
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($monogram)
->setBorder(true);
$header = $this->buildHeaderView($task);
$details = $this->buildPropertyView($task, $field_list, $edges, $handles);
$description = $this->buildDescriptionView($task);
$curtain = $this->buildCurtain($task, $edit_engine);
$title = pht('%s %s', $monogram, $task->getTitle());
$comment_view = $edit_engine
->buildEditEngineCommentView($task);
$timeline->setQuoteRef($monogram);
$comment_view->setTransactionTimeline($timeline);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn(array(
$timeline,
$comment_view,
))
->addPropertySection(pht('Description'), $description)
->addPropertySection(pht('Details'), $details);
$graph_limit = 100;
$task_graph = id(new ManiphestTaskGraph())
->setViewer($viewer)
->setSeedPHID($task->getPHID())
->setLimit($graph_limit)
->loadGraph();
if (!$task_graph->isEmpty()) {
- if ($task_graph->isOverLimit()) {
+ $parent_type = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST;
+ $subtask_type = ManiphestTaskDependsOnTaskEdgeType::EDGECONST;
+ $parent_map = $task_graph->getEdges($parent_type);
+ $subtask_map = $task_graph->getEdges($subtask_type);
+ $parent_list = idx($parent_map, $task->getPHID(), array());
+ $subtask_list = idx($subtask_map, $task->getPHID(), array());
+ $has_parents = (bool)$parent_list;
+ $has_subtasks = (bool)$subtask_list;
+
+ $search_text = pht('Search...');
+
+ // First, get a count of direct parent tasks and subtasks. If there
+ // are too many of these, we just don't draw anything. You can use
+ // the search button to browse tasks with the search UI instead.
+ $direct_count = count($parent_list) + count($subtask_list);
+
+ if ($direct_count > $graph_limit) {
$message = pht(
- 'Task graph too large to display (this task is connected to '.
- 'more than %s other tasks).',
- $graph_limit);
+ 'Task graph too large to display (this task is directly connected '.
+ 'to more than %s other tasks). Use %s to explore connected tasks.',
+ $graph_limit,
+ phutil_tag('strong', array(), $search_text));
$message = phutil_tag('em', array(), $message);
$graph_table = id(new PHUIPropertyListView())
->addTextContent($message);
} else {
+ // If there aren't too many direct tasks, but there are too many total
+ // tasks, we'll only render directly connected tasks.
+ if ($task_graph->isOverLimit()) {
+ $task_graph->setRenderOnlyAdjacentNodes(true);
+ }
$graph_table = $task_graph->newGraphTable();
}
- $parent_type = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST;
- $subtask_type = ManiphestTaskDependsOnTaskEdgeType::EDGECONST;
-
- $parent_map = $task_graph->getEdges($parent_type);
- $subtask_map = $task_graph->getEdges($subtask_type);
-
- $has_parents = (bool)idx($parent_map, $task->getPHID());
- $has_subtasks = (bool)idx($subtask_map, $task->getPHID());
-
$parents_uri = urisprintf(
'/?subtaskIDs=%d#R',
$task->getID());
$parents_uri = $this->getApplicationURI($parents_uri);
$subtasks_uri = urisprintf(
'/?parentIDs=%d#R',
$task->getID());
$subtasks_uri = $this->getApplicationURI($subtasks_uri);
$dropdown_menu = id(new PhabricatorActionListView())
->setViewer($viewer)
->addAction(
id(new PhabricatorActionView())
->setHref($parents_uri)
->setName(pht('Search Parent Tasks'))
->setDisabled(!$has_parents)
->setIcon('fa-chevron-circle-up'))
->addAction(
id(new PhabricatorActionView())
->setHref($subtasks_uri)
->setName(pht('Search Subtasks'))
->setDisabled(!$has_subtasks)
->setIcon('fa-chevron-circle-down'));
$graph_menu = id(new PHUIButtonView())
->setTag('a')
->setIcon('fa-search')
- ->setText(pht('Search...'))
+ ->setText($search_text)
->setDropdownMenu($dropdown_menu);
$graph_header = id(new PHUIHeaderView())
->setHeader(pht('Task Graph'))
->addActionLink($graph_menu);
$view->addPropertySection($graph_header, $graph_table);
}
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->setPageObjectPHIDs(
array(
$task->getPHID(),
))
->appendChild(
array(
$view,
));
}
private function buildHeaderView(ManiphestTask $task) {
$view = id(new PHUIHeaderView())
->setHeader($task->getTitle())
->setUser($this->getRequest()->getUser())
->setPolicyObject($task);
$priority_name = ManiphestTaskPriority::getTaskPriorityName(
$task->getPriority());
$priority_color = ManiphestTaskPriority::getTaskPriorityColor(
$task->getPriority());
$status = $task->getStatus();
$status_name = ManiphestTaskStatus::renderFullDescription(
$status, $priority_name, $priority_color);
$view->addProperty(PHUIHeaderView::PROPERTY_STATUS, $status_name);
$view->setHeaderIcon(ManiphestTaskStatus::getStatusIcon(
$task->getStatus()).' '.$priority_color);
if (ManiphestTaskPoints::getIsEnabled()) {
$points = $task->getPoints();
if ($points !== null) {
$points_name = pht('%s %s',
$task->getPoints(),
ManiphestTaskPoints::getPointsLabel());
$tag = id(new PHUITagView())
->setName($points_name)
->setShade('blue')
->setType(PHUITagView::TYPE_SHADE);
$view->addTag($tag);
}
}
return $view;
}
private function buildCurtain(
ManiphestTask $task,
PhabricatorEditEngine $edit_engine) {
$viewer = $this->getViewer();
$id = $task->getID();
$phid = $task->getPHID();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$task,
PhabricatorPolicyCapability::CAN_EDIT);
$curtain = $this->newCurtainView($task);
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Task'))
->setIcon('fa-pencil')
->setHref($this->getApplicationURI("/task/edit/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
$edit_config = $edit_engine->loadDefaultEditConfiguration();
$can_create = (bool)$edit_config;
$can_reassign = $edit_engine->hasEditAccessToTransaction(
ManiphestTransaction::TYPE_OWNER);
if ($can_create) {
$form_key = $edit_config->getIdentifier();
$edit_uri = id(new PhutilURI("/task/edit/form/{$form_key}/"))
->setQueryParam('parent', $id)
->setQueryParam('template', $id)
->setQueryParam('status', ManiphestTaskStatus::getDefaultStatus());
$edit_uri = $this->getApplicationURI($edit_uri);
} else {
// TODO: This will usually give us a somewhat-reasonable error page, but
// could be a bit cleaner.
$edit_uri = "/task/edit/{$id}/";
$edit_uri = $this->getApplicationURI($edit_uri);
}
$subtask_item = id(new PhabricatorActionView())
->setName(pht('Create Subtask'))
->setHref($edit_uri)
->setIcon('fa-level-down')
->setDisabled(!$can_create)
->setWorkflow(!$can_create);
$relationship_list = PhabricatorObjectRelationshipList::newForObject(
$viewer,
$task);
$submenu_actions = array(
$subtask_item,
ManiphestTaskHasParentRelationship::RELATIONSHIPKEY,
ManiphestTaskHasSubtaskRelationship::RELATIONSHIPKEY,
ManiphestTaskMergeInRelationship::RELATIONSHIPKEY,
ManiphestTaskCloseAsDuplicateRelationship::RELATIONSHIPKEY,
);
$task_submenu = $relationship_list->newActionSubmenu($submenu_actions)
->setName(pht('Edit Related Tasks...'))
->setIcon('fa-anchor');
$curtain->addAction($task_submenu);
$relationship_submenu = $relationship_list->newActionMenu();
if ($relationship_submenu) {
$curtain->addAction($relationship_submenu);
}
$owner_phid = $task->getOwnerPHID();
$author_phid = $task->getAuthorPHID();
$handles = $viewer->loadHandles(array($owner_phid, $author_phid));
if ($owner_phid) {
$image_uri = $handles[$owner_phid]->getImageURI();
$image_href = $handles[$owner_phid]->getURI();
$owner = $viewer->renderHandle($owner_phid)->render();
$content = phutil_tag('strong', array(), $owner);
$assigned_to = id(new PHUIHeadThingView())
->setImage($image_uri)
->setImageHref($image_href)
->setContent($content);
} else {
$assigned_to = phutil_tag('em', array(), pht('None'));
}
$curtain->newPanel()
->setHeaderText(pht('Assigned To'))
->appendChild($assigned_to);
$author_uri = $handles[$author_phid]->getImageURI();
$author_href = $handles[$author_phid]->getURI();
$author = $viewer->renderHandle($author_phid)->render();
$content = phutil_tag('strong', array(), $author);
$date = phabricator_date($task->getDateCreated(), $viewer);
$content = pht('%s, %s', $content, $date);
$authored_by = id(new PHUIHeadThingView())
->setImage($author_uri)
->setImageHref($author_href)
->setContent($content);
$curtain->newPanel()
->setHeaderText(pht('Authored By'))
->appendChild($authored_by);
return $curtain;
}
private function buildPropertyView(
ManiphestTask $task,
PhabricatorCustomFieldList $field_list,
array $edges,
$handles) {
$viewer = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer);
$source = $task->getOriginalEmailSource();
if ($source) {
$subject = '[T'.$task->getID().'] '.$task->getTitle();
$view->addProperty(
pht('From Email'),
phutil_tag(
'a',
array(
'href' => 'mailto:'.$source.'?subject='.$subject,
),
$source));
}
$edge_types = array(
ManiphestTaskHasRevisionEdgeType::EDGECONST
=> pht('Differential Revisions'),
ManiphestTaskHasMockEdgeType::EDGECONST
=> pht('Pholio Mocks'),
);
$revisions_commits = array();
$commit_phids = array_keys(
$edges[ManiphestTaskHasCommitEdgeType::EDGECONST]);
if ($commit_phids) {
$commit_drev = DiffusionCommitHasRevisionEdgeType::EDGECONST;
$drev_edges = id(new PhabricatorEdgeQuery())
->withSourcePHIDs($commit_phids)
->withEdgeTypes(array($commit_drev))
->execute();
foreach ($commit_phids as $phid) {
$revisions_commits[$phid] = $handles->renderHandle($phid)
->setShowHovercard(true);
$revision_phid = key($drev_edges[$phid][$commit_drev]);
$revision_handle = $handles->getHandleIfExists($revision_phid);
if ($revision_handle) {
$task_drev = ManiphestTaskHasRevisionEdgeType::EDGECONST;
unset($edges[$task_drev][$revision_phid]);
$revisions_commits[$phid] = hsprintf(
'%s / %s',
$revision_handle->renderHovercardLink($revision_handle->getName()),
$revisions_commits[$phid]);
}
}
}
foreach ($edge_types as $edge_type => $edge_name) {
if ($edges[$edge_type]) {
$edge_handles = $viewer->loadHandles(array_keys($edges[$edge_type]));
$view->addProperty(
$edge_name,
$edge_handles->renderList());
}
}
if ($revisions_commits) {
$view->addProperty(
pht('Commits'),
phutil_implode_html(phutil_tag('br'), $revisions_commits));
}
$field_list->appendFieldsToPropertyList(
$task,
$viewer,
$view);
if ($view->hasAnyProperties()) {
return $view;
}
return null;
}
private function buildDescriptionView(ManiphestTask $task) {
$viewer = $this->getViewer();
$section = null;
$description = $task->getDescription();
if (strlen($description)) {
$section = new PHUIPropertyListView();
$section->addTextContent(
phutil_tag(
'div',
array(
'class' => 'phabricator-remarkup',
),
id(new PHUIRemarkupView($viewer, $description))
->setContextObject($task)));
}
return $section;
}
}
diff --git a/src/infrastructure/graph/ManiphestTaskGraph.php b/src/infrastructure/graph/ManiphestTaskGraph.php
index f2f8f8843d..53727b3779 100644
--- a/src/infrastructure/graph/ManiphestTaskGraph.php
+++ b/src/infrastructure/graph/ManiphestTaskGraph.php
@@ -1,151 +1,163 @@
<?php
final class ManiphestTaskGraph
extends PhabricatorObjectGraph {
private $seedMaps = array();
protected function getEdgeTypes() {
return array(
ManiphestTaskDependedOnByTaskEdgeType::EDGECONST,
ManiphestTaskDependsOnTaskEdgeType::EDGECONST,
);
}
protected function getParentEdgeType() {
return ManiphestTaskDependsOnTaskEdgeType::EDGECONST;
}
protected function newQuery() {
return new ManiphestTaskQuery();
}
protected function isClosed($object) {
return $object->isClosed();
}
protected function newTableRow($phid, $object, $trace) {
$viewer = $this->getViewer();
if ($object) {
$status = $object->getStatus();
$priority = $object->getPriority();
$status_icon = ManiphestTaskStatus::getStatusIcon($status);
$status_name = ManiphestTaskStatus::getTaskStatusName($status);
$priority_color = ManiphestTaskPriority::getTaskPriorityColor($priority);
if ($object->isClosed()) {
$priority_color = 'grey';
}
$status = array(
id(new PHUIIconView())->setIcon($status_icon, $priority_color),
' ',
$status_name,
);
$owner_phid = $object->getOwnerPHID();
if ($owner_phid) {
$assigned = $viewer->renderHandle($owner_phid);
} else {
$assigned = phutil_tag('em', array(), pht('None'));
}
$link = phutil_tag(
'a',
array(
'href' => $object->getURI(),
),
$object->getTitle());
$link = array(
phutil_tag(
'span',
array(
'class' => 'object-name',
),
$object->getMonogram()),
' ',
$link,
);
} else {
$status = null;
$assigned = null;
$link = $viewer->renderHandle($phid);
}
if ($this->isParentTask($object)) {
$marker = 'fa-chevron-circle-up bluegrey';
$marker_tip = pht('Direct Parent');
} else if ($this->isChildTask($object)) {
$marker = 'fa-chevron-circle-down bluegrey';
$marker_tip = pht('Direct Subtask');
} else {
$marker = null;
}
if ($marker) {
$marker = id(new PHUIIconView())
->setIcon($marker)
->addSigil('has-tooltip')
->setMetadata(
array(
'tip' => $marker_tip,
'align' => 'E',
));
}
$link = AphrontTableView::renderSingleDisplayLine($link);
return array(
$marker,
$trace,
$status,
$assigned,
$link,
);
}
protected function newTable(AphrontTableView $table) {
return $table
->setHeaders(
array(
null,
null,
pht('Status'),
pht('Assigned'),
pht('Task'),
))
->setColumnClasses(
array(
'nudgeright',
'threads',
'graph-status',
null,
'wide pri object-link',
));
}
private function isParentTask(ManiphestTask $task) {
$map = $this->getSeedMap(ManiphestTaskDependedOnByTaskEdgeType::EDGECONST);
return isset($map[$task->getPHID()]);
}
private function isChildTask(ManiphestTask $task) {
$map = $this->getSeedMap(ManiphestTaskDependsOnTaskEdgeType::EDGECONST);
return isset($map[$task->getPHID()]);
}
private function getSeedMap($type) {
if (!isset($this->seedMaps[$type])) {
$maps = $this->getEdges($type);
$phids = idx($maps, $this->getSeedPHID(), array());
$phids = array_fuse($phids);
$this->seedMaps[$type] = $phids;
}
return $this->seedMaps[$type];
}
+
+ protected function newEllipsisRow() {
+ return array(
+ null,
+ null,
+ null,
+ null,
+ pht("\xC2\xB7 \xC2\xB7 \xC2\xB7"),
+ );
+ }
+
+
}
diff --git a/src/infrastructure/graph/PhabricatorObjectGraph.php b/src/infrastructure/graph/PhabricatorObjectGraph.php
index 0e8cd7e906..48e0fcbe73 100644
--- a/src/infrastructure/graph/PhabricatorObjectGraph.php
+++ b/src/infrastructure/graph/PhabricatorObjectGraph.php
@@ -1,233 +1,286 @@
<?php
abstract class PhabricatorObjectGraph
extends AbstractDirectedGraph {
private $viewer;
private $edges = array();
private $edgeReach = array();
private $seedPHID;
private $objects;
private $loadEntireGraph = false;
private $limit;
+ private $adjacent;
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
public function getViewer() {
if (!$this->viewer) {
throw new PhutilInvalidStateException('setViewer');
}
return $this->viewer;
}
public function setLimit($limit) {
$this->limit = $limit;
return $this;
}
public function getLimit() {
return $this->limit;
}
+ final public function setRenderOnlyAdjacentNodes($adjacent) {
+ $this->adjacent = $adjacent;
+ return $this;
+ }
+
+ final public function getRenderOnlyAdjacentNodes() {
+ return $this->adjacent;
+ }
+
abstract protected function getEdgeTypes();
abstract protected function getParentEdgeType();
abstract protected function newQuery();
abstract protected function newTableRow($phid, $object, $trace);
abstract protected function newTable(AphrontTableView $table);
abstract protected function isClosed($object);
+ protected function newEllipsisRow() {
+ return array(
+ '...',
+ );
+ }
+
final public function setSeedPHID($phid) {
$this->seedPHID = $phid;
$this->edgeReach[$phid] = array_fill_keys($this->getEdgeTypes(), true);
return $this->addNodes(
array(
'<seed>' => array($phid),
));
}
final public function getSeedPHID() {
return $this->seedPHID;
}
final public function isEmpty() {
return (count($this->getNodes()) <= 2);
}
final public function isOverLimit() {
$limit = $this->getLimit();
if (!$limit) {
return false;
}
return (count($this->edgeReach) > $limit);
}
final public function getEdges($type) {
$edges = idx($this->edges, $type, array());
// Remove any nodes which we never reached. We can get these when loading
// only part of the graph: for example, they point at other subtasks of
// parents or other parents of subtasks.
$nodes = $this->getNodes();
foreach ($edges as $src => $dsts) {
foreach ($dsts as $key => $dst) {
if (!isset($nodes[$dst])) {
unset($edges[$src][$key]);
}
}
}
return $edges;
}
final public function setLoadEntireGraph($load_entire_graph) {
$this->loadEntireGraph = $load_entire_graph;
return $this;
}
final public function getLoadEntireGraph() {
return $this->loadEntireGraph;
}
final protected function loadEdges(array $nodes) {
if ($this->isOverLimit()) {
return array_fill_keys($nodes, array());
}
$edge_types = $this->getEdgeTypes();
$query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs($nodes)
->withEdgeTypes($edge_types);
$query->execute();
$whole_graph = $this->getLoadEntireGraph();
$map = array();
foreach ($nodes as $node) {
$map[$node] = array();
foreach ($edge_types as $edge_type) {
$dst_phids = $query->getDestinationPHIDs(
array($node),
array($edge_type));
$this->edges[$edge_type][$node] = $dst_phids;
foreach ($dst_phids as $dst_phid) {
if ($whole_graph || isset($this->edgeReach[$node][$edge_type])) {
$map[$node][] = $dst_phid;
}
$this->edgeReach[$dst_phid][$edge_type] = true;
}
}
$map[$node] = array_values(array_fuse($map[$node]));
}
return $map;
}
final public function newGraphTable() {
$viewer = $this->getViewer();
$ancestry = $this->getEdges($this->getParentEdgeType());
+ $only_adjacent = $this->getRenderOnlyAdjacentNodes();
+ if ($only_adjacent) {
+ $adjacent = array(
+ $this->getSeedPHID() => $this->getSeedPHID(),
+ );
+
+ foreach ($this->getEdgeTypes() as $edge_type) {
+ $map = $this->getEdges($edge_type);
+ $direct = idx($map, $this->getSeedPHID(), array());
+ $adjacent += array_fuse($direct);
+ }
+
+ foreach ($ancestry as $key => $list) {
+ if (!isset($adjacent[$key])) {
+ unset($ancestry[$key]);
+ continue;
+ }
+
+ foreach ($list as $list_key => $item) {
+ if (!isset($adjacent[$item])) {
+ unset($ancestry[$key][$list_key]);
+ }
+ }
+ }
+ }
+
$objects = $this->newQuery()
->setViewer($viewer)
->withPHIDs(array_keys($ancestry))
->execute();
$objects = mpull($objects, null, 'getPHID');
$order = id(new PhutilDirectedScalarGraph())
->addNodes($ancestry)
->getTopographicallySortedNodes();
$ancestry = array_select_keys($ancestry, $order);
$traces = id(new PHUIDiffGraphView())
->renderGraph($ancestry);
$ii = 0;
$rows = array();
$rowc = array();
+
+ if ($only_adjacent) {
+ $rows[] = $this->newEllipsisRow();
+ $rowc[] = 'more';
+ }
+
foreach ($ancestry as $phid => $ignored) {
$object = idx($objects, $phid);
$rows[] = $this->newTableRow($phid, $object, $traces[$ii++]);
$classes = array();
if ($phid == $this->seedPHID) {
$classes[] = 'highlighted';
}
if ($object) {
if ($this->isClosed($object)) {
$classes[] = 'closed';
}
}
if ($classes) {
$classes = implode(' ', $classes);
} else {
$classes = null;
}
$rowc[] = $classes;
}
+ if ($only_adjacent) {
+ $rows[] = $this->newEllipsisRow();
+ $rowc[] = 'more';
+ }
+
$table = id(new AphrontTableView($rows))
->setClassName('object-graph-table')
->setRowClasses($rowc);
$this->objects = $objects;
return $this->newTable($table);
}
final public function getReachableObjects($edge_type) {
if ($this->objects === null) {
throw new PhutilInvalidStateException('newGraphTable');
}
$graph = $this->getEdges($edge_type);
$seen = array();
$look = array($this->seedPHID);
while ($look) {
$phid = array_pop($look);
$parents = idx($graph, $phid, array());
foreach ($parents as $parent) {
if (isset($seen[$parent])) {
continue;
}
$seen[$parent] = $parent;
$look[] = $parent;
}
}
$reachable = array();
foreach ($seen as $phid) {
if ($phid == $this->seedPHID) {
continue;
}
$object = idx($this->objects, $phid);
if (!$object) {
continue;
}
$reachable[] = $object;
}
return $reachable;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Jun 11, 12:49 AM (1 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
141523
Default Alt Text
(25 KB)

Event Timeline