diff --git a/src/applications/differential/phid/DifferentialPHIDTypeRevision.php b/src/applications/differential/phid/DifferentialPHIDTypeRevision.php --- a/src/applications/differential/phid/DifferentialPHIDTypeRevision.php +++ b/src/applications/differential/phid/DifferentialPHIDTypeRevision.php @@ -12,6 +12,10 @@ return pht('Revision'); } + public function getPHIDTypeApplicationClass() { + return 'PhabricatorApplicationDifferential'; + } + public function newObject() { return new DifferentialRevision(); } diff --git a/src/applications/maniphest/phid/ManiphestPHIDTypeTask.php b/src/applications/maniphest/phid/ManiphestPHIDTypeTask.php --- a/src/applications/maniphest/phid/ManiphestPHIDTypeTask.php +++ b/src/applications/maniphest/phid/ManiphestPHIDTypeTask.php @@ -12,6 +12,10 @@ return pht('Task'); } + public function getPHIDTypeApplicationClass() { + return 'PhabricatorApplicationManiphest'; + } + public function newObject() { return new ManiphestTask(); } diff --git a/src/applications/people/phid/PhabricatorPeoplePHIDTypeUser.php b/src/applications/people/phid/PhabricatorPeoplePHIDTypeUser.php --- a/src/applications/people/phid/PhabricatorPeoplePHIDTypeUser.php +++ b/src/applications/people/phid/PhabricatorPeoplePHIDTypeUser.php @@ -12,6 +12,10 @@ return pht('User'); } + public function getPHIDTypeApplicationClass() { + return 'PhabricatorApplicationPeople'; + } + public function getTypeIcon() { return 'policy-all'; } diff --git a/src/applications/phid/type/PhabricatorPHIDType.php b/src/applications/phid/type/PhabricatorPHIDType.php --- a/src/applications/phid/type/PhabricatorPHIDType.php +++ b/src/applications/phid/type/PhabricatorPHIDType.php @@ -13,6 +13,20 @@ return null; } + + /** + * Get the class name for the application this type belongs to. + * + * @return string|null Class name of the corresponding application, or null + * if the type is not bound to an application. + */ + public function getPHIDTypeApplicationClass() { + // TODO: Some day this should probably be abstract, but for now it only + // affects global search and there's no real burning need to go classify + // every PHID type. + return null; + } + /** * Build a @{class:PhabricatorPolicyAwareQuery} to load objects of this type * by PHID. @@ -103,6 +117,15 @@ throw new Exception("Not implemented!"); } + + /** + * Get all known PHID types. + * + * To get PHID types a given user has access to, see + * @{method:getAllInstalledTypes}. + * + * @return dict Map of type constants to types. + */ public static function getAllTypes() { static $types; if ($types === null) { @@ -133,4 +156,48 @@ return $types; } + + /** + * Get all PHID types of applications installed for a given viewer. + * + * @param PhabricatorUser Viewing user. + * @return dict Map of constants to installed + * types. + */ + public static function getAllInstalledTypes(PhabricatorUser $viewer) { + $all_types = self::getAllTypes(); + + $installed_types = array(); + + $app_classes = array(); + foreach ($all_types as $key => $type) { + $app_class = $type->getPHIDTypeApplicationClass(); + + if ($app_class === null) { + // If the PHID type isn't bound to an application, include it as + // installed. + $installed_types[$key] = $type; + continue; + } + + // Otherwise, we need to check if this application is installed before + // including the PHID type. + $app_classes[$app_class][$key] = $type; + } + + if ($app_classes) { + $apps = id(new PhabricatorApplicationQuery()) + ->setViewer($viewer) + ->withInstalled(true) + ->withClasses(array_keys($app_classes)) + ->execute(); + + foreach ($apps as $app_class => $app) { + $installed_types += $app_classes[$app_class]; + } + } + + return $installed_types; + } + } diff --git a/src/applications/pholio/phid/PholioPHIDTypeMock.php b/src/applications/pholio/phid/PholioPHIDTypeMock.php --- a/src/applications/pholio/phid/PholioPHIDTypeMock.php +++ b/src/applications/pholio/phid/PholioPHIDTypeMock.php @@ -12,6 +12,10 @@ return pht('Mock'); } + public function getPHIDTypeApplicationClass() { + return 'PhabricatorApplicationPholio'; + } + public function newObject() { return new PholioMock(); } diff --git a/src/applications/phriction/phid/PhrictionPHIDTypeDocument.php b/src/applications/phriction/phid/PhrictionPHIDTypeDocument.php --- a/src/applications/phriction/phid/PhrictionPHIDTypeDocument.php +++ b/src/applications/phriction/phid/PhrictionPHIDTypeDocument.php @@ -12,6 +12,10 @@ return pht('Wiki Document'); } + public function getPHIDTypeApplicationClass() { + return 'PhabricatorApplicationPhriction'; + } + public function newObject() { return new PhrictionDocument(); } diff --git a/src/applications/ponder/phid/PonderPHIDTypeQuestion.php b/src/applications/ponder/phid/PonderPHIDTypeQuestion.php --- a/src/applications/ponder/phid/PonderPHIDTypeQuestion.php +++ b/src/applications/ponder/phid/PonderPHIDTypeQuestion.php @@ -12,6 +12,10 @@ return pht('Question'); } + public function getPHIDTypeApplicationClass() { + return 'PhabricatorApplicationPonder'; + } + public function newObject() { return new PonderQuestion(); } diff --git a/src/applications/project/phid/PhabricatorProjectPHIDTypeProject.php b/src/applications/project/phid/PhabricatorProjectPHIDTypeProject.php --- a/src/applications/project/phid/PhabricatorProjectPHIDTypeProject.php +++ b/src/applications/project/phid/PhabricatorProjectPHIDTypeProject.php @@ -12,6 +12,10 @@ return pht('Project'); } + public function getPHIDTypeApplicationClass() { + return 'PhabricatorApplicationProject'; + } + public function getTypeIcon() { return 'policy-project'; } diff --git a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeCommit.php b/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeCommit.php --- a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeCommit.php +++ b/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeCommit.php @@ -12,6 +12,10 @@ return pht('Commit'); } + public function getPHIDTypeApplicationClass() { + return 'PhabricatorApplicationDiffusion'; + } + public function newObject() { return new PhabricatorRepositoryCommit(); } diff --git a/src/applications/search/query/PhabricatorSearchApplicationSearchEngine.php b/src/applications/search/query/PhabricatorSearchApplicationSearchEngine.php --- a/src/applications/search/query/PhabricatorSearchApplicationSearchEngine.php +++ b/src/applications/search/query/PhabricatorSearchApplicationSearchEngine.php @@ -96,7 +96,7 @@ $type_values = $saved->getParameter('types', array()); $type_values = array_fuse($type_values); - $types = self::getIndexableDocumentTypes(); + $types = self::getIndexableDocumentTypes($this->requireViewer()); $types_control = id(new AphrontFormCheckboxControl()) ->setLabel(pht('Document Types')); @@ -190,18 +190,21 @@ return parent::buildSavedQueryFromBuiltin($query_key); } - public static function getIndexableDocumentTypes() { + public static function getIndexableDocumentTypes( + PhabricatorUser $viewer = null) { + // TODO: This is inelegant and not very efficient, but gets us reasonable // results. It would be nice to do this more elegantly. - // TODO: We should hide types associated with applications the user can - // not access. There's no reasonable way to do this right now. - $indexers = id(new PhutilSymbolLoader()) ->setAncestorClass('PhabricatorSearchDocumentIndexer') ->loadObjects(); - $types = PhabricatorPHIDType::getAllTypes(); + if ($viewer) { + $types = PhabricatorPHIDType::getAllInstalledTypes($viewer); + } else { + $types = PhabricatorPHIDType::getAllTypes(); + } $results = array(); foreach ($types as $type) {