/** * @task load */ public static function getAllTypes() { static $type_map; if ($type_map === null) { $types = id(new PhutilSymbolLoader())->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 (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; }