[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/applications/search/controller/ -> PhabricatorSearchAttachController.php (source)

   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  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1