1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-15 19:32:40 +01:00
phorge-phorge/src/applications/search/controller/PhabricatorSearchRelationshipController.php
epriestley 25cc90d632 Inch toward using ApplicationSearch to power related objects
Summary:
Ref T4788. Fixes T9232. This moves the "search for stuff to attach to this object" flow away from hard-coding and legacy constants and toward something more modular and flexible.

It also adds an "Edit Commits..." action to Maniphest, resolving T9232. The behavior of the search for commits isn't great right now, but it will improve once these use real ApplicationSearch.

Test Plan: Edited a tasks' related commits, mocks, tasks, etc.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4788, T9232

Differential Revision: https://secure.phabricator.com/D16189
2016-06-29 11:22:29 -07:00

177 lines
5.4 KiB
PHP

<?php
final class PhabricatorSearchRelationshipController
extends PhabricatorSearchBaseController {
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$object = $this->loadRelationshipObject();
if (!$object) {
return new Aphront404Response();
}
$relationship = $this->loadRelationship($object);
if (!$relationship) {
return new Aphront404Response();
}
$src_phid = $object->getPHID();
$edge_type = $relationship->getEdgeConstant();
$dst_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
$src_phid,
$edge_type);
$all_phids = $dst_phids;
$all_phids[] = $src_phid;
$handles = $viewer->loadHandles($all_phids);
$src_handle = $handles[$src_phid];
$done_uri = $src_handle->getURI();
$initial_phids = $dst_phids;
if ($request->isFormPost()) {
$phids = explode(';', $request->getStr('phids'));
$phids = array_filter($phids);
$phids = array_values($phids);
$initial_phids = $request->getStrList('initialPHIDs');
// Apply the changes as adds and removes relative to the original state
// of the object when the dialog was rendered so that two users adding
// relationships at the same time don't race and overwrite one another.
$add_phids = array_diff($phids, $initial_phids);
$rem_phids = array_diff($initial_phids, $phids);
if ($add_phids) {
$dst_objects = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withPHIDs($phids)
->setRaisePolicyExceptions(true)
->execute();
$dst_objects = mpull($dst_objects, null, 'getPHID');
} else {
$dst_objects = array();
}
try {
foreach ($add_phids as $add_phid) {
$dst_object = idx($dst_objects, $add_phid);
if (!$dst_object) {
throw new Exception(
pht(
'You can not create a relationship to object "%s" because '.
'the object does not exist or could not be loaded.',
$add_phid));
}
if (!$relationship->canRelateObjects($object, $dst_object)) {
throw new Exception(
pht(
'You can not create a relationship (of type "%s") to object '.
'"%s" because it is not the right type of object for this '.
'relationship.',
$relationship->getRelationshipConstant(),
$add_phid));
}
}
} catch (Exception $ex) {
return $this->newUnrelatableObjectResponse($ex, $done_uri);
}
$editor = $object->getApplicationTransactionEditor()
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnMissingFields(true)
->setContinueOnNoEffect(true);
$xactions = array();
$xactions[] = $object->getApplicationTransactionTemplate()
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue('edge:type', $edge_type)
->setNewValue(array(
'+' => array_fuse($add_phids),
'-' => array_fuse($rem_phids),
));
try {
$editor->applyTransactions($object, $xactions);
return id(new AphrontRedirectResponse())->setURI($done_uri);
} catch (PhabricatorEdgeCycleException $ex) {
return $this->newGraphCycleResponse($ex, $done_uri);
}
}
$handles = iterator_to_array($handles);
$handles = array_select_keys($handles, $dst_phids);
// TODO: These are hard-coded for now.
$filters = array(
'assigned' => pht('Assigned to Me'),
'created' => pht('Created By Me'),
'open' => pht('All Open Objects'),
'all' => pht('All Objects'),
);
$dialog_title = $relationship->getDialogTitleText();
$dialog_header = $relationship->getDialogHeaderText();
$dialog_button = $relationship->getDialogButtonText();
$dialog_instructions = $relationship->getDialogInstructionsText();
$source_uri = $relationship->getSourceURI($object);
return id(new PhabricatorObjectSelectorDialog())
->setUser($viewer)
->setInitialPHIDs($initial_phids)
->setHandles($handles)
->setFilters($filters)
->setSelectedFilter('created')
->setExcluded($src_phid)
->setCancelURI($done_uri)
->setSearchURI($source_uri)
->setTitle($dialog_title)
->setHeader($dialog_header)
->setButtonText($dialog_button)
->setInstructions($dialog_instructions)
->buildDialog();
}
private function newGraphCycleResponse(
PhabricatorEdgeCycleException $ex,
$done_uri) {
$viewer = $this->getViewer();
$cycle = $ex->getCycle();
$handles = $this->loadViewerHandles($cycle);
$names = array();
foreach ($cycle as $cycle_phid) {
$names[] = $handles[$cycle_phid]->getFullName();
}
$message = pht(
'You can not create that relationship because it would create a '.
'circular dependency:');
$list = implode(" \xE2\x86\x92 ", $names);
return $this->newDialog()
->setTitle(pht('Circular Dependency'))
->appendParagraph($message)
->appendParagraph($list)
->addCancelButton($done_uri);
}
private function newUnrelatableObjectResponse(Exception $ex, $done_uri) {
$message = $ex->getMessage();
return $this->newDialog()
->setTitle(pht('Invalid Relationship'))
->appendParagraph($message)
->addCancelButton($done_uri);
}
}