Path: blob/master/src/applications/differential/customfield/DifferentialJIRAIssuesField.php
12256 views
<?php12final class DifferentialJIRAIssuesField3extends DifferentialStoredCustomField {45private $error;67public function getFieldKey() {8return 'phabricator:jira-issues';9}1011public function getFieldKeyForConduit() {12return 'jira.issues';13}1415public function isFieldEnabled() {16return (bool)PhabricatorJIRAAuthProvider::getJIRAProvider();17}1819public function canDisableField() {20return false;21}2223public function getValueForStorage() {24return json_encode($this->getValue());25}2627public function setValueFromStorage($value) {28try {29$this->setValue(phutil_json_decode($value));30} catch (PhutilJSONParserException $ex) {31$this->setValue(array());32}33return $this;34}3536public function getFieldName() {37return pht('JIRA Issues');38}3940public function getFieldDescription() {41return pht('Lists associated JIRA issues.');42}4344public function shouldAppearInPropertyView() {45return true;46}4748public function renderPropertyViewLabel() {49return $this->getFieldName();50}5152public function renderPropertyViewValue(array $handles) {53$xobjs = $this->loadDoorkeeperExternalObjects($this->getValue());54if (!$xobjs) {55return null;56}5758$links = array();59foreach ($xobjs as $xobj) {60$links[] = id(new DoorkeeperTagView())61->setExternalObject($xobj);62}6364return phutil_implode_html(phutil_tag('br'), $links);65}6667private function buildDoorkeeperRefs($value) {68$provider = PhabricatorJIRAAuthProvider::getJIRAProvider();6970$refs = array();71if ($value) {72foreach ($value as $jira_key) {73$refs[] = id(new DoorkeeperObjectRef())74->setApplicationType(DoorkeeperBridgeJIRA::APPTYPE_JIRA)75->setApplicationDomain($provider->getProviderDomain())76->setObjectType(DoorkeeperBridgeJIRA::OBJTYPE_ISSUE)77->setObjectID($jira_key);78}79}8081return $refs;82}8384private function loadDoorkeeperExternalObjects($value) {85$refs = $this->buildDoorkeeperRefs($value);86if (!$refs) {87return array();88}8990$xobjs = id(new DoorkeeperExternalObjectQuery())91->setViewer($this->getViewer())92->withObjectKeys(mpull($refs, 'getObjectKey'))93->execute();9495return $xobjs;96}9798public function shouldAppearInEditView() {99return PhabricatorJIRAAuthProvider::getJIRAProvider();100}101102public function shouldAppearInApplicationTransactions() {103return PhabricatorJIRAAuthProvider::getJIRAProvider();104}105106public function readValueFromRequest(AphrontRequest $request) {107$this->setValue($request->getStrList($this->getFieldKey()));108return $this;109}110111public function renderEditControl(array $handles) {112return id(new AphrontFormTextControl())113->setLabel(pht('JIRA Issues'))114->setCaption(115pht('Example: %s', phutil_tag('tt', array(), 'JIS-3, JIS-9')))116->setName($this->getFieldKey())117->setValue(implode(', ', nonempty($this->getValue(), array())))118->setError($this->error);119}120121public function getOldValueForApplicationTransactions() {122return array_unique(nonempty($this->getValue(), array()));123}124125public function getNewValueForApplicationTransactions() {126return array_unique(nonempty($this->getValue(), array()));127}128129public function validateApplicationTransactions(130PhabricatorApplicationTransactionEditor $editor,131$type,132array $xactions) {133134$this->error = null;135136$errors = parent::validateApplicationTransactions(137$editor,138$type,139$xactions);140141$transaction = null;142foreach ($xactions as $xaction) {143$old = $xaction->getOldValue();144$new = $xaction->getNewValue();145146$add = array_diff($new, $old);147if (!$add) {148continue;149}150151// Only check that the actor can see newly added JIRA refs. You're152// allowed to remove refs or make no-op changes even if you aren't153// linked to JIRA.154155try {156$refs = id(new DoorkeeperImportEngine())157->setViewer($this->getViewer())158->setRefs($this->buildDoorkeeperRefs($add))159->setThrowOnMissingLink(true)160->execute();161} catch (DoorkeeperMissingLinkException $ex) {162$this->error = pht('Not Linked');163$errors[] = new PhabricatorApplicationTransactionValidationError(164$type,165pht('Not Linked'),166pht(167'You can not add JIRA issues (%s) to this revision because your '.168'%s account is not linked to a JIRA account.',169implode(', ', $add),170PlatformSymbols::getPlatformServerName()),171$xaction);172continue;173}174175$bad = array();176foreach ($refs as $ref) {177if (!$ref->getIsVisible()) {178$bad[] = $ref->getObjectID();179}180}181182if ($bad) {183$bad = implode(', ', $bad);184$this->error = pht('Invalid');185186$errors[] = new PhabricatorApplicationTransactionValidationError(187$type,188pht('Invalid'),189pht(190'Some JIRA issues could not be loaded. They may not exist, or '.191'you may not have permission to view them: %s',192$bad),193$xaction);194}195}196197return $errors;198}199200public function getApplicationTransactionTitle(201PhabricatorApplicationTransaction $xaction) {202203$old = $xaction->getOldValue();204if (!is_array($old)) {205$old = array();206}207208$new = $xaction->getNewValue();209if (!is_array($new)) {210$new = array();211}212213$add = array_diff($new, $old);214$rem = array_diff($old, $new);215216$author_phid = $xaction->getAuthorPHID();217if ($add && $rem) {218return pht(219'%s updated JIRA issue(s): added %d %s; removed %d %s.',220$xaction->renderHandleLink($author_phid),221phutil_count($add),222implode(', ', $add),223phutil_count($rem),224implode(', ', $rem));225} else if ($add) {226return pht(227'%s added %d JIRA issue(s): %s.',228$xaction->renderHandleLink($author_phid),229phutil_count($add),230implode(', ', $add));231} else if ($rem) {232return pht(233'%s removed %d JIRA issue(s): %s.',234$xaction->renderHandleLink($author_phid),235phutil_count($rem),236implode(', ', $rem));237}238239return parent::getApplicationTransactionTitle($xaction);240}241242public function applyApplicationTransactionExternalEffects(243PhabricatorApplicationTransaction $xaction) {244245// Update the CustomField storage.246parent::applyApplicationTransactionExternalEffects($xaction);247248// Now, synchronize the Doorkeeper edges.249$revision = $this->getObject();250$revision_phid = $revision->getPHID();251252$edge_type = PhabricatorJiraIssueHasObjectEdgeType::EDGECONST;253$xobjs = $this->loadDoorkeeperExternalObjects($xaction->getNewValue());254$edge_dsts = mpull($xobjs, 'getPHID');255256$edges = PhabricatorEdgeQuery::loadDestinationPHIDs(257$revision_phid,258$edge_type);259260$editor = new PhabricatorEdgeEditor();261262foreach (array_diff($edges, $edge_dsts) as $rem_edge) {263$editor->removeEdge($revision_phid, $edge_type, $rem_edge);264}265266foreach (array_diff($edge_dsts, $edges) as $add_edge) {267$editor->addEdge($revision_phid, $edge_type, $add_edge);268}269270$editor->save();271}272273public function shouldAppearInConduitDictionary() {274return true;275}276277public function shouldAppearInConduitTransactions() {278return true;279}280281protected function newConduitEditParameterType() {282return new ConduitStringListParameterType();283}284285}286287288