Commit 7ed69966 authored by epriestley's avatar epriestley
Browse files

Provide basic infrastructure for moving PHIDs, Handles and Object Names to applications

Summary:
See discussion in T2715. Currently, PHIDs are all hard coded in the PHID application. In the long run, we need to move them out into actual applications.

A specific immediate issue is Releeph, which uses a very very old and very broken mechanism to inject PHIDs in a way that only sort of works.

Moving forward, every PHID type will be provided by a `PhabricatorPHIDType` subclass, which will manage loading it, etc.

This also moves toward cleaning up the "load objects by name" (where "name" means something like `D12`) code, which is an //enormous// mess and spread across at least 4-5 callsites.

Test Plan: Used `phid.lookup` and `phid.query` to load Slowvotes.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Differential Revision: https://secure.phabricator.com/D6502
parent 3742e0f4
......@@ -44,7 +44,7 @@ foreach ($comments as $comment) {
PhabricatorPHIDConstants::PHID_TYPE_XCMT);
$xaction_phid = PhabricatorPHID::generateNewPHID(
PhabricatorPHIDConstants::PHID_TYPE_XACT,
PhabricatorPHIDConstants::PHID_TYPE_POLL);
PhabricatorSlowvotePHIDTypePoll::TYPECONST);
$source = PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_LEGACY,
......
......@@ -1313,6 +1313,7 @@ phutil_register_library_map(array(
'PhabricatorObjectListView' => 'view/control/PhabricatorObjectListView.php',
'PhabricatorObjectMailReceiver' => 'applications/metamta/receiver/PhabricatorObjectMailReceiver.php',
'PhabricatorObjectMailReceiverTestCase' => 'applications/metamta/receiver/__tests__/PhabricatorObjectMailReceiverTestCase.php',
'PhabricatorObjectQuery' => 'applications/phid/query/PhabricatorObjectQuery.php',
'PhabricatorObjectSelectorDialog' => 'view/control/PhabricatorObjectSelectorDialog.php',
'PhabricatorOffsetPagedQuery' => 'infrastructure/query/PhabricatorOffsetPagedQuery.php',
'PhabricatorOwnerPathQuery' => 'applications/owners/query/PhabricatorOwnerPathQuery.php',
......@@ -1331,10 +1332,10 @@ phutil_register_library_map(array(
'PhabricatorOwnersPath' => 'applications/owners/storage/PhabricatorOwnersPath.php',
'PhabricatorPHDConfigOptions' => 'applications/config/option/PhabricatorPHDConfigOptions.php',
'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php',
'PhabricatorPHIDConfigOptions' => 'applications/phid/config/PhabricatorPHIDConfigOptions.php',
'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php',
'PhabricatorPHIDController' => 'applications/phid/controller/PhabricatorPHIDController.php',
'PhabricatorPHIDLookupController' => 'applications/phid/controller/PhabricatorPHIDLookupController.php',
'PhabricatorPHIDType' => 'applications/phid/type/PhabricatorPHIDType.php',
'PhabricatorPHPMailerConfigOptions' => 'applications/config/option/PhabricatorPHPMailerConfigOptions.php',
'PhabricatorPagedFormExample' => 'applications/uiexample/examples/PhabricatorPagedFormExample.php',
'PhabricatorPaste' => 'applications/paste/storage/PhabricatorPaste.php',
......@@ -1540,6 +1541,7 @@ phutil_register_library_map(array(
'PhabricatorSlowvoteEditor' => 'applications/slowvote/editor/PhabricatorSlowvoteEditor.php',
'PhabricatorSlowvoteListController' => 'applications/slowvote/controller/PhabricatorSlowvoteListController.php',
'PhabricatorSlowvoteOption' => 'applications/slowvote/storage/PhabricatorSlowvoteOption.php',
'PhabricatorSlowvotePHIDTypePoll' => 'applications/slowvote/phid/PhabricatorSlowvotePHIDTypePoll.php',
'PhabricatorSlowvotePoll' => 'applications/slowvote/storage/PhabricatorSlowvotePoll.php',
'PhabricatorSlowvotePollController' => 'applications/slowvote/controller/PhabricatorSlowvotePollController.php',
'PhabricatorSlowvoteQuery' => 'applications/slowvote/query/PhabricatorSlowvoteQuery.php',
......@@ -3275,6 +3277,7 @@ phutil_register_library_map(array(
'PhabricatorObjectListView' => 'AphrontView',
'PhabricatorObjectMailReceiver' => 'PhabricatorMailReceiver',
'PhabricatorObjectMailReceiverTestCase' => 'PhabricatorTestCase',
'PhabricatorObjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery',
'PhabricatorOwnersConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorOwnersController' => 'PhabricatorController',
......@@ -3293,7 +3296,6 @@ phutil_register_library_map(array(
'PhabricatorOwnersPackageTestCase' => 'PhabricatorTestCase',
'PhabricatorOwnersPath' => 'PhabricatorOwnersDAO',
'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorPHIDConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorPHIDController' => 'PhabricatorController',
'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController',
'PhabricatorPHPMailerConfigOptions' => 'PhabricatorApplicationConfigOptions',
......@@ -3513,6 +3515,7 @@ phutil_register_library_map(array(
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
),
'PhabricatorSlowvoteOption' => 'PhabricatorSlowvoteDAO',
'PhabricatorSlowvotePHIDTypePoll' => 'PhabricatorPHIDType',
'PhabricatorSlowvotePoll' =>
array(
0 => 'PhabricatorSlowvoteDAO',
......
......@@ -141,6 +141,13 @@ final class PhabricatorSetupCheckExtraConfig extends PhabricatorSetupCheck {
$ancient_config = array_fill_keys($auth_config, $reason_auth);
$ancient_config += array(
'phid.external-loaders' =>
pht(
'External loaders have been replaced. Extend `PhabricatorPHIDType` '.
'to implement new PHID and handle types.'),
);
return $ancient_config;
}
}
......@@ -99,6 +99,11 @@ final class PhabricatorObjectHandle {
}
public function getTypeName() {
$types = PhabricatorPHIDType::getAllTypes();
if (isset($types[$this->getType()])) {
return $types[$this->getType()]->getTypeName();
}
static $map = array(
PhabricatorPHIDConstants::PHID_TYPE_USER => 'User',
PhabricatorPHIDConstants::PHID_TYPE_TASK => 'Task',
......@@ -116,7 +121,6 @@ final class PhabricatorObjectHandle {
PhabricatorPHIDConstants::PHID_TYPE_PSTE => 'Paste',
PhabricatorPHIDConstants::PHID_TYPE_PROJ => 'Project',
PhabricatorPHIDConstants::PHID_TYPE_LEGD => 'Legalpad Document',
PhabricatorPHIDConstants::PHID_TYPE_POLL => 'Slowvote',
);
return idx($map, $this->getType(), $this->getType());
......
......@@ -15,7 +15,6 @@ final class PhabricatorPHIDConstants {
const PHID_TYPE_OPKG = 'OPKG';
const PHID_TYPE_PSTE = 'PSTE';
const PHID_TYPE_STRY = 'STRY';
const PHID_TYPE_POLL = 'POLL';
const PHID_TYPE_WIKI = 'WIKI';
const PHID_TYPE_APRJ = 'APRJ';
const PHID_TYPE_ACMT = 'ACMT';
......
......@@ -34,6 +34,16 @@ final class ConduitAPI_phid_lookup_Method
}
}
$query = id(new PhabricatorObjectQuery())
->setViewer($request->getUser())
->withNames($names);
$query->execute();
$objects = $query->getNamedResults();
foreach ($objects as $name => $object) {
$phids[$name] = $object->getPHID();
}
$handles = id(new PhabricatorObjectHandleData($phids))
->setViewer($request->getUser())
->loadHandles();
......
<?php
final class PhabricatorPHIDConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht("PHID");
}
public function getDescription() {
return pht("Configure PHID generation and lookup.");
}
public function getOptions() {
return array(
$this->newOption(
'phid.external-loaders',
'wild',
null)
->setDescription(
pht(
'For each new 4-char PHID type, point to an external loader for '.
'that type.')),
);
}
}
......@@ -22,9 +22,17 @@ final class PhabricatorObjectHandleData {
}
public function loadObjects() {
$types = phid_group_by_type($this->phids);
$phids = array_fuse($this->phids);
$objects = id(new PhabricatorObjectQuery())
->setViewer($this->viewer)
->withPHIDs($phids)
->execute();
$objects = array();
// For objects which don't support PhabricatorPHIDType yet, load them the
// old way.
$phids = array_diff_key($phids, array_keys($objects));
$types = phid_group_by_type($phids);
foreach ($types as $type => $phids) {
$objects += $this->loadObjectsOfType($type, $phids);
}
......@@ -142,11 +150,6 @@ final class PhabricatorObjectHandleData {
->loadAllWhere('phid IN (%Ls)', $phids);
return mpull($images, null, 'getPHID');
case PhabricatorPHIDConstants::PHID_TYPE_POLL:
$polls = id(new PhabricatorSlowvotePoll())
->loadAllWhere('phid IN (%Ls)', $phids);
return mpull($polls, null, 'getPHID');
case PhabricatorPHIDConstants::PHID_TYPE_XACT:
$subtypes = array();
foreach ($phids as $phid) {
......@@ -238,16 +241,13 @@ final class PhabricatorObjectHandleData {
}
public function loadHandles() {
$objects = $this->loadObjects();
$types = phid_group_by_type($this->phids);
$handles = array();
$external_loaders = PhabricatorEnv::getEnvConfig('phid.external-loaders');
foreach ($types as $type => $phids) {
$objects = $this->loadObjectsOfType($type, $phids);
switch ($type) {
case PhabricatorPHIDConstants::PHID_TYPE_MAGIC:
......@@ -674,7 +674,7 @@ final class PhabricatorObjectHandleData {
break;
case PhabricatorPHIDConstants::PHID_TYPE_POLL:
case PhabricatorSlowvotePHIDTypePoll::TYPECONST:
foreach ($phids as $phid) {
$handle = new PhabricatorObjectHandle();
$handle->setPHID($phid);
......@@ -807,20 +807,6 @@ final class PhabricatorObjectHandleData {
default:
$loader = null;
if (isset($external_loaders[$type])) {
$loader = $external_loaders[$type];
} else if (isset($external_loaders['*'])) {
$loader = $external_loaders['*'];
}
if ($loader) {
$object = newv($loader, array());
assert_instances_of(array($type => $object), 'ObjectHandleLoader');
$handles += $object->loadHandles($phids);
break;
}
foreach ($phids as $phid) {
$handle = new PhabricatorObjectHandle();
$handle->setType($type);
......
<?php
final class PhabricatorObjectQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $phids;
private $names;
private $namedResults;
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withNames(array $names) {
$this->names = $names;
return $this;
}
public function loadPage() {
$types = PhabricatorPHIDType::getAllTypes();
$this->namedResults = $this->loadObjectsByName($types);
return $this->loadObjectsByPHID($types) +
mpull($this->namedResults, null, 'getPHID');
}
public function getNamedResults() {
if ($this->namedResults === null) {
throw new Exception("Call execute() before getNamedResults()!");
}
return $this->namedResults;
}
private function loadObjectsByName(array $types) {
$names = $this->names;
if (!$names) {
return array();
}
$groups = array();
foreach ($names as $name) {
foreach ($types as $type => $type_impl) {
if (!$type_impl->canLoadNamedObject($name)) {
continue;
}
$groups[$type][] = $name;
break;
}
}
$results = array();
foreach ($groups as $type => $group) {
$results += $types[$type]->loadNamedObjects($this, $group);
}
return $results;
}
private function loadObjectsByPHID(array $types) {
$phids = $this->phids;
if (!$phids) {
return array();
}
$groups = array();
foreach ($phids as $phid) {
$type = phid_get_type($phid);
$groups[$type][] = $phid;
}
$results = array();
foreach ($groups as $type => $group) {
if (isset($types[$type])) {
$objects = $types[$type]->loadObjects($this, $group);
$results += mpull($objects, null, 'getPHID');
}
}
return $results;
}
}
......@@ -25,6 +25,18 @@ final class PhabricatorPHID {
}
public static function fromObjectName($name, PhabricatorUser $viewer) {
$query = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withNames(array($name));
$query->execute();
$objects = $query->getNamedResults();
if ($objects) {
return head($objects)->getPHID();
}
/// TODO: Destroy this legacy stuff.
$object = null;
$match = null;
if (preg_match('/^PHID-[A-Z]+-.{20}$/', $name)) {
......
<?php
abstract class PhabricatorPHIDType {
abstract public function getTypeConstant();
abstract public function getTypeName();
public function newObject() {
return null;
}
abstract public function loadObjects(
PhabricatorObjectQuery $query,
array $phids);
abstract public function loadHandles(array $phids, array $objects);
public function canLoadNamedObject($name) {
return false;
}
public function loadNamedObjects(
PhabricatorObjectQuery $query,
array $names) {
throw new Exception("Not implemented!");
}
public static function getAllTypes() {
static $types;
if ($types === null) {
$objects = id(new PhutilSymbolLoader())
->setAncestorClass(__CLASS__)
->loadObjects();
$map = array();
$original = array();
foreach ($objects as $object) {
$type = $object->getTypeConstant();
if (isset($map[$type])) {
$that_class = $original[$type];
$this_class = get_class($object);
throw new Exception(
"Two PhabricatorPHIDType classes ({$that_class}, {$this_class}) ".
"both handle PHID type '{$type}'. A type may be handled by only ".
"one class.");
}
$original[$type] = get_class($object);
$map[$type] = $object;
}
$types = $map;
}
return $types;
}
}
<?php
final class PhabricatorSlowvotePHIDTypePoll extends PhabricatorPHIDType {
const TYPECONST = 'POLL';
public function getTypeConstant() {
return self::TYPECONST;
}
public function getTypeName() {
return pht('Slowvote Poll');
}
public function newObject() {
return new PhabricatorSlowvotePoll();
}
public function loadObjects(
PhabricatorObjectQuery $query,
array $phids) {
return id(new PhabricatorSlowvoteQuery())
->setViewer($query->getViewer())
->withPHIDs($phids)
->execute();
}
public function loadHandles(array $phids, array $objects) {
throw new Exception("TODO");
}
public function canLoadNamedObject($name) {
return preg_match('/^V\d*[1-9]\d*$/i', $name);
}
public function loadNamedObjects(
PhabricatorObjectQuery $query,
array $names) {
$id_map = array();
foreach ($names as $name) {
$id = (int)substr($name, 1);
$id_map[$id][] = $name;
}
$objects = id(new PhabricatorSlowvoteQuery())
->setViewer($query->getViewer())
->withIDs(array_keys($id_map))
->execute();
$results = array();
foreach ($objects as $id => $object) {
foreach (idx($id_map, $id, array()) as $name) {
$results[$name] = $object;
}
}
return $results;
}
}
......@@ -36,7 +36,7 @@ final class PhabricatorSlowvotePoll extends PhabricatorSlowvoteDAO
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(
PhabricatorPHIDConstants::PHID_TYPE_POLL);
PhabricatorSlowvotePHIDTypePoll::TYPECONST);
}
public function getOptions() {
......
......@@ -13,7 +13,7 @@ final class PhabricatorSlowvoteTransaction
}
public function getApplicationTransactionType() {
return PhabricatorPHIDConstants::PHID_TYPE_POLL;
return PhabricatorSlowvotePHIDTypePoll::TYPECONST;
}
public function getApplicationTransactionCommentObject() {
......
......@@ -144,6 +144,15 @@ final class PhabricatorEdgeConfig extends PhabricatorEdgeConstants {
}
public static function establishConnection($phid_type, $conn_type) {
$map = PhabricatorPHIDType::getAllTypes();
if (isset($map[$phid_type])) {
$type = $map[$phid_type];
$object = $type->newObject();
if ($object) {
return $object->establishConnection($conn_type);
}
}
static $class_map = array(
PhabricatorPHIDConstants::PHID_TYPE_TASK => 'ManiphestTask',
PhabricatorPHIDConstants::PHID_TYPE_CMIT => 'PhabricatorRepository',
......@@ -167,7 +176,6 @@ final class PhabricatorEdgeConfig extends PhabricatorEdgeConstants {
PhabricatorPHIDConstants::PHID_TYPE_CHRG => 'PhortuneCharge',
PhabricatorPHIDConstants::PHID_TYPE_XOBJ => 'DoorkeeperExternalObject',
PhabricatorPHIDConstants::PHID_TYPE_LEGD => 'LegalpadDocument',
PhabricatorPHIDConstants::PHID_TYPE_POLL => 'PhabricatorSlowvotePoll',
);
$class = idx($class_map, $phid_type);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment