diff --git a/src/applications/differential/editor/revision/DifferentialRevisionEditor.php b/src/applications/differential/editor/revision/DifferentialRevisionEditor.php index 3f9e91d010..822c641031 100644 --- a/src/applications/differential/editor/revision/DifferentialRevisionEditor.php +++ b/src/applications/differential/editor/revision/DifferentialRevisionEditor.php @@ -308,12 +308,10 @@ class DifferentialRevisionEditor { $stable[$key] = array_diff_key($old[$key], $add[$key] + $rem[$key]); } - self::removeReviewers( + self::alterReviewers( $revision, + $this->reviewers, array_keys($rem['rev']), - $this->actorPHID); - self::addReviewers( - $revision, array_keys($add['rev']), $this->actorPHID); @@ -493,42 +491,93 @@ class DifferentialRevisionEditor { } - public static function addReviewers( + public static function alterReviewers( DifferentialRevision $revision, - array $reviewer_ids, + array $stable_phids, + array $rem_phids, + array $add_phids, $reason_phid) { -/* - foreach ($reviewer_ids as $reviewer_id) { - $relationship = new DifferentialRelationship(); - $relationship->setRevisionID($revision->getID()); - $relationship->setRelatedPHID($reviewer_id); - $relationship->setForbidden(false); - $relationship->setReasonPHID($reason_phid); - $relationship->setRelation(DifferentialRelationship::RELATION_REVIEWER); - $relationship->replace(); - } -*/ - } - public static function removeReviewers( - DifferentialRevision $revision, - array $reviewer_ids, - $reason_phid) { -/* - if (!$reviewer_ids) { - return; + $rem_map = array_fill_keys($rem_phids, true); + $add_map = array_fill_keys($add_phids, true); + + $seq_map = array_values($stable_phids); + $seq_map = array_flip($seq_map); + foreach ($rem_map as $phid => $ignored) { + if (!isset($seq_map[$phid])) { + $seq_map[$phid] = count($seq_map); + } + } + foreach ($add_map as $phid => $ignored) { + if (!isset($seq_map[$phid])) { + $seq_map[$phid] = count($seq_map); + } } - foreach ($reviewer_ids as $reviewer_id) { - $relationship = new DifferentialRelationship(); - $relationship->setRevisionID($revision->getID()); - $relationship->setRelatedPHID($reviewer_id); - $relationship->setForbidden(true); - $relationship->setReasonPHID($reason_phid); - $relationship->setRelation(DifferentialRelationship::RELATION_REVIEWER); - $relationship->replace(); + $raw = $revision->getRawRelations(DifferentialRevision::RELATION_REVIEWER); + $raw = ipull($raw, 'objectPHID'); + + $sequence = count($seq_map); + foreach ($raw as $phid => $relation) { + if (isset($seq_map[$phid])) { + $raw[$phid]['sequence'] = $seq_map[$phid]; + } else { + $raw[$phid]['sequence'] = $sequence++; + } } -*/ + $raw = isort($raw, 'sequence'); + + foreach ($raw as $phid => $relation) { + if (isset($rem_map[$phid])) { + $relation['forbidden'] = true; + $relation['reasonPHID'] = $reason_phid; + } else if (isset($add_map[$phid])) { + $relation['forbidden'] = false; + $relation['reasonPHID'] = $reason_phid; + } + } + + foreach ($add_phids as $add) { + $raw[] = array( + 'objectPHID' => $add, + 'forbidden' => false, + 'sequence' => idx($seq_map, $add, $sequence++), + 'reasonPHID' => $reason_phid, + ); + } + + $conn_w = $revision->establishConnection('w'); + + $sql = array(); + foreach ($raw as $relation) { + $sql[] = qsprintf( + $conn_w, + '(%d, %s, %s, %d, %d, %s)', + $revision->getID(), + DifferentialRevision::RELATION_REVIEWER, + $relation['objectPHID'], + $relation['forbidden'], + $relation['sequence'], + $relation['reasonPHID']); + } + + $conn_w->openTransaction(); + queryfx( + $conn_w, + 'DELETE FROM %T WHERE revisionID = %d AND relation = %s', + DifferentialRevision::RELATIONSHIP_TABLE, + $revision->getID(), + DifferentialRevision::RELATION_REVIEWER); + if ($sql) { + queryfx( + $conn_w, + 'INSERT INTO %T + (revisionID, relation, objectPHID, forbidden, sequence, reasonPHID) + VALUES %Q', + DifferentialRevision::RELATIONSHIP_TABLE, + implode(', ', $sql)); + } + $conn_w->saveTransaction(); } /* diff --git a/src/applications/differential/editor/revision/__init__.php b/src/applications/differential/editor/revision/__init__.php index 1be89fe9a6..6a5577586c 100644 --- a/src/applications/differential/editor/revision/__init__.php +++ b/src/applications/differential/editor/revision/__init__.php @@ -10,6 +10,9 @@ phutil_require_module('phabricator', 'applications/differential/constants/revisi phutil_require_module('phabricator', 'applications/differential/mail/ccwelcome'); phutil_require_module('phabricator', 'applications/differential/mail/newdiff'); phutil_require_module('phabricator', 'applications/differential/storage/changeset'); +phutil_require_module('phabricator', 'applications/differential/storage/revision'); +phutil_require_module('phabricator', 'storage/qsprintf'); +phutil_require_module('phabricator', 'storage/queryfx'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/differential/storage/revision/DifferentialRevision.php b/src/applications/differential/storage/revision/DifferentialRevision.php index 5f3b6008ca..a14989e48e 100755 --- a/src/applications/differential/storage/revision/DifferentialRevision.php +++ b/src/applications/differential/storage/revision/DifferentialRevision.php @@ -32,7 +32,15 @@ class DifferentialRevision extends DifferentialDAO { protected $dateCommitted; protected $lineCount; - + + private $related; + private $forbidden; + + const RELATIONSHIP_TABLE = 'differential_relationship'; + + const RELATION_REVIEWER = 'revw'; + const RELATION_SUBSCRIBED = 'subd'; + public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, @@ -42,17 +50,102 @@ class DifferentialRevision extends DifferentialDAO { public function generatePHID() { return PhabricatorPHID::generateNewPHID('DREV'); } - + public function loadRelationships() { - + if (!$this->getID()) { + $this->relationships = array(); + $this->related = array(); + $this->forbidden = array(); + return; + } + + $data = queryfx_all( + $this->establishConnection('r'), + 'SELECT * FROM %T WHERE revisionID = %d ORDER BY sequence', + self::RELATIONSHIP_TABLE, + $this->getID()); + + $related = array(); + $forbidden = array(); + + foreach ($data as $row) { + if ($row['forbidden']) { + $forbidden[] = $row; + } else { + $related[] = $row; + } + } + + $this->related = igroup($related, 'relation'); + $this->forbidden = igroup($related, 'relation'); + $this->relationships = igroup($data, 'relation'); + + return $this; } - + public function getReviewers() { - return array(); + return $this->getRelatedPHIDs(self::RELATION_REVIEWER); } - + public function getCCPHIDs() { - return array(); + return $this->getRelatedPHIDs(self::RELATION_SUBSCRIBED); + } + + private function getRelatedPHIDs($relation) { + if ($this->related === null) { + throw new Exception("Must load relationships!"); + } + + $related = idx($this->related, $relation, array()); + + return ipull($related, 'objectPHID'); + } + + public function getRawRelations($relation) { + return idx($this->relationships, $relation, array()); + } + + public function writeRelatedPHIDs( + $relation, + $phids, + $reason_phid, + $forbidden) { + + $conn_w = $this->establishConnection('w'); + + $sql = array(); + $phids = array_values($phids); + foreach ($phids as $key => $phid) { + $sql[] = qsprintf( + $conn_w, + '(%d, %s, %d, %s, %d)', + $this->getRevisionID(), + $phid, + $key, + $reason_phid, + $forbidden); + } + + $conn_w->openTransaction(); + queryfx( + $conn_w, + 'DELETE FROM %T WHERE revisionID = %d AND relation = %s + AND forbidden = %d + AND relatedPHID NOT IN (%Ls)', + self::RELATIONSHIP_TABLE, + $this->getID(), + $relation, + $forbidden, + $phids); + queryfx( + $conn_w, + 'INSERT INTO %T + (revisionID, relatedPHID, sequence, reason_phid, forbidden) + VALUES %Q + ON DUPLICATE KEY UPDATE sequence = VALUES(sequence)', + self::RELATIONSHIP_TABLE, + implode(', ', $sql)); + $conn_w->saveTransaction(); } } diff --git a/src/applications/differential/storage/revision/__init__.php b/src/applications/differential/storage/revision/__init__.php index 3ffc401e91..641a9e397b 100644 --- a/src/applications/differential/storage/revision/__init__.php +++ b/src/applications/differential/storage/revision/__init__.php @@ -7,6 +7,11 @@ phutil_require_module('phabricator', 'applications/differential/storage/base'); +phutil_require_module('phabricator', 'applications/phid/storage/phid'); +phutil_require_module('phabricator', 'storage/qsprintf'); +phutil_require_module('phabricator', 'storage/queryfx'); + +phutil_require_module('phutil', 'utils'); phutil_require_source('DifferentialRevision.php'); diff --git a/src/storage/connection/base/AphrontDatabaseConnection.php b/src/storage/connection/base/AphrontDatabaseConnection.php index f06769492f..5d7fd27e27 100644 --- a/src/storage/connection/base/AphrontDatabaseConnection.php +++ b/src/storage/connection/base/AphrontDatabaseConnection.php @@ -107,7 +107,7 @@ abstract class AphrontDatabaseConnection { self::$transactionShutdownRegistered = true; register_shutdown_function( array( - 'LiskConnection', + 'AphrontDatabaseConnection', 'shutdownTransactionStacks', )); }