protected function applyReviewers(array $phids, $is_blocking)
 {
     $adapter = $this->getAdapter();
     $object = $adapter->getObject();
     $phids = array_fuse($phids);
     // Don't try to add revision authors as reviewers.
     $authors = array();
     foreach ($phids as $phid) {
         if ($phid == $object->getAuthorPHID()) {
             $authors[] = $phid;
             unset($phids[$phid]);
         }
     }
     if ($authors) {
         $this->logEffect(self::DO_AUTHORS, $authors);
         if (!$phids) {
             return;
         }
     }
     $reviewers = $object->getReviewerStatus();
     $reviewers = mpull($reviewers, null, 'getReviewerPHID');
     if ($is_blocking) {
         $new_status = DifferentialReviewerStatus::STATUS_BLOCKING;
     } else {
         $new_status = DifferentialReviewerStatus::STATUS_ADDED;
     }
     $new_strength = DifferentialReviewerStatus::getStatusStrength($new_status);
     $current = array();
     foreach ($phids as $phid) {
         if (!isset($reviewers[$phid])) {
             continue;
         }
         // If we're applying a stronger status (usually, upgrading a reviewer
         // into a blocking reviewer), skip this check so we apply the change.
         $old_strength = DifferentialReviewerStatus::getStatusStrength($reviewers[$phid]->getStatus());
         if ($old_strength <= $new_strength) {
             continue;
         }
         $current[] = $phid;
     }
     $allowed_types = array(PhabricatorPeopleUserPHIDType::TYPECONST, PhabricatorProjectProjectPHIDType::TYPECONST);
     $targets = $this->loadStandardTargets($phids, $allowed_types, $current);
     if (!$targets) {
         return;
     }
     $phids = array_fuse(array_keys($targets));
     $value = array();
     foreach ($phids as $phid) {
         $value[$phid] = array('data' => array('status' => $new_status));
     }
     $edgetype_reviewer = DifferentialRevisionHasReviewerEdgeType::EDGECONST;
     $xaction = $adapter->newTransaction()->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $edgetype_reviewer)->setNewValue(array('+' => $value));
     $adapter->queueTransaction($xaction);
     if ($is_blocking) {
         $this->logEffect(self::DO_ADD_BLOCKING_REVIEWERS, $phids);
     } else {
         $this->logEffect(self::DO_ADD_REVIEWERS, $phids);
     }
 }
 protected function didApplyHeraldRules(PhabricatorLiskDAO $object, HeraldAdapter $adapter, HeraldTranscript $transcript)
 {
     $xactions = array();
     // Build a transaction to adjust reviewers.
     $reviewers = array(DifferentialReviewerStatus::STATUS_ADDED => array_keys($adapter->getReviewersAddedByHerald()), DifferentialReviewerStatus::STATUS_BLOCKING => array_keys($adapter->getBlockingReviewersAddedByHerald()));
     $old_reviewers = $object->getReviewerStatus();
     $old_reviewers = mpull($old_reviewers, null, 'getReviewerPHID');
     $value = array();
     foreach ($reviewers as $status => $phids) {
         foreach ($phids as $phid) {
             if ($phid == $object->getAuthorPHID()) {
                 // Don't try to add the revision's author as a reviewer, since this
                 // isn't valid and doesn't make sense.
                 continue;
             }
             // If the target is already a reviewer, don't try to change anything
             // if their current status is at least as strong as the new status.
             // For example, don't downgrade an "Accepted" to a "Blocking Reviewer".
             $old_reviewer = idx($old_reviewers, $phid);
             if ($old_reviewer) {
                 $old_status = $old_reviewer->getStatus();
                 $old_strength = DifferentialReviewerStatus::getStatusStrength($old_status);
                 $new_strength = DifferentialReviewerStatus::getStatusStrength($status);
                 if ($new_strength <= $old_strength) {
                     continue;
                 }
             }
             $value['+'][$phid] = array('data' => array('status' => $status));
         }
     }
     if ($value) {
         $edge_reviewer = DifferentialRevisionHasReviewerEdgeType::EDGECONST;
         $xactions[] = id(new DifferentialTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $edge_reviewer)->setNewValue($value);
     }
     // Require legalpad document signatures.
     $legal_phids = $adapter->getRequiredSignatureDocumentPHIDs();
     if ($legal_phids) {
         // We only require signatures of documents which have not already
         // been signed. In general, this reduces the amount of churn that
         // signature rules cause.
         $signatures = id(new LegalpadDocumentSignatureQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withDocumentPHIDs($legal_phids)->withSignerPHIDs(array($object->getAuthorPHID()))->execute();
         $signed_phids = mpull($signatures, 'getDocumentPHID');
         $legal_phids = array_diff($legal_phids, $signed_phids);
         // If we still have something to trigger, add the edges.
         if ($legal_phids) {
             $edge_legal = LegalpadObjectNeedsSignatureEdgeType::EDGECONST;
             $xactions[] = id(new DifferentialTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $edge_legal)->setNewValue(array('+' => array_fuse($legal_phids)));
         }
     }
     // Apply build plans.
     HarbormasterBuildable::applyBuildPlans($adapter->getDiff()->getPHID(), $adapter->getPHID(), $adapter->getBuildPlans());
     return $xactions;
 }
 private function newAutoReviewTransaction(PhabricatorLiskDAO $object, array $phids, $is_blocking)
 {
     // TODO: This is substantially similar to DifferentialReviewersHeraldAction
     // and both are needlessly complex. This logic should live in the normal
     // transaction application pipeline. See T10967.
     $reviewers = $object->getReviewerStatus();
     $reviewers = mpull($reviewers, null, 'getReviewerPHID');
     if ($is_blocking) {
         $new_status = DifferentialReviewerStatus::STATUS_BLOCKING;
     } else {
         $new_status = DifferentialReviewerStatus::STATUS_ADDED;
     }
     $new_strength = DifferentialReviewerStatus::getStatusStrength($new_status);
     $current = array();
     foreach ($phids as $phid) {
         if (!isset($reviewers[$phid])) {
             continue;
         }
         // If we're applying a stronger status (usually, upgrading a reviewer
         // into a blocking reviewer), skip this check so we apply the change.
         $old_strength = DifferentialReviewerStatus::getStatusStrength($reviewers[$phid]->getStatus());
         if ($old_strength <= $new_strength) {
             continue;
         }
         $current[] = $phid;
     }
     $phids = array_diff($phids, $current);
     if (!$phids) {
         return null;
     }
     $phids = array_fuse($phids);
     $value = array();
     foreach ($phids as $phid) {
         $value[$phid] = array('data' => array('status' => $new_status));
     }
     $edgetype_reviewer = DifferentialRevisionHasReviewerEdgeType::EDGECONST;
     $owners_phid = id(new PhabricatorOwnersApplication())->getPHID();
     return $object->getApplicationTransactionTemplate()->setAuthorPHID($owners_phid)->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $edgetype_reviewer)->setNewValue(array('+' => $value));
 }
 protected function mergeEdgeData($type, array $u, array $v)
 {
     $result = parent::mergeEdgeData($type, $u, $v);
     switch ($type) {
         case DifferentialRevisionHasReviewerEdgeType::EDGECONST:
             // When the same reviewer has their status updated by multiple
             // transactions, we want the strongest status to win. An example of
             // this is when a user adds a comment and also accepts a revision which
             // they are a reviewer on. The comment creates a "commented" status,
             // while the accept creates an "accepted" status. Since accept is
             // stronger, it should win and persist.
             $u_status = idx($u, 'status');
             $v_status = idx($v, 'status');
             $u_str = DifferentialReviewerStatus::getStatusStrength($u_status);
             $v_str = DifferentialReviewerStatus::getStatusStrength($v_status);
             if ($u_str > $v_str) {
                 $result['status'] = $u_status;
             } else {
                 $result['status'] = $v_status;
             }
             break;
     }
     return $result;
 }