Page MenuHomePhabricator

D16163.diff
No OneTemporary

D16163.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -3394,6 +3394,7 @@
'PhabricatorSearchOrderController' => 'applications/search/controller/PhabricatorSearchOrderController.php',
'PhabricatorSearchOrderField' => 'applications/search/field/PhabricatorSearchOrderField.php',
'PhabricatorSearchRelationship' => 'applications/search/constants/PhabricatorSearchRelationship.php',
+ 'PhabricatorSearchRelationshipController' => 'applications/search/controller/PhabricatorSearchRelationshipController.php',
'PhabricatorSearchResultBucket' => 'applications/search/buckets/PhabricatorSearchResultBucket.php',
'PhabricatorSearchResultBucketGroup' => 'applications/search/buckets/PhabricatorSearchResultBucketGroup.php',
'PhabricatorSearchResultView' => 'applications/search/view/PhabricatorSearchResultView.php',
@@ -8213,6 +8214,7 @@
'PhabricatorSearchOrderController' => 'PhabricatorSearchBaseController',
'PhabricatorSearchOrderField' => 'PhabricatorSearchField',
'PhabricatorSearchRelationship' => 'Phobject',
+ 'PhabricatorSearchRelationshipController' => 'PhabricatorSearchBaseController',
'PhabricatorSearchResultBucket' => 'Phobject',
'PhabricatorSearchResultBucketGroup' => 'Phobject',
'PhabricatorSearchResultView' => 'AphrontView',
diff --git a/src/applications/maniphest/relationship/ManiphestTaskHasCommitRelationship.php b/src/applications/maniphest/relationship/ManiphestTaskHasCommitRelationship.php
--- a/src/applications/maniphest/relationship/ManiphestTaskHasCommitRelationship.php
+++ b/src/applications/maniphest/relationship/ManiphestTaskHasCommitRelationship.php
@@ -24,4 +24,20 @@
return false;
}
+ public function canRelateObjects($src, $dst) {
+ return ($dst instanceof PhabricatorRepositoryCommit);
+ }
+
+ public function getDialogTitleText() {
+ return pht('Edit Related Commits');
+ }
+
+ public function getDialogHeaderText() {
+ return pht('Current Commits');
+ }
+
+ public function getDialogButtonText() {
+ return pht('Save Related Commits');
+ }
+
}
diff --git a/src/applications/maniphest/relationship/ManiphestTaskHasMockRelationship.php b/src/applications/maniphest/relationship/ManiphestTaskHasMockRelationship.php
--- a/src/applications/maniphest/relationship/ManiphestTaskHasMockRelationship.php
+++ b/src/applications/maniphest/relationship/ManiphestTaskHasMockRelationship.php
@@ -17,4 +17,20 @@
return 'fa-camera-retro';
}
+ public function canRelateObjects($src, $dst) {
+ return ($dst instanceof PholioMock);
+ }
+
+ public function getDialogTitleText() {
+ return pht('Edit Related Mocks');
+ }
+
+ public function getDialogHeaderText() {
+ return pht('Current Mocks');
+ }
+
+ public function getDialogButtonText() {
+ return pht('Save Related Mocks');
+ }
+
}
diff --git a/src/applications/maniphest/relationship/ManiphestTaskHasRevisionRelationship.php b/src/applications/maniphest/relationship/ManiphestTaskHasRevisionRelationship.php
--- a/src/applications/maniphest/relationship/ManiphestTaskHasRevisionRelationship.php
+++ b/src/applications/maniphest/relationship/ManiphestTaskHasRevisionRelationship.php
@@ -17,4 +17,20 @@
return 'fa-cog';
}
+ public function canRelateObjects($src, $dst) {
+ return ($dst instanceof DifferentialRevision);
+ }
+
+ public function getDialogTitleText() {
+ return pht('Edit Related Revisions');
+ }
+
+ public function getDialogHeaderText() {
+ return pht('Current Revisions');
+ }
+
+ public function getDialogButtonText() {
+ return pht('Save Related Revisions');
+ }
+
}
diff --git a/src/applications/search/application/PhabricatorSearchApplication.php b/src/applications/search/application/PhabricatorSearchApplication.php
--- a/src/applications/search/application/PhabricatorSearchApplication.php
+++ b/src/applications/search/application/PhabricatorSearchApplication.php
@@ -41,6 +41,8 @@
'delete/(?P<queryKey>[^/]+)/(?P<engine>[^/]+)/'
=> 'PhabricatorSearchDeleteController',
'order/(?P<engine>[^/]+)/' => 'PhabricatorSearchOrderController',
+ 'rel/(?P<relationshipKey>[^/]+)/(?P<sourcePHID>[^/]+)/'
+ => 'PhabricatorSearchRelationshipController',
),
);
}
diff --git a/src/applications/search/controller/PhabricatorSearchRelationshipController.php b/src/applications/search/controller/PhabricatorSearchRelationshipController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/controller/PhabricatorSearchRelationshipController.php
@@ -0,0 +1,198 @@
+<?php
+
+final class PhabricatorSearchRelationshipController
+ extends PhabricatorSearchBaseController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $this->getViewer();
+
+ $phid = $request->getURIData('sourcePHID');
+ $object = id(new PhabricatorObjectQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($phid))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$object) {
+ return new Aphront404Response();
+ }
+
+ $list = PhabricatorObjectRelationshipList::newForObject(
+ $viewer,
+ $object);
+
+ $relationship_key = $request->getURIData('relationshipKey');
+ $relationship = $list->getRelationship($relationship_key);
+ 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();
+
+ if ($request->isFormPost()) {
+ $phids = explode(';', $request->getStr('phids'));
+ $phids = array_filter($phids);
+ $phids = array_values($phids);
+
+ // TODO: Embed these in the form instead, to gracefully resolve
+ // concurrent edits like we do for subscribers and projects.
+ $old_phids = $dst_phids;
+
+ $add_phids = $phids;
+ $rem_phids = array_diff($old_phids, $add_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();
+
+ // TODO: Remove this, this is just legacy support.
+ $legacy_kinds = array(
+ ManiphestTaskHasCommitEdgeType::EDGECONST => 'CMIT',
+ ManiphestTaskHasMockEdgeType::EDGECONST => 'MOCK',
+ ManiphestTaskHasRevisionEdgeType::EDGECONST => 'DREV',
+ );
+
+ $edge_type = $relationship->getEdgeConstant();
+ $legacy_kind = idx($legacy_kinds, $edge_type);
+ if (!$legacy_kind) {
+ throw new Exception(
+ pht('Only specific legacy relationships are supported!'));
+ }
+
+ return id(new PhabricatorObjectSelectorDialog())
+ ->setUser($viewer)
+ ->setHandles($handles)
+ ->setFilters($filters)
+ ->setSelectedFilter('created')
+ ->setExcluded($phid)
+ ->setCancelURI($done_uri)
+ ->setSearchURI("/search/select/{$legacy_kind}/edge/")
+ ->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: %s.',
+ implode(" \xE2\x86\x92 ", $names));
+
+ return $this->newDialog()
+ ->setTitle(pht('Circular Dependency'))
+ ->appendParagraph($message)
+ ->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);
+ }
+
+}
diff --git a/src/applications/search/relationship/PhabricatorObjectRelationship.php b/src/applications/search/relationship/PhabricatorObjectRelationship.php
--- a/src/applications/search/relationship/PhabricatorObjectRelationship.php
+++ b/src/applications/search/relationship/PhabricatorObjectRelationship.php
@@ -24,6 +24,16 @@
abstract protected function getActionName();
abstract protected function getActionIcon();
+ abstract public function canRelateObjects($src, $dst);
+
+ abstract public function getDialogTitleText();
+ abstract public function getDialogHeaderText();
+ abstract public function getDialogButtonText();
+
+ public function getDialogInstructionsText() {
+ return null;
+ }
+
public function shouldAppearInActionMenu() {
return true;
}
@@ -58,24 +68,8 @@
private function getActionURI($object) {
$phid = $object->getPHID();
-
- // TODO: Remove this, this is just legacy support for the current
- // controller until a new one gets built.
- $legacy_kinds = array(
- ManiphestTaskHasCommitEdgeType::EDGECONST => 'CMIT',
- ManiphestTaskHasMockEdgeType::EDGECONST => 'MOCK',
- ManiphestTaskHasRevisionEdgeType::EDGECONST => 'DREV',
- );
-
- $edge_type = $this->getEdgeConstant();
- $legacy_kind = idx($legacy_kinds, $edge_type);
- if (!$legacy_kind) {
- throw new Exception(
- pht(
- 'Only specific legacy relationships are supported!'));
- }
-
- return "/search/attach/{$phid}/{$legacy_kind}/";
+ $type = $this->getRelationshipConstant();
+ return "/search/rel/{$type}/{$phid}/";
}
}
diff --git a/src/applications/search/relationship/PhabricatorObjectRelationshipList.php b/src/applications/search/relationship/PhabricatorObjectRelationshipList.php
--- a/src/applications/search/relationship/PhabricatorObjectRelationshipList.php
+++ b/src/applications/search/relationship/PhabricatorObjectRelationshipList.php
@@ -71,6 +71,10 @@
->setSubmenu($actions);
}
+ public function getRelationship($key) {
+ return idx($this->relationships, $key);
+ }
+
public static function newForObject(PhabricatorUser $viewer, $object) {
$relationships = PhabricatorObjectRelationship::getAllRelationships();

File Metadata

Mime Type
text/plain
Expires
Wed, Jan 22, 9:41 AM (2 h, 43 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7028742
Default Alt Text
D16163.diff (13 KB)

Event Timeline