@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at recaptime-dev/main 229 lines 7.4 kB view raw
1<?php 2 3final class PhabricatorSearchRelationshipController 4 extends PhabricatorSearchBaseController { 5 6 public function handleRequest(AphrontRequest $request) { 7 $viewer = $this->getViewer(); 8 9 $object = $this->loadRelationshipObject(); 10 if (!$object) { 11 return new Aphront404Response(); 12 } 13 14 $relationship = $this->loadRelationship($object); 15 if (!$relationship) { 16 return new Aphront404Response(); 17 } 18 19 $src_phid = $object->getPHID(); 20 $edge_type = $relationship->getEdgeConstant(); 21 22 // If this is a normal relationship, users can remove related objects. If 23 // it's a special relationship like a merge, we can't undo it, so we won't 24 // prefill the current related objects. 25 if ($relationship->canUndoRelationship()) { 26 $dst_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( 27 $src_phid, 28 $edge_type); 29 } else { 30 $dst_phids = array(); 31 } 32 33 $all_phids = $dst_phids; 34 $all_phids[] = $src_phid; 35 36 $handles = $viewer->loadHandles($all_phids); 37 $src_handle = $handles[$src_phid]; 38 39 $done_uri = $src_handle->getURI(); 40 $initial_phids = $dst_phids; 41 42 $maximum = $relationship->getMaximumSelectionSize(); 43 44 if ($request->isFormPost()) { 45 $phids = explode(';', $request->getStr('phids')); 46 $phids = array_filter($phids); 47 $phids = array_values($phids); 48 49 // The UI normally enforces this with Javascript, so this is just a 50 // sanity check and does not need to be particularly user-friendly. 51 if ($maximum && (count($phids) > $maximum)) { 52 throw new Exception( 53 pht( 54 'Too many relationships (%s, of type "%s").', 55 phutil_count($phids), 56 $relationship->getRelationshipConstant())); 57 } 58 59 $initial_phids = $request->getStrList('initialPHIDs'); 60 61 // Apply the changes as adds and removes relative to the original state 62 // of the object when the dialog was rendered so that two users adding 63 // relationships at the same time don't race and overwrite one another. 64 $add_phids = array_diff($phids, $initial_phids); 65 $rem_phids = array_diff($initial_phids, $phids); 66 $all_phids = array_merge($add_phids, $rem_phids); 67 68 $capabilities = $relationship->getRequiredRelationshipCapabilities(); 69 70 if ($all_phids) { 71 $dst_objects = id(new PhabricatorObjectQuery()) 72 ->setViewer($viewer) 73 ->withPHIDs($all_phids) 74 ->setRaisePolicyExceptions(true) 75 ->requireCapabilities($capabilities) 76 ->execute(); 77 $dst_objects = mpull($dst_objects, null, 'getPHID'); 78 } else { 79 $dst_objects = array(); 80 } 81 82 try { 83 foreach ($add_phids as $add_phid) { 84 $dst_object = idx($dst_objects, $add_phid); 85 if (!$dst_object) { 86 throw new Exception( 87 pht( 88 'You can not create a relationship to object "%s" because '. 89 'the object does not exist or could not be loaded.', 90 $add_phid)); 91 } 92 93 if ($add_phid == $src_phid) { 94 throw new Exception( 95 pht( 96 'You can not create a relationship to object "%s" because '. 97 'objects can not be related to themselves.', 98 $add_phid)); 99 } 100 101 if (!$relationship->canRelateObjects($object, $dst_object)) { 102 throw new Exception( 103 pht( 104 'You can not create a relationship (of type "%s") to object '. 105 '"%s" because it is not the right type of object for this '. 106 'relationship.', 107 $relationship->getRelationshipConstant(), 108 $add_phid)); 109 } 110 } 111 } catch (Exception $ex) { 112 return $this->newUnrelatableObjectResponse($ex, $done_uri); 113 } 114 115 $content_source = PhabricatorContentSource::newFromRequest($request); 116 $relationship->setContentSource($content_source); 117 118 $editor = $object->getApplicationTransactionEditor() 119 ->setActor($viewer) 120 ->setContentSource($content_source) 121 ->setContinueOnMissingFields(true) 122 ->setContinueOnNoEffect(true); 123 124 $xactions = array(); 125 $xactions[] = $object->getApplicationTransactionTemplate() 126 ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 127 ->setMetadataValue('edge:type', $edge_type) 128 ->setNewValue(array( 129 '+' => array_fuse($add_phids), 130 '-' => array_fuse($rem_phids), 131 )); 132 133 $add_objects = array_select_keys($dst_objects, $add_phids); 134 $rem_objects = array_select_keys($dst_objects, $rem_phids); 135 136 if ($add_objects || $rem_objects) { 137 $more_xactions = $relationship->willUpdateRelationships( 138 $object, 139 $add_objects, 140 $rem_objects); 141 foreach ($more_xactions as $xaction) { 142 $xactions[] = $xaction; 143 } 144 } 145 146 try { 147 $editor->applyTransactions($object, $xactions); 148 149 if ($add_objects || $rem_objects) { 150 $relationship->didUpdateRelationships( 151 $object, 152 $add_objects, 153 $rem_objects); 154 } 155 156 return id(new AphrontRedirectResponse())->setURI($done_uri); 157 } catch (PhabricatorEdgeCycleException $ex) { 158 return $this->newGraphCycleResponse($ex, $done_uri); 159 } 160 } 161 162 $handles = iterator_to_array($handles); 163 $handles = array_select_keys($handles, $dst_phids); 164 165 $dialog_title = $relationship->getDialogTitleText(); 166 $dialog_header = $relationship->getDialogHeaderText(); 167 $dialog_button = $relationship->getDialogButtonText(); 168 $dialog_instructions = $relationship->getDialogInstructionsText(); 169 170 $source_uri = $relationship->getSourceURI($object); 171 172 $source = $relationship->newSource(); 173 174 $filters = $source->getFilters(); 175 $selected_filter = $source->getSelectedFilter(); 176 177 return id(new PhabricatorObjectSelectorDialog()) 178 ->setUser($viewer) 179 ->setInitialPHIDs($initial_phids) 180 ->setHandles($handles) 181 ->setFilters($filters) 182 ->setSelectedFilter($selected_filter) 183 ->setExcluded($src_phid) 184 ->setCancelURI($done_uri) 185 ->setSearchURI($source_uri) 186 ->setTitle($dialog_title) 187 ->setHeader($dialog_header) 188 ->setButtonText($dialog_button) 189 ->setInstructions($dialog_instructions) 190 ->setMaximumSelectionSize($maximum) 191 ->buildDialog(); 192 } 193 194 private function newGraphCycleResponse( 195 PhabricatorEdgeCycleException $ex, 196 $done_uri) { 197 198 $viewer = $this->getViewer(); 199 $cycle = $ex->getCycle(); 200 201 $handles = $this->loadViewerHandles($cycle); 202 $names = array(); 203 foreach ($cycle as $cycle_phid) { 204 $names[] = $handles[$cycle_phid]->getFullName(); 205 } 206 207 $message = pht( 208 'You can not create that relationship because it would create a '. 209 'circular dependency:'); 210 211 $list = implode(" \xE2\x86\x92 ", $names); 212 213 return $this->newDialog() 214 ->setTitle(pht('Circular Dependency')) 215 ->appendParagraph($message) 216 ->appendParagraph($list) 217 ->addCancelButton($done_uri); 218 } 219 220 private function newUnrelatableObjectResponse(Exception $ex, $done_uri) { 221 $message = $ex->getMessage(); 222 223 return $this->newDialog() 224 ->setTitle(pht('Invalid Relationship')) 225 ->appendParagraph($message) 226 ->addCancelButton($done_uri); 227 } 228 229}