[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 final class PhabricatorSearchAttachController 4 extends PhabricatorSearchBaseController { 5 6 private $phid; 7 private $type; 8 private $action; 9 10 const ACTION_ATTACH = 'attach'; 11 const ACTION_MERGE = 'merge'; 12 const ACTION_DEPENDENCIES = 'dependencies'; 13 const ACTION_BLOCKS = 'blocks'; 14 const ACTION_EDGE = 'edge'; 15 16 public function willProcessRequest(array $data) { 17 $this->phid = $data['phid']; 18 $this->type = $data['type']; 19 $this->action = idx($data, 'action', self::ACTION_ATTACH); 20 } 21 22 public function processRequest() { 23 24 $request = $this->getRequest(); 25 $user = $request->getUser(); 26 27 $handle = id(new PhabricatorHandleQuery()) 28 ->setViewer($user) 29 ->withPHIDs(array($this->phid)) 30 ->executeOne(); 31 32 $object_type = $handle->getType(); 33 $attach_type = $this->type; 34 35 $object = id(new PhabricatorObjectQuery()) 36 ->setViewer($user) 37 ->withPHIDs(array($this->phid)) 38 ->executeOne(); 39 40 if (!$object) { 41 return new Aphront404Response(); 42 } 43 44 $edge_type = null; 45 switch ($this->action) { 46 case self::ACTION_EDGE: 47 case self::ACTION_DEPENDENCIES: 48 case self::ACTION_BLOCKS: 49 case self::ACTION_ATTACH: 50 $edge_type = $this->getEdgeType($object_type, $attach_type); 51 break; 52 } 53 54 if ($request->isFormPost()) { 55 $phids = explode(';', $request->getStr('phids')); 56 $phids = array_filter($phids); 57 $phids = array_values($phids); 58 59 if ($edge_type) { 60 if (!$object instanceof PhabricatorApplicationTransactionInterface) { 61 throw new Exception( 62 pht( 63 'Expected object ("%s") to implement interface "%s".', 64 get_class($object), 65 'PhabricatorApplicationTransactionInterface')); 66 } 67 68 $old_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( 69 $this->phid, 70 $edge_type); 71 $add_phids = $phids; 72 $rem_phids = array_diff($old_phids, $add_phids); 73 74 $txn_editor = $object->getApplicationTransactionEditor() 75 ->setActor($user) 76 ->setContentSourceFromRequest($request) 77 ->setContinueOnMissingFields(true); 78 79 $txn_template = $object->getApplicationTransactionTemplate() 80 ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 81 ->setMetadataValue('edge:type', $edge_type) 82 ->setNewValue(array( 83 '+' => array_fuse($add_phids), 84 '-' => array_fuse($rem_phids), 85 )); 86 $txn_editor->applyTransactions( 87 $object->getApplicationTransactionObject(), 88 array($txn_template)); 89 90 return id(new AphrontReloadResponse())->setURI($handle->getURI()); 91 } else { 92 return $this->performMerge($object, $handle, $phids); 93 } 94 } else { 95 if ($edge_type) { 96 $phids = PhabricatorEdgeQuery::loadDestinationPHIDs( 97 $this->phid, 98 $edge_type); 99 } else { 100 // This is a merge. 101 $phids = array(); 102 } 103 } 104 105 $strings = $this->getStrings(); 106 107 $handles = $this->loadViewerHandles($phids); 108 109 $obj_dialog = new PhabricatorObjectSelectorDialog(); 110 $obj_dialog 111 ->setUser($user) 112 ->setHandles($handles) 113 ->setFilters($this->getFilters($strings)) 114 ->setSelectedFilter($strings['selected']) 115 ->setExcluded($this->phid) 116 ->setCancelURI($handle->getURI()) 117 ->setSearchURI('/search/select/'.$attach_type.'/') 118 ->setTitle($strings['title']) 119 ->setHeader($strings['header']) 120 ->setButtonText($strings['button']) 121 ->setInstructions($strings['instructions']); 122 123 $dialog = $obj_dialog->buildDialog(); 124 125 return id(new AphrontDialogResponse())->setDialog($dialog); 126 } 127 128 private function performMerge( 129 ManiphestTask $task, 130 PhabricatorObjectHandle $handle, 131 array $phids) { 132 133 $user = $this->getRequest()->getUser(); 134 $response = id(new AphrontReloadResponse())->setURI($handle->getURI()); 135 136 $phids = array_fill_keys($phids, true); 137 unset($phids[$task->getPHID()]); // Prevent merging a task into itself. 138 139 if (!$phids) { 140 return $response; 141 } 142 143 $targets = id(new ManiphestTaskQuery()) 144 ->setViewer($user) 145 ->withPHIDs(array_keys($phids)) 146 ->execute(); 147 148 if (empty($targets)) { 149 return $response; 150 } 151 152 $editor = id(new ManiphestTransactionEditor()) 153 ->setActor($user) 154 ->setContentSourceFromRequest($this->getRequest()) 155 ->setContinueOnNoEffect(true) 156 ->setContinueOnMissingFields(true); 157 158 $cc_vector = array(); 159 $cc_vector[] = $task->getCCPHIDs(); 160 foreach ($targets as $target) { 161 $cc_vector[] = $target->getCCPHIDs(); 162 $cc_vector[] = array( 163 $target->getAuthorPHID(), 164 $target->getOwnerPHID(), 165 ); 166 167 $merged_into_txn = id(new ManiphestTransaction()) 168 ->setTransactionType(ManiphestTransaction::TYPE_MERGED_INTO) 169 ->setNewValue($task->getPHID()); 170 171 $editor->applyTransactions( 172 $target, 173 array($merged_into_txn)); 174 175 } 176 $all_ccs = array_mergev($cc_vector); 177 $all_ccs = array_filter($all_ccs); 178 $all_ccs = array_unique($all_ccs); 179 180 $add_ccs = id(new ManiphestTransaction()) 181 ->setTransactionType(ManiphestTransaction::TYPE_CCS) 182 ->setNewValue($all_ccs); 183 184 $merged_from_txn = id(new ManiphestTransaction()) 185 ->setTransactionType(ManiphestTransaction::TYPE_MERGED_FROM) 186 ->setNewValue(mpull($targets, 'getPHID')); 187 188 $editor->applyTransactions( 189 $task, 190 array($add_ccs, $merged_from_txn)); 191 192 return $response; 193 } 194 195 private function getStrings() { 196 switch ($this->type) { 197 case DifferentialRevisionPHIDType::TYPECONST: 198 $noun = 'Revisions'; 199 $selected = 'created'; 200 break; 201 case ManiphestTaskPHIDType::TYPECONST: 202 $noun = 'Tasks'; 203 $selected = 'assigned'; 204 break; 205 case PhabricatorRepositoryCommitPHIDType::TYPECONST: 206 $noun = 'Commits'; 207 $selected = 'created'; 208 break; 209 case PholioMockPHIDType::TYPECONST: 210 $noun = 'Mocks'; 211 $selected = 'created'; 212 break; 213 } 214 215 switch ($this->action) { 216 case self::ACTION_EDGE: 217 case self::ACTION_ATTACH: 218 $dialog_title = "Manage Attached {$noun}"; 219 $header_text = "Currently Attached {$noun}"; 220 $button_text = "Save {$noun}"; 221 $instructions = null; 222 break; 223 case self::ACTION_MERGE: 224 $dialog_title = 'Merge Duplicate Tasks'; 225 $header_text = 'Tasks To Merge'; 226 $button_text = "Merge {$noun}"; 227 $instructions = 228 'These tasks will be merged into the current task and then closed. '. 229 'The current task will grow stronger.'; 230 break; 231 case self::ACTION_DEPENDENCIES: 232 $dialog_title = 'Edit Dependencies'; 233 $header_text = 'Current Dependencies'; 234 $button_text = 'Save Dependencies'; 235 $instructions = null; 236 break; 237 case self::ACTION_BLOCKS: 238 $dialog_title = pht('Edit Blocking Tasks'); 239 $header_text = pht('Current Blocking Tasks'); 240 $button_text = pht('Save Blocking Tasks'); 241 $instructions = null; 242 break; 243 } 244 245 return array( 246 'target_plural_noun' => $noun, 247 'selected' => $selected, 248 'title' => $dialog_title, 249 'header' => $header_text, 250 'button' => $button_text, 251 'instructions' => $instructions, 252 ); 253 } 254 255 private function getFilters(array $strings) { 256 if ($this->type == PholioMockPHIDType::TYPECONST) { 257 $filters = array( 258 'created' => 'Created By Me', 259 'all' => 'All '.$strings['target_plural_noun'], 260 ); 261 } else { 262 $filters = array( 263 'assigned' => 'Assigned to Me', 264 'created' => 'Created By Me', 265 'open' => 'All Open '.$strings['target_plural_noun'], 266 'all' => 'All '.$strings['target_plural_noun'], 267 ); 268 } 269 270 return $filters; 271 } 272 273 private function getEdgeType($src_type, $dst_type) { 274 $t_cmit = PhabricatorRepositoryCommitPHIDType::TYPECONST; 275 $t_task = ManiphestTaskPHIDType::TYPECONST; 276 $t_drev = DifferentialRevisionPHIDType::TYPECONST; 277 $t_mock = PholioMockPHIDType::TYPECONST; 278 279 $map = array( 280 $t_cmit => array( 281 $t_task => DiffusionCommitHasTaskEdgeType::EDGECONST, 282 ), 283 $t_task => array( 284 $t_cmit => ManiphestTaskHasCommitEdgeType::EDGECONST, 285 $t_task => PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK, 286 $t_drev => ManiphestTaskHasRevisionEdgeType::EDGECONST, 287 $t_mock => PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK, 288 ), 289 $t_drev => array( 290 $t_drev => PhabricatorEdgeConfig::TYPE_DREV_DEPENDS_ON_DREV, 291 $t_task => DifferentialRevisionHasTaskEdgeType::EDGECONST, 292 ), 293 $t_mock => array( 294 $t_task => PhabricatorEdgeConfig::TYPE_MOCK_HAS_TASK, 295 ), 296 ); 297 298 if (empty($map[$src_type][$dst_type])) { 299 return null; 300 } 301 302 return $map[$src_type][$dst_type]; 303 } 304 305 private function raiseGraphCycleException(PhabricatorEdgeCycleException $ex) { 306 $cycle = $ex->getCycle(); 307 308 $handles = $this->loadViewerHandles($cycle); 309 $names = array(); 310 foreach ($cycle as $cycle_phid) { 311 $names[] = $handles[$cycle_phid]->getFullName(); 312 } 313 $names = implode(" \xE2\x86\x92 ", $names); 314 throw new Exception( 315 "You can not create that dependency, because it would create a ". 316 "circular dependency: {$names}."); 317 } 318 319 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |