diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1554,6 +1554,7 @@ 'PhabricatorEdgeGraph' => 'infrastructure/edges/util/PhabricatorEdgeGraph.php', 'PhabricatorEdgeQuery' => 'infrastructure/edges/query/PhabricatorEdgeQuery.php', 'PhabricatorEdgeTestCase' => 'infrastructure/edges/__tests__/PhabricatorEdgeTestCase.php', + 'PhabricatorEdgeType' => 'infrastructure/edges/constants/PhabricatorEdgeType.php', 'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php', 'PhabricatorEmailLoginController' => 'applications/auth/controller/PhabricatorEmailLoginController.php', 'PhabricatorEmailVerificationController' => 'applications/auth/controller/PhabricatorEmailVerificationController.php', @@ -1704,6 +1705,7 @@ 'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php', 'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php', 'PhabricatorKeyValueDatabaseCache' => 'applications/cache/PhabricatorKeyValueDatabaseCache.php', + 'PhabricatorLegacyEdgeType' => 'infrastructure/edges/constants/PhabricatorLegacyEdgeType.php', 'PhabricatorLegalpadConfigOptions' => 'applications/legalpad/config/PhabricatorLegalpadConfigOptions.php', 'PhabricatorLegalpadPHIDTypeDocument' => 'applications/legalpad/phid/PhabricatorLegalpadPHIDTypeDocument.php', 'PhabricatorLipsumArtist' => 'applications/lipsum/image/PhabricatorLipsumArtist.php', @@ -4393,6 +4395,7 @@ 'PhabricatorEdgeGraph' => 'AbstractDirectedGraph', 'PhabricatorEdgeQuery' => 'PhabricatorQuery', 'PhabricatorEdgeTestCase' => 'PhabricatorTestCase', + 'PhabricatorEdgeType' => 'Phobject', 'PhabricatorEditor' => 'Phobject', 'PhabricatorEmailLoginController' => 'PhabricatorAuthController', 'PhabricatorEmailVerificationController' => 'PhabricatorAuthController', @@ -4550,6 +4553,7 @@ 'PhabricatorIteratedMD5PasswordHasher' => 'PhabricatorPasswordHasher', 'PhabricatorJavelinLinter' => 'ArcanistLinter', 'PhabricatorKeyValueDatabaseCache' => 'PhutilKeyValueCache', + 'PhabricatorLegacyEdgeType' => 'PhabricatorEdgeType', 'PhabricatorLegalpadConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorLegalpadPHIDTypeDocument' => 'PhabricatorPHIDType', 'PhabricatorLipsumGenerateWorkflow' => 'PhabricatorLipsumManagementWorkflow', diff --git a/src/infrastructure/edges/constants/PhabricatorEdgeConfig.php b/src/infrastructure/edges/constants/PhabricatorEdgeConfig.php --- a/src/infrastructure/edges/constants/PhabricatorEdgeConfig.php +++ b/src/infrastructure/edges/constants/PhabricatorEdgeConfig.php @@ -78,6 +78,13 @@ const TYPE_OBJECT_NEEDS_SIGNATURE = 49; const TYPE_SIGNATURE_NEEDED_BY_OBJECT = 50; +/* !!! STOP !!! STOP !!! STOP !!! STOP !!! STOP !!! STOP !!! STOP !!! STOP !! */ + + // HEY! DO NOT ADD NEW CONSTANTS HERE! + // Instead, subclass PhabricatorEdgeType. + +/* !!! STOP !!! STOP !!! STOP !!! STOP !!! STOP !!! STOP !!! STOP !!! STOP !! */ + const TYPE_TEST_NO_CYCLE = 9000; const TYPE_PHOB_HAS_ASANATASK = 80001; @@ -89,6 +96,34 @@ const TYPE_PHOB_HAS_JIRAISSUE = 80004; const TYPE_JIRAISSUE_HAS_PHOB = 80005; + public static function getLegacyTypes($exclude) { + $consts = array_merge( + range(1, 50), + array(9000), + range(80000, 80005)); + $consts = array_diff($consts, $exclude); + + $map = array(); + foreach ($consts as $const) { + $prevent_cycles = self::shouldPreventCycles($const); + $inverse_constant = self::getInverse($const); + + $map[$const] = id(new PhabricatorLegacyEdgeType()) + ->setEdgeConstant($const) + ->setShouldPreventCycles($prevent_cycles) + ->setInverseEdgeConstant($inverse_constant) + ->setStrings( + array( + self::getAddStringForEdgeType($const), + self::getRemoveStringForEdgeType($const), + self::getEditStringForEdgeType($const), + self::getFeedStringForEdgeType($const), + )); + } + + return $map; + } + public static function getInverse($edge_type) { static $map = array( self::TYPE_TASK_HAS_COMMIT => self::TYPE_COMMIT_HAS_TASK, @@ -136,7 +171,7 @@ self::TYPE_DREV_HAS_COMMIT => self::TYPE_COMMIT_HAS_DREV, self::TYPE_COMMIT_HAS_DREV => self::TYPE_DREV_HAS_COMMIT, - self::TYPE_OBJECT_HAS_CONTRIBUTOR => self::TYPE_SUBSCRIBED_TO_OBJECT, + self::TYPE_OBJECT_HAS_CONTRIBUTOR => self::TYPE_CONTRIBUTED_TO_OBJECT, self::TYPE_CONTRIBUTED_TO_OBJECT => self::TYPE_OBJECT_HAS_CONTRIBUTOR, self::TYPE_TASK_HAS_MOCK => self::TYPE_MOCK_HAS_TASK, diff --git a/src/infrastructure/edges/constants/PhabricatorEdgeType.php b/src/infrastructure/edges/constants/PhabricatorEdgeType.php new file mode 100644 --- /dev/null +++ b/src/infrastructure/edges/constants/PhabricatorEdgeType.php @@ -0,0 +1,217 @@ +setAncestorClass(__CLASS__) + ->loadObjects(); + + $map = array(); + + + // TODO: Remove this once everything is migrated. + $exclude = mpull($types, 'getEdgeConstant'); + $map = PhabricatorEdgeConfig::getLegacyTypes($exclude); + unset($types['PhabricatorLegacyEdgeType']); + + + foreach ($types as $class => $type) { + $const = $type->getEdgeConstant(); + + if (!is_int($const) || ($const <= 0)) { + throw new Exception( + pht( + 'Edge type "%s" has an invalid edge constant. Edge constants '. + 'must be positive integers.', + $class)); + } + + if (isset($map[$const])) { + throw new Exception( + pht( + 'Two edge types ("%s", "%s") share the same edge constant '. + '(%d). Each edge type must have a unique constant.', + $class, + get_class($map[$const]), + $const)); + } + + $map[$const] = $type; + } + + // Check that all the inverse edge definitions actually make sense. If + // edge type A says B is its inverse, B must exist and say that A is its + // inverse. + + foreach ($map as $const => $type) { + $inverse = $type->getInverseEdgeConstant(); + if ($inverse === null) { + continue; + } + + if (empty($map[$inverse])) { + throw new Exception( + pht( + 'Edge type "%s" ("%d") defines an inverse type ("%d") which '. + 'does not exist.', + get_class($type), + $const, + $inverse)); + } + + $inverse_inverse = $map[$inverse]->getInverseEdgeConstant(); + if ($inverse_inverse !== $const) { + throw new Exception( + pht( + 'Edge type "%s" ("%d") defines an inverse type ("%d"), but that '. + 'inverse type defines a different type ("%d") as its '. + 'inverse.', + get_class($type), + $const, + $inverse, + $inverse_inverse)); + } + } + + $type_map = $map; + } + + return $type_map; + } + + + /** + * @task load + */ + public static function getByConst($const) { + $type = idx(self::getAllTypes(), $const); + + if (!$type) { + throw new Exception( + pht('Unknown edge constant "%s"!', $const)); + } + + return $type; + } + +} diff --git a/src/infrastructure/edges/constants/PhabricatorLegacyEdgeType.php b/src/infrastructure/edges/constants/PhabricatorLegacyEdgeType.php new file mode 100644 --- /dev/null +++ b/src/infrastructure/edges/constants/PhabricatorLegacyEdgeType.php @@ -0,0 +1,119 @@ +edgeConstant; + } + + public function getInverseEdgeConstant() { + return $this->inverseEdgeConstant; + } + + public function getShouldPreventCycles() { + return $this->shouldPreventCycles; + } + + public function setEdgeConstant($edge_constant) { + $this->edgeConstant = $edge_constant; + return $this; + } + + public function setInverseEdgeConstant($inverse_edge_constant) { + $this->inverseEdgeConstant = $inverse_edge_constant; + return $this; + } + + public function setShouldPreventCycles($should_prevent_cycles) { + $this->shouldPreventCycles = $should_prevent_cycles; + return $this; + } + + public function setStrings(array $strings) { + $this->strings = $strings; + return $this; + } + + private function getString($idx, array $argv) { + array_unshift($argv, idx($this->strings, $idx, '')); + + // TODO: Burn this class in a fire. Just hiding this from lint for now. + $pht_func = 'pht'; + return call_user_func_array($pht_func, $argv); + } + + public function getTransactionAddString( + $actor, + $add_count, + $add_edges) { + + $args = func_get_args(); + return $this->getString(0, $args); + } + + public function getTransactionRemoveString( + $actor, + $rem_count, + $rem_edges) { + + $args = func_get_args(); + return $this->getString(1, $args); + } + + public function getTransactionEditString( + $actor, + $total_count, + $add_count, + $add_edges, + $rem_count, + $rem_edges) { + + $args = func_get_args(); + return $this->getString(2, $args); + } + + public function getFeedAddString( + $actor, + $object, + $add_count, + $add_edges) { + + $args = func_get_args(); + return $this->getString(3, $args); + } + + public function getFeedRemoveString( + $actor, + $object, + $rem_count, + $rem_edges) { + + $args = func_get_args(); + return $this->getString(3, $args); + } + + public function getFeedEditString( + $actor, + $object, + $total_count, + $add_count, + $add_edges, + $rem_count, + $rem_edges) { + + $args = func_get_args(); + return $this->getString(3, $args); + } + +}