mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-23 23:32:40 +01:00
Implement a rough initial version of ApplicationSearch-driven Conduit read endpoints
Summary: Ref T9964. See that task for some context and discussion. Ref T7715, which has the bigger picture here. Basically, I want Conduit read endpoints to be full-power, ApplicationSearch-driven endpoints, so that applications can: - Write one EditEngine and get web + conduit writes for free. - Write one SearchEngine and get web + conduit reads for free. I previously made some steps toward this, but this puts more of the structure in place. Test Plan: Viewed API console endpoint and read 20 pages of docs: {F1021961} Made various calls: with query keys, constraints, pagination, and limits. Viewed new {nav Config > Modules} page. Reviewers: chad Reviewed By: chad Maniphest Tasks: T7715, T9964 Differential Revision: https://secure.phabricator.com/D14743
This commit is contained in:
parent
ab7d3caa00
commit
4ec6990ca7
13 changed files with 950 additions and 1 deletions
|
@ -236,6 +236,7 @@ phutil_register_library_map(array(
|
||||||
'ConduitMethodNotFoundException' => 'applications/conduit/protocol/exception/ConduitMethodNotFoundException.php',
|
'ConduitMethodNotFoundException' => 'applications/conduit/protocol/exception/ConduitMethodNotFoundException.php',
|
||||||
'ConduitPingConduitAPIMethod' => 'applications/conduit/method/ConduitPingConduitAPIMethod.php',
|
'ConduitPingConduitAPIMethod' => 'applications/conduit/method/ConduitPingConduitAPIMethod.php',
|
||||||
'ConduitQueryConduitAPIMethod' => 'applications/conduit/method/ConduitQueryConduitAPIMethod.php',
|
'ConduitQueryConduitAPIMethod' => 'applications/conduit/method/ConduitQueryConduitAPIMethod.php',
|
||||||
|
'ConduitResultSearchEngineExtension' => 'applications/conduit/query/ConduitResultSearchEngineExtension.php',
|
||||||
'ConduitSSHWorkflow' => 'applications/conduit/ssh/ConduitSSHWorkflow.php',
|
'ConduitSSHWorkflow' => 'applications/conduit/ssh/ConduitSSHWorkflow.php',
|
||||||
'ConduitTokenGarbageCollector' => 'applications/conduit/garbagecollector/ConduitTokenGarbageCollector.php',
|
'ConduitTokenGarbageCollector' => 'applications/conduit/garbagecollector/ConduitTokenGarbageCollector.php',
|
||||||
'ConpherenceColumnViewController' => 'applications/conpherence/controller/ConpherenceColumnViewController.php',
|
'ConpherenceColumnViewController' => 'applications/conpherence/controller/ConpherenceColumnViewController.php',
|
||||||
|
@ -1557,6 +1558,7 @@ phutil_register_library_map(array(
|
||||||
'PasteMailReceiver' => 'applications/paste/mail/PasteMailReceiver.php',
|
'PasteMailReceiver' => 'applications/paste/mail/PasteMailReceiver.php',
|
||||||
'PasteQueryConduitAPIMethod' => 'applications/paste/conduit/PasteQueryConduitAPIMethod.php',
|
'PasteQueryConduitAPIMethod' => 'applications/paste/conduit/PasteQueryConduitAPIMethod.php',
|
||||||
'PasteReplyHandler' => 'applications/paste/mail/PasteReplyHandler.php',
|
'PasteReplyHandler' => 'applications/paste/mail/PasteReplyHandler.php',
|
||||||
|
'PasteSearchConduitAPIMethod' => 'applications/paste/conduit/PasteSearchConduitAPIMethod.php',
|
||||||
'PeopleBrowseUserDirectoryCapability' => 'applications/people/capability/PeopleBrowseUserDirectoryCapability.php',
|
'PeopleBrowseUserDirectoryCapability' => 'applications/people/capability/PeopleBrowseUserDirectoryCapability.php',
|
||||||
'PeopleCreateUsersCapability' => 'applications/people/capability/PeopleCreateUsersCapability.php',
|
'PeopleCreateUsersCapability' => 'applications/people/capability/PeopleCreateUsersCapability.php',
|
||||||
'PeopleUserLogGarbageCollector' => 'applications/people/garbagecollector/PeopleUserLogGarbageCollector.php',
|
'PeopleUserLogGarbageCollector' => 'applications/people/garbagecollector/PeopleUserLogGarbageCollector.php',
|
||||||
|
@ -1880,6 +1882,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/PhabricatorConduitMethodCallLog.php',
|
'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/PhabricatorConduitMethodCallLog.php',
|
||||||
'PhabricatorConduitMethodQuery' => 'applications/conduit/query/PhabricatorConduitMethodQuery.php',
|
'PhabricatorConduitMethodQuery' => 'applications/conduit/query/PhabricatorConduitMethodQuery.php',
|
||||||
'PhabricatorConduitRequestExceptionHandler' => 'aphront/handler/PhabricatorConduitRequestExceptionHandler.php',
|
'PhabricatorConduitRequestExceptionHandler' => 'aphront/handler/PhabricatorConduitRequestExceptionHandler.php',
|
||||||
|
'PhabricatorConduitResultInterface' => 'applications/conduit/interface/PhabricatorConduitResultInterface.php',
|
||||||
'PhabricatorConduitSearchEngine' => 'applications/conduit/query/PhabricatorConduitSearchEngine.php',
|
'PhabricatorConduitSearchEngine' => 'applications/conduit/query/PhabricatorConduitSearchEngine.php',
|
||||||
'PhabricatorConduitTestCase' => '__tests__/PhabricatorConduitTestCase.php',
|
'PhabricatorConduitTestCase' => '__tests__/PhabricatorConduitTestCase.php',
|
||||||
'PhabricatorConduitToken' => 'applications/conduit/storage/PhabricatorConduitToken.php',
|
'PhabricatorConduitToken' => 'applications/conduit/storage/PhabricatorConduitToken.php',
|
||||||
|
@ -2364,6 +2367,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorLipsumManagementWorkflow' => 'applications/lipsum/management/PhabricatorLipsumManagementWorkflow.php',
|
'PhabricatorLipsumManagementWorkflow' => 'applications/lipsum/management/PhabricatorLipsumManagementWorkflow.php',
|
||||||
'PhabricatorLipsumMondrianArtist' => 'applications/lipsum/image/PhabricatorLipsumMondrianArtist.php',
|
'PhabricatorLipsumMondrianArtist' => 'applications/lipsum/image/PhabricatorLipsumMondrianArtist.php',
|
||||||
'PhabricatorLiskDAO' => 'infrastructure/storage/lisk/PhabricatorLiskDAO.php',
|
'PhabricatorLiskDAO' => 'infrastructure/storage/lisk/PhabricatorLiskDAO.php',
|
||||||
|
'PhabricatorLiskSearchEngineExtension' => 'applications/search/engineextension/PhabricatorLiskSearchEngineExtension.php',
|
||||||
'PhabricatorLiskSerializer' => 'infrastructure/storage/lisk/PhabricatorLiskSerializer.php',
|
'PhabricatorLiskSerializer' => 'infrastructure/storage/lisk/PhabricatorLiskSerializer.php',
|
||||||
'PhabricatorListFilterUIExample' => 'applications/uiexample/examples/PhabricatorListFilterUIExample.php',
|
'PhabricatorListFilterUIExample' => 'applications/uiexample/examples/PhabricatorListFilterUIExample.php',
|
||||||
'PhabricatorLocalDiskFileStorageEngine' => 'applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php',
|
'PhabricatorLocalDiskFileStorageEngine' => 'applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php',
|
||||||
|
@ -2745,6 +2749,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPolicyQuery' => 'applications/policy/query/PhabricatorPolicyQuery.php',
|
'PhabricatorPolicyQuery' => 'applications/policy/query/PhabricatorPolicyQuery.php',
|
||||||
'PhabricatorPolicyRequestExceptionHandler' => 'aphront/handler/PhabricatorPolicyRequestExceptionHandler.php',
|
'PhabricatorPolicyRequestExceptionHandler' => 'aphront/handler/PhabricatorPolicyRequestExceptionHandler.php',
|
||||||
'PhabricatorPolicyRule' => 'applications/policy/rule/PhabricatorPolicyRule.php',
|
'PhabricatorPolicyRule' => 'applications/policy/rule/PhabricatorPolicyRule.php',
|
||||||
|
'PhabricatorPolicySearchEngineExtension' => 'applications/policy/engineextension/PhabricatorPolicySearchEngineExtension.php',
|
||||||
'PhabricatorPolicyTestCase' => 'applications/policy/__tests__/PhabricatorPolicyTestCase.php',
|
'PhabricatorPolicyTestCase' => 'applications/policy/__tests__/PhabricatorPolicyTestCase.php',
|
||||||
'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php',
|
'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php',
|
||||||
'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php',
|
'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php',
|
||||||
|
@ -2980,6 +2985,9 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSearchDocumentTypeDatasource' => 'applications/search/typeahead/PhabricatorSearchDocumentTypeDatasource.php',
|
'PhabricatorSearchDocumentTypeDatasource' => 'applications/search/typeahead/PhabricatorSearchDocumentTypeDatasource.php',
|
||||||
'PhabricatorSearchEditController' => 'applications/search/controller/PhabricatorSearchEditController.php',
|
'PhabricatorSearchEditController' => 'applications/search/controller/PhabricatorSearchEditController.php',
|
||||||
'PhabricatorSearchEngine' => 'applications/search/engine/PhabricatorSearchEngine.php',
|
'PhabricatorSearchEngine' => 'applications/search/engine/PhabricatorSearchEngine.php',
|
||||||
|
'PhabricatorSearchEngineAPIMethod' => 'applications/search/engine/PhabricatorSearchEngineAPIMethod.php',
|
||||||
|
'PhabricatorSearchEngineExtension' => 'applications/search/engineextension/PhabricatorSearchEngineExtension.php',
|
||||||
|
'PhabricatorSearchEngineExtensionModule' => 'applications/search/engineextension/PhabricatorSearchEngineExtensionModule.php',
|
||||||
'PhabricatorSearchEngineTestCase' => 'applications/search/engine/__tests__/PhabricatorSearchEngineTestCase.php',
|
'PhabricatorSearchEngineTestCase' => 'applications/search/engine/__tests__/PhabricatorSearchEngineTestCase.php',
|
||||||
'PhabricatorSearchField' => 'applications/search/field/PhabricatorSearchField.php',
|
'PhabricatorSearchField' => 'applications/search/field/PhabricatorSearchField.php',
|
||||||
'PhabricatorSearchHovercardController' => 'applications/search/controller/PhabricatorSearchHovercardController.php',
|
'PhabricatorSearchHovercardController' => 'applications/search/controller/PhabricatorSearchHovercardController.php',
|
||||||
|
@ -3067,6 +3075,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSpacesNoAccessController' => 'applications/spaces/controller/PhabricatorSpacesNoAccessController.php',
|
'PhabricatorSpacesNoAccessController' => 'applications/spaces/controller/PhabricatorSpacesNoAccessController.php',
|
||||||
'PhabricatorSpacesRemarkupRule' => 'applications/spaces/remarkup/PhabricatorSpacesRemarkupRule.php',
|
'PhabricatorSpacesRemarkupRule' => 'applications/spaces/remarkup/PhabricatorSpacesRemarkupRule.php',
|
||||||
'PhabricatorSpacesSchemaSpec' => 'applications/spaces/storage/PhabricatorSpacesSchemaSpec.php',
|
'PhabricatorSpacesSchemaSpec' => 'applications/spaces/storage/PhabricatorSpacesSchemaSpec.php',
|
||||||
|
'PhabricatorSpacesSearchEngineExtension' => 'applications/spaces/engineextension/PhabricatorSpacesSearchEngineExtension.php',
|
||||||
'PhabricatorSpacesSearchField' => 'applications/spaces/searchfield/PhabricatorSpacesSearchField.php',
|
'PhabricatorSpacesSearchField' => 'applications/spaces/searchfield/PhabricatorSpacesSearchField.php',
|
||||||
'PhabricatorSpacesTestCase' => 'applications/spaces/__tests__/PhabricatorSpacesTestCase.php',
|
'PhabricatorSpacesTestCase' => 'applications/spaces/__tests__/PhabricatorSpacesTestCase.php',
|
||||||
'PhabricatorSpacesViewController' => 'applications/spaces/controller/PhabricatorSpacesViewController.php',
|
'PhabricatorSpacesViewController' => 'applications/spaces/controller/PhabricatorSpacesViewController.php',
|
||||||
|
@ -4063,6 +4072,7 @@ phutil_register_library_map(array(
|
||||||
'ConduitMethodNotFoundException' => 'ConduitException',
|
'ConduitMethodNotFoundException' => 'ConduitException',
|
||||||
'ConduitPingConduitAPIMethod' => 'ConduitAPIMethod',
|
'ConduitPingConduitAPIMethod' => 'ConduitAPIMethod',
|
||||||
'ConduitQueryConduitAPIMethod' => 'ConduitAPIMethod',
|
'ConduitQueryConduitAPIMethod' => 'ConduitAPIMethod',
|
||||||
|
'ConduitResultSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
|
||||||
'ConduitSSHWorkflow' => 'PhabricatorSSHWorkflow',
|
'ConduitSSHWorkflow' => 'PhabricatorSSHWorkflow',
|
||||||
'ConduitTokenGarbageCollector' => 'PhabricatorGarbageCollector',
|
'ConduitTokenGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||||
'ConpherenceColumnViewController' => 'ConpherenceController',
|
'ConpherenceColumnViewController' => 'ConpherenceController',
|
||||||
|
@ -5577,6 +5587,7 @@ phutil_register_library_map(array(
|
||||||
'PasteMailReceiver' => 'PhabricatorObjectMailReceiver',
|
'PasteMailReceiver' => 'PhabricatorObjectMailReceiver',
|
||||||
'PasteQueryConduitAPIMethod' => 'PasteConduitAPIMethod',
|
'PasteQueryConduitAPIMethod' => 'PasteConduitAPIMethod',
|
||||||
'PasteReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
|
'PasteReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
|
||||||
|
'PasteSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
||||||
'PeopleBrowseUserDirectoryCapability' => 'PhabricatorPolicyCapability',
|
'PeopleBrowseUserDirectoryCapability' => 'PhabricatorPolicyCapability',
|
||||||
'PeopleCreateUsersCapability' => 'PhabricatorPolicyCapability',
|
'PeopleCreateUsersCapability' => 'PhabricatorPolicyCapability',
|
||||||
'PeopleUserLogGarbageCollector' => 'PhabricatorGarbageCollector',
|
'PeopleUserLogGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||||
|
@ -5962,6 +5973,7 @@ phutil_register_library_map(array(
|
||||||
),
|
),
|
||||||
'PhabricatorConduitMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorConduitMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhabricatorConduitRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
'PhabricatorConduitRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||||
|
'PhabricatorConduitResultInterface' => 'PhabricatorPHIDInterface',
|
||||||
'PhabricatorConduitSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhabricatorConduitSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
'PhabricatorConduitTestCase' => 'PhabricatorTestCase',
|
'PhabricatorConduitTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorConduitToken' => array(
|
'PhabricatorConduitToken' => array(
|
||||||
|
@ -6527,6 +6539,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorLipsumManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
'PhabricatorLipsumManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
'PhabricatorLipsumMondrianArtist' => 'PhabricatorLipsumArtist',
|
'PhabricatorLipsumMondrianArtist' => 'PhabricatorLipsumArtist',
|
||||||
'PhabricatorLiskDAO' => 'LiskDAO',
|
'PhabricatorLiskDAO' => 'LiskDAO',
|
||||||
|
'PhabricatorLiskSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
|
||||||
'PhabricatorLiskSerializer' => 'Phobject',
|
'PhabricatorLiskSerializer' => 'Phobject',
|
||||||
'PhabricatorListFilterUIExample' => 'PhabricatorUIExample',
|
'PhabricatorListFilterUIExample' => 'PhabricatorUIExample',
|
||||||
'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine',
|
'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine',
|
||||||
|
@ -6823,6 +6836,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorDestructibleInterface',
|
'PhabricatorDestructibleInterface',
|
||||||
'PhabricatorApplicationTransactionInterface',
|
'PhabricatorApplicationTransactionInterface',
|
||||||
'PhabricatorSpacesInterface',
|
'PhabricatorSpacesInterface',
|
||||||
|
'PhabricatorConduitResultInterface',
|
||||||
),
|
),
|
||||||
'PhabricatorPasteApplication' => 'PhabricatorApplication',
|
'PhabricatorPasteApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorPasteArchiveController' => 'PhabricatorPasteController',
|
'PhabricatorPasteArchiveController' => 'PhabricatorPasteController',
|
||||||
|
@ -6965,6 +6979,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPolicyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorPolicyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhabricatorPolicyRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
'PhabricatorPolicyRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||||
'PhabricatorPolicyRule' => 'Phobject',
|
'PhabricatorPolicyRule' => 'Phobject',
|
||||||
|
'PhabricatorPolicySearchEngineExtension' => 'PhabricatorSearchEngineExtension',
|
||||||
'PhabricatorPolicyTestCase' => 'PhabricatorTestCase',
|
'PhabricatorPolicyTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorPolicyTestObject' => array(
|
'PhabricatorPolicyTestObject' => array(
|
||||||
'Phobject',
|
'Phobject',
|
||||||
|
@ -7265,6 +7280,9 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSearchDocumentTypeDatasource' => 'PhabricatorTypeaheadDatasource',
|
'PhabricatorSearchDocumentTypeDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||||
'PhabricatorSearchEditController' => 'PhabricatorSearchBaseController',
|
'PhabricatorSearchEditController' => 'PhabricatorSearchBaseController',
|
||||||
'PhabricatorSearchEngine' => 'Phobject',
|
'PhabricatorSearchEngine' => 'Phobject',
|
||||||
|
'PhabricatorSearchEngineAPIMethod' => 'ConduitAPIMethod',
|
||||||
|
'PhabricatorSearchEngineExtension' => 'Phobject',
|
||||||
|
'PhabricatorSearchEngineExtensionModule' => 'PhabricatorConfigModule',
|
||||||
'PhabricatorSearchEngineTestCase' => 'PhabricatorTestCase',
|
'PhabricatorSearchEngineTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorSearchField' => 'Phobject',
|
'PhabricatorSearchField' => 'Phobject',
|
||||||
'PhabricatorSearchHovercardController' => 'PhabricatorSearchBaseController',
|
'PhabricatorSearchHovercardController' => 'PhabricatorSearchBaseController',
|
||||||
|
@ -7367,6 +7385,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSpacesNoAccessController' => 'PhabricatorSpacesController',
|
'PhabricatorSpacesNoAccessController' => 'PhabricatorSpacesController',
|
||||||
'PhabricatorSpacesRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
'PhabricatorSpacesRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
||||||
'PhabricatorSpacesSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
'PhabricatorSpacesSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||||
|
'PhabricatorSpacesSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
|
||||||
'PhabricatorSpacesSearchField' => 'PhabricatorSearchTokenizerField',
|
'PhabricatorSpacesSearchField' => 'PhabricatorSearchTokenizerField',
|
||||||
'PhabricatorSpacesTestCase' => 'PhabricatorTestCase',
|
'PhabricatorSpacesTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorSpacesViewController' => 'PhabricatorSpacesController',
|
'PhabricatorSpacesViewController' => 'PhabricatorSpacesController',
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface PhabricatorConduitResultInterface
|
||||||
|
extends PhabricatorPHIDInterface {
|
||||||
|
|
||||||
|
public function getFieldSpecificationsForConduit();
|
||||||
|
public function getFieldValuesForConduit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEMPLATE IMPLEMENTATION /////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/* -( PhabricatorConduitResultInterface )---------------------------------- */
|
||||||
|
/*
|
||||||
|
|
||||||
|
public function getFieldSpecificationsForConduit() {
|
||||||
|
return array(
|
||||||
|
'name' => array(
|
||||||
|
'type' => 'string',
|
||||||
|
'description' => pht('The name of the object.'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldValuesForConduit() {
|
||||||
|
return array(
|
||||||
|
'name' => $this->getName(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ConduitResultSearchEngineExtension
|
||||||
|
extends PhabricatorSearchEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'conduit';
|
||||||
|
|
||||||
|
public function isExtensionEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExtensionName() {
|
||||||
|
return pht('Support for ConduitResultInterface');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
return ($object instanceof PhabricatorConduitResultInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldSpecificationsForConduit($object) {
|
||||||
|
return $object->getFieldSpecificationsForConduit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldValuesForConduit($object) {
|
||||||
|
return $object->getFieldValuesForConduit();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PasteSearchConduitAPIMethod
|
||||||
|
extends PhabricatorSearchEngineAPIMethod {
|
||||||
|
|
||||||
|
public function getAPIMethodName() {
|
||||||
|
return 'paste.search';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newSearchEngine() {
|
||||||
|
return new PhabricatorPasteSearchEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodSummary() {
|
||||||
|
return pht('Read information about pastes.');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,7 +10,8 @@ final class PhabricatorPaste extends PhabricatorPasteDAO
|
||||||
PhabricatorProjectInterface,
|
PhabricatorProjectInterface,
|
||||||
PhabricatorDestructibleInterface,
|
PhabricatorDestructibleInterface,
|
||||||
PhabricatorApplicationTransactionInterface,
|
PhabricatorApplicationTransactionInterface,
|
||||||
PhabricatorSpacesInterface {
|
PhabricatorSpacesInterface,
|
||||||
|
PhabricatorConduitResultInterface {
|
||||||
|
|
||||||
protected $title;
|
protected $title;
|
||||||
protected $authorPHID;
|
protected $authorPHID;
|
||||||
|
@ -250,4 +251,38 @@ final class PhabricatorPaste extends PhabricatorPasteDAO
|
||||||
return $this->spacePHID;
|
return $this->spacePHID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorConduitResultInterface )---------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getFieldSpecificationsForConduit() {
|
||||||
|
return array(
|
||||||
|
'title' => array(
|
||||||
|
'type' => 'string',
|
||||||
|
'description' => pht('The name of the object.'),
|
||||||
|
),
|
||||||
|
'authorPHID' => array(
|
||||||
|
'type' => 'phid',
|
||||||
|
'description' => pht('User PHID of the author.'),
|
||||||
|
),
|
||||||
|
'language' => array(
|
||||||
|
'type' => 'string?',
|
||||||
|
'description' => pht('Language to use for syntax highlighting.'),
|
||||||
|
),
|
||||||
|
'status' => array(
|
||||||
|
'type' => 'string',
|
||||||
|
'description' => pht('Active or archived status of the paste.'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldValuesForConduit() {
|
||||||
|
return array(
|
||||||
|
'title' => $this->getTitle(),
|
||||||
|
'authorPHID' => $this->getAuthorPHID(),
|
||||||
|
'language' => nonempty($this->getLanguage(), null),
|
||||||
|
'status' => $this->getStatus(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPolicySearchEngineExtension
|
||||||
|
extends PhabricatorSearchEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'policy';
|
||||||
|
|
||||||
|
public function isExtensionEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExtensionName() {
|
||||||
|
return pht('Support for Policies');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
return ($object instanceof PhabricatorPolicyInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldSpecificationsForConduit($object) {
|
||||||
|
return array(
|
||||||
|
'policy' => array(
|
||||||
|
'type' => 'map<string, wild>',
|
||||||
|
'description' => pht(
|
||||||
|
'Map of capabilities to current policies.'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldValuesForConduit($object) {
|
||||||
|
$capabilities = $object->getCapabilities();
|
||||||
|
|
||||||
|
$map = array();
|
||||||
|
foreach ($capabilities as $capability) {
|
||||||
|
$map[$capability] = $object->getPolicy($capability);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'policy' => $map,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1172,4 +1172,197 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getSearchFieldsForConduit() {
|
||||||
|
$fields = $this->buildSearchFields();
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildConduitResponse(ConduitAPIRequest $request) {
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
$fields = $this->buildSearchFields();
|
||||||
|
|
||||||
|
$query_key = $request->getValue('queryKey');
|
||||||
|
if (!strlen($query_key)) {
|
||||||
|
$saved_query = new PhabricatorSavedQuery();
|
||||||
|
} else if ($this->isBuiltinQuery($query_key)) {
|
||||||
|
$saved_query = $this->buildSavedQueryFromBuiltin($query_key);
|
||||||
|
} else {
|
||||||
|
$saved_query = id(new PhabricatorSavedQueryQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withQueryKeys(array($query_key))
|
||||||
|
->executeOne();
|
||||||
|
if (!$saved_query) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Query key "%s" does not correspond to a valid query.',
|
||||||
|
$query_key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
$field->setViewer($viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
$constraints = $request->getValue('constraints', array());
|
||||||
|
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
if (!$field->getValueExistsInConduitRequest($constraints)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $field->readValueFromConduitRequest($constraints);
|
||||||
|
$saved_query->setParameter($field->getKey(), $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->saveQuery($saved_query);
|
||||||
|
|
||||||
|
|
||||||
|
$query = $this->buildQueryFromSavedQuery($saved_query);
|
||||||
|
$pager = $this->newPagerForSavedQuery($saved_query);
|
||||||
|
|
||||||
|
$this->setQueryOrderForConduit($query, $request);
|
||||||
|
$this->setPagerLimitForConduit($pager, $request);
|
||||||
|
$this->setPagerOffsetsForConduit($pager, $request);
|
||||||
|
|
||||||
|
$objects = $this->executeQuery($query, $pager);
|
||||||
|
|
||||||
|
$data = array();
|
||||||
|
if ($objects) {
|
||||||
|
$field_extensions = $this->getConduitFieldExtensions();
|
||||||
|
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$data[] = $this->getObjectWireFormatForConduit(
|
||||||
|
$object,
|
||||||
|
$field_extensions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'data' => $data,
|
||||||
|
'query' => array(
|
||||||
|
'queryKey' => $saved_query->getQueryKey(),
|
||||||
|
),
|
||||||
|
'cursor' => array(
|
||||||
|
'limit' => $pager->getPageSize(),
|
||||||
|
'after' => $pager->getNextPageID(),
|
||||||
|
'before' => $pager->getPrevPageID(),
|
||||||
|
'order' => $request->getValue('order'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllConduitFieldSpecifications() {
|
||||||
|
$extensions = $this->getConduitFieldExtensions();
|
||||||
|
$object = $this->newQuery()->newResultObject();
|
||||||
|
|
||||||
|
$specifications = array();
|
||||||
|
foreach ($extensions as $extension) {
|
||||||
|
$specifications += $extension->getFieldSpecificationsForConduit($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $specifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getConduitFieldExtensions() {
|
||||||
|
$extensions = PhabricatorSearchEngineExtension::getAllEnabledExtensions();
|
||||||
|
$object = $this->newQuery()->newResultObject();
|
||||||
|
|
||||||
|
$field_extensions = array();
|
||||||
|
foreach ($extensions as $key => $extension) {
|
||||||
|
if ($extension->getFieldSpecificationsForConduit($object)) {
|
||||||
|
$field_extensions[$key] = $extension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $field_extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setQueryOrderForConduit($query, ConduitAPIRequest $request) {
|
||||||
|
$order = $request->getValue('order');
|
||||||
|
if ($order === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_scalar($order)) {
|
||||||
|
$query->setOrder($order);
|
||||||
|
} else {
|
||||||
|
$query->setOrderVector($order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setPagerLimitForConduit($pager, ConduitAPIRequest $request) {
|
||||||
|
$limit = $request->getValue('limit');
|
||||||
|
|
||||||
|
// If there's no limit specified and the query uses a weird huge page
|
||||||
|
// size, just leave it at the default gigantic page size. Otherwise,
|
||||||
|
// make sure it's between 1 and 100, inclusive.
|
||||||
|
|
||||||
|
if ($limit === null) {
|
||||||
|
if ($pager->getPageSize() >= 0xFFFF) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
$limit = 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($limit > 100) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Maximum page size for Conduit API method calls is 100, but '.
|
||||||
|
'this call specified %s.',
|
||||||
|
$limit));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($limit < 1) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Minimum page size for API searches is 1, but this call '.
|
||||||
|
'specified %s.',
|
||||||
|
$limit));
|
||||||
|
}
|
||||||
|
|
||||||
|
$pager->setPageSize($limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setPagerOffsetsForConduit(
|
||||||
|
$pager,
|
||||||
|
ConduitAPIRequest $request) {
|
||||||
|
$before_id = $request->getValue('before');
|
||||||
|
if ($before_id !== null) {
|
||||||
|
$pager->setBeforeID($before_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$after_id = $request->getValue('after');
|
||||||
|
if ($after_id !== null) {
|
||||||
|
$pager->setAfterID($after_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectWireFormatForConduit(
|
||||||
|
$object,
|
||||||
|
array $field_extensions) {
|
||||||
|
$phid = $object->getPHID();
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'id' => (int)$object->getID(),
|
||||||
|
'type' => phid_get_type($phid),
|
||||||
|
'phid' => $phid,
|
||||||
|
'fields' => $this->getObjectWireFieldsForConduit(
|
||||||
|
$object,
|
||||||
|
$field_extensions),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectWireFieldsForConduit(
|
||||||
|
$object,
|
||||||
|
array $field_extensions) {
|
||||||
|
|
||||||
|
$fields = array();
|
||||||
|
foreach ($field_extensions as $extension) {
|
||||||
|
$fields += $extension->getFieldValuesForConduit($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,384 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorSearchEngineAPIMethod
|
||||||
|
extends ConduitAPIMethod {
|
||||||
|
|
||||||
|
abstract public function newSearchEngine();
|
||||||
|
|
||||||
|
public function getApplication() {
|
||||||
|
$engine = $this->newSearchEngine();
|
||||||
|
$class = $engine->getApplicationClassName();
|
||||||
|
return PhabricatorApplication::getByClass($class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodStatus() {
|
||||||
|
return self::METHOD_STATUS_UNSTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodStatusDescription() {
|
||||||
|
return pht('ApplicationSearch methods are highly unstable.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected function defineParamTypes() {
|
||||||
|
return array(
|
||||||
|
'queryKey' => 'optional string',
|
||||||
|
'constraints' => 'optional map<string, wild>',
|
||||||
|
'order' => 'optional order',
|
||||||
|
) + $this->getPagerParamTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected function defineReturnType() {
|
||||||
|
return 'map<string, wild>';
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected function execute(ConduitAPIRequest $request) {
|
||||||
|
$engine = $this->newSearchEngine()
|
||||||
|
->setViewer($request->getUser());
|
||||||
|
|
||||||
|
return $engine->buildConduitResponse($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getMethodDescription() {
|
||||||
|
// TODO: We don't currently have a real viewer in this method.
|
||||||
|
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||||
|
|
||||||
|
$engine = $this->newSearchEngine()
|
||||||
|
->setViewer($viewer);
|
||||||
|
|
||||||
|
$query = $engine->newQuery();
|
||||||
|
|
||||||
|
$out = array();
|
||||||
|
|
||||||
|
$out[] = pht(<<<EOTEXT
|
||||||
|
This is a standard **ApplicationSearch** method which will let you list, query,
|
||||||
|
or search for objects.
|
||||||
|
|
||||||
|
EOTEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
$out[] = pht(<<<EOTEXT
|
||||||
|
Prebuilt Queries
|
||||||
|
----------------
|
||||||
|
|
||||||
|
You can use a builtin or saved query as a starting point by passing it with
|
||||||
|
`queryKey`. If you don't specify a `queryKey`, the query will start with no
|
||||||
|
constraints.
|
||||||
|
|
||||||
|
For example, many applications have builtin queries like `"active"` or
|
||||||
|
`"open"` to find only active or enabled results. To use a `queryKey`, specify
|
||||||
|
it like this:
|
||||||
|
|
||||||
|
```lang=json
|
||||||
|
{
|
||||||
|
...
|
||||||
|
"queryKey": "active",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
These builtin and saved queries are available:
|
||||||
|
EOTEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
$head_querykey = pht('Query Key');
|
||||||
|
$head_name = pht('Name');
|
||||||
|
$head_builtin = pht('Builtin');
|
||||||
|
|
||||||
|
$named_queries = $engine->loadAllNamedQueries();
|
||||||
|
|
||||||
|
$table = array();
|
||||||
|
$table[] = "| {$head_querykey} | {$head_name} | {$head_builtin} |";
|
||||||
|
$table[] = '|------------------|--------------|-----------------|';
|
||||||
|
foreach ($named_queries as $named_query) {
|
||||||
|
$key = $named_query->getQueryKey();
|
||||||
|
$name = $named_query->getQueryName();
|
||||||
|
$builtin = $named_query->getIsBuiltin()
|
||||||
|
? pht('Builtin')
|
||||||
|
: pht('Custom');
|
||||||
|
|
||||||
|
$table[] = "| `{$key}` | {$name} | {$builtin} |";
|
||||||
|
}
|
||||||
|
$table = implode("\n", $table);
|
||||||
|
$out[] = $table;
|
||||||
|
|
||||||
|
$out[] = pht(<<<EOTEXT
|
||||||
|
You can also use **any** query you run via the web UI as a starting point. You
|
||||||
|
can find the key for a query by examining the URI after running a normal
|
||||||
|
search.
|
||||||
|
EOTEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
$out[] = pht(<<<EOTEXT
|
||||||
|
Custom Constraints
|
||||||
|
------------------
|
||||||
|
|
||||||
|
You can add custom constraints to the basic query by passing `constraints`.
|
||||||
|
This will let you filter results (for example, show only results with a
|
||||||
|
certain state, status, or owner).
|
||||||
|
|
||||||
|
Specify constraints like this:
|
||||||
|
|
||||||
|
```lang=json
|
||||||
|
{
|
||||||
|
...
|
||||||
|
"constraints": {
|
||||||
|
"authorPHIDs": ["PHID-USER-1111", "PHID-USER-2222"],
|
||||||
|
"statuses": ["open", "closed"]
|
||||||
|
},
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you specify both a `queryKey` and `constraints`, the basic query
|
||||||
|
configuration will be applied first as a starting point, then any additional
|
||||||
|
values in `constraints` will be applied, overwriting the defaults from the
|
||||||
|
original query.
|
||||||
|
|
||||||
|
This API endpoint supports these constraints:
|
||||||
|
EOTEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
$head_key = pht('Key');
|
||||||
|
$head_label = pht('Label');
|
||||||
|
$head_type = pht('Type');
|
||||||
|
$head_desc = pht('Description');
|
||||||
|
|
||||||
|
$fields = $engine->getSearchFieldsForConduit();
|
||||||
|
|
||||||
|
$table = array();
|
||||||
|
$table[] = "| {$head_key} | {$head_label} | {$head_type} | {$head_desc} |";
|
||||||
|
$table[] = '|-------------|---------------|--------------|--------------|';
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
$key = $field->getKey();
|
||||||
|
$label = $field->getLabel();
|
||||||
|
|
||||||
|
// TODO: Support generating and surfacing this information.
|
||||||
|
$type = pht('TODO');
|
||||||
|
$description = pht('TODO');
|
||||||
|
|
||||||
|
$table[] = "| `{$key}` | **{$label}** | `{$type}` | {$description}";
|
||||||
|
}
|
||||||
|
$table = implode("\n", $table);
|
||||||
|
$out[] = $table;
|
||||||
|
|
||||||
|
|
||||||
|
$out[] = pht(<<<EOTEXT
|
||||||
|
Result Order
|
||||||
|
------------
|
||||||
|
|
||||||
|
Use `order` to choose an ordering for the results. Either specify a single
|
||||||
|
key from the builtin orders (these are a set of meaningful, high-level,
|
||||||
|
human-readable orders) or specify a list of low-level columns.
|
||||||
|
|
||||||
|
To use a high-level order, choose a builtin order from the table below
|
||||||
|
and specify it like this:
|
||||||
|
|
||||||
|
```lang=json
|
||||||
|
{
|
||||||
|
...
|
||||||
|
"order": "newest",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
These builtin orders are available:
|
||||||
|
EOTEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
$head_builtin = pht('Builtin Order');
|
||||||
|
$head_description = pht('Description');
|
||||||
|
$head_columns = pht('Columns');
|
||||||
|
|
||||||
|
$orders = $query->getBuiltinOrders();
|
||||||
|
|
||||||
|
$table = array();
|
||||||
|
$table[] = "| {$head_builtin} | {$head_description} | {$head_columns} |";
|
||||||
|
$table[] = '|-----------------|---------------------|-----------------|';
|
||||||
|
foreach ($orders as $key => $order) {
|
||||||
|
$name = $order['name'];
|
||||||
|
$columns = implode(', ', $order['vector']);
|
||||||
|
$table[] = "| `{$key}` | {$name} | {$columns} |";
|
||||||
|
}
|
||||||
|
$table = implode("\n", $table);
|
||||||
|
$out[] = $table;
|
||||||
|
|
||||||
|
$out[] = pht(<<<EOTEXT
|
||||||
|
You can choose a low-level column order instead. This is an advanced feature.
|
||||||
|
|
||||||
|
In your custom order: each column may only be specified once; each column may
|
||||||
|
be prefixed with "-" to invert the order; the last column must be unique; and
|
||||||
|
no column other than the last may be unique.
|
||||||
|
|
||||||
|
To use a low-level order, choose a sequence of columns and specify them like
|
||||||
|
this:
|
||||||
|
|
||||||
|
```lang=json
|
||||||
|
{
|
||||||
|
...
|
||||||
|
"order": ["color", "-name", "id"],
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
These low-level columns are available:
|
||||||
|
EOTEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
$head_column = pht('Column Key');
|
||||||
|
$head_unique = pht('Unique');
|
||||||
|
|
||||||
|
$columns = $query->getOrderableColumns();
|
||||||
|
|
||||||
|
$table = array();
|
||||||
|
$table[] = "| {$head_column} | {$head_unique} |";
|
||||||
|
$table[] = '|----------------|----------------|';
|
||||||
|
foreach ($columns as $key => $column) {
|
||||||
|
$unique = idx($column, 'unique')
|
||||||
|
? pht('Yes')
|
||||||
|
: pht('No');
|
||||||
|
|
||||||
|
$table[] = "| `{$key}` | {$unique} |";
|
||||||
|
}
|
||||||
|
$table = implode("\n", $table);
|
||||||
|
$out[] = $table;
|
||||||
|
|
||||||
|
|
||||||
|
$out[] = pht(<<<EOTEXT
|
||||||
|
Result Format
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The result format is a dictionary with several fields:
|
||||||
|
|
||||||
|
- `data`: Contains the actual results, as a list of dictionaries.
|
||||||
|
- `query`: Details about the query which was issued.
|
||||||
|
- `cursor`: Information about how to issue another query to get the next
|
||||||
|
(or previous) page of results. See "Paging and Limits" below.
|
||||||
|
|
||||||
|
EOTEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
$out[] = pht(<<<EOTEXT
|
||||||
|
Fields
|
||||||
|
------
|
||||||
|
|
||||||
|
The `data` field of the result contains a list of results. Each result has
|
||||||
|
some metadata and a `fields` key, which contains the primary object fields.
|
||||||
|
|
||||||
|
For example, the results may look something like this:
|
||||||
|
|
||||||
|
```lang=json
|
||||||
|
{
|
||||||
|
...
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": 123,
|
||||||
|
"phid": "PHID-WXYZ-1111",
|
||||||
|
"fields": {
|
||||||
|
"name": "First Example Object",
|
||||||
|
"authorPHID": "PHID-USER-2222"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 124,
|
||||||
|
"phid": "PHID-WXYZ-3333",
|
||||||
|
"fields": {
|
||||||
|
"name": "Second Example Object",
|
||||||
|
"authorPHID": "PHID-USER-4444"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This result structure is standardized across all search methods, but the
|
||||||
|
available fields differ from application to application.
|
||||||
|
|
||||||
|
These are the fields available on this object type:
|
||||||
|
|
||||||
|
EOTEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
$specs = $engine->getAllConduitFieldSpecifications();
|
||||||
|
|
||||||
|
$table = array();
|
||||||
|
$table[] = "| {$head_key} | {$head_type} | {$head_description} |";
|
||||||
|
$table[] = '|-------------|--------------|---------------------|';
|
||||||
|
foreach ($specs as $key => $spec) {
|
||||||
|
$type = idx($spec, 'type');
|
||||||
|
$description = idx($spec, 'description');
|
||||||
|
$table[] = "| `{$key}` | `{$type}` | {$description} |";
|
||||||
|
}
|
||||||
|
$table = implode("\n", $table);
|
||||||
|
$out[] = $table;
|
||||||
|
|
||||||
|
$out[] = pht(<<<EOTEXT
|
||||||
|
Paging and Limits
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Queries are limited to returning 100 results at a time. If you want fewer
|
||||||
|
results than this, you can use `limit` to specify a smaller limit.
|
||||||
|
|
||||||
|
If you want more results, you'll need to make additional queries to retrieve
|
||||||
|
more pages of results.
|
||||||
|
|
||||||
|
The result structure contains a `cursor` key with information you'll need in
|
||||||
|
order to fetch the next page. After an initial query, it will usually look
|
||||||
|
something like this:
|
||||||
|
|
||||||
|
```lang=json
|
||||||
|
{
|
||||||
|
...
|
||||||
|
"cursor": {
|
||||||
|
"limit": 100,
|
||||||
|
"after": "1234",
|
||||||
|
"before": null,
|
||||||
|
"order": null
|
||||||
|
}
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `limit` and `order` fields are describing the effective limit and order the
|
||||||
|
query was executed with, and are usually not of much interest. The `after` and
|
||||||
|
`before` fields give you cursors which you can pass when making another API
|
||||||
|
call in order to get the next (or previous) page of results.
|
||||||
|
|
||||||
|
To get the next page of results, repeat your API call with all the same
|
||||||
|
parameters as the original call, but pass the `after` cursor you received from
|
||||||
|
the first call in the `after` parameter when making the second call.
|
||||||
|
|
||||||
|
If you do things correctly, you should get the second page of results, and
|
||||||
|
a cursor structure like this:
|
||||||
|
|
||||||
|
```lang=json
|
||||||
|
{
|
||||||
|
...
|
||||||
|
"cursor": {
|
||||||
|
"limit": 5,
|
||||||
|
"after": "4567",
|
||||||
|
"before": "7890",
|
||||||
|
"order": null
|
||||||
|
}
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now continue to the third page of results by passing the new `after`
|
||||||
|
cursor to the `after` parameter in your third call, or return to the previous
|
||||||
|
page of results by passing the `before` cursor to the `before` parameter. This
|
||||||
|
might be useful if you are rendering a web UI for a user and want to provide
|
||||||
|
"Next Page" and "Previous Page" links.
|
||||||
|
|
||||||
|
If `after` is `null`, there is no next page of results available. Likewise,
|
||||||
|
if `before` is `null`, there are no previous results available.
|
||||||
|
|
||||||
|
EOTEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
$out = implode("\n\n", $out);
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorLiskSearchEngineExtension
|
||||||
|
extends PhabricatorSearchEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'lisk';
|
||||||
|
|
||||||
|
public function isExtensionEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExtensionName() {
|
||||||
|
return pht('Lisk Builtin Properties');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
if (!($object instanceof LiskDAO)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$object->getConfigOption(LiskDAO::CONFIG_TIMESTAMPS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldSpecificationsForConduit($object) {
|
||||||
|
return array(
|
||||||
|
'dateCreated' => array(
|
||||||
|
'type' => 'int',
|
||||||
|
'description' => pht(
|
||||||
|
'Epoch timestamp when the object was created.'),
|
||||||
|
),
|
||||||
|
'dateModified' => array(
|
||||||
|
'type' => 'int',
|
||||||
|
'description' => pht(
|
||||||
|
'Epoch timestamp when the object was last updated.'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldValuesForConduit($object) {
|
||||||
|
return array(
|
||||||
|
'dateCreated' => (int)$object->getDateCreated(),
|
||||||
|
'dateModified' => (int)$object->getDateModified(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorSearchEngineExtension extends Phobject {
|
||||||
|
|
||||||
|
private $viewer;
|
||||||
|
|
||||||
|
final public function getExtensionKey() {
|
||||||
|
return $this->getPhobjectClassConstant('EXTENSIONKEY');
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function setViewer($viewer) {
|
||||||
|
$this->viewer = $viewer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getViewer() {
|
||||||
|
return $this->viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function isExtensionEnabled();
|
||||||
|
abstract public function getExtensionName();
|
||||||
|
abstract public function supportsObject($object);
|
||||||
|
|
||||||
|
public function getFieldSpecificationsForConduit($object) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldValuesForConduit($object) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function getAllExtensions() {
|
||||||
|
return id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass(__CLASS__)
|
||||||
|
->setUniqueMethod('getExtensionKey')
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function getAllEnabledExtensions() {
|
||||||
|
$extensions = self::getAllExtensions();
|
||||||
|
|
||||||
|
foreach ($extensions as $key => $extension) {
|
||||||
|
if (!$extension->isExtensionEnabled()) {
|
||||||
|
unset($extensions[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorSearchEngineExtensionModule
|
||||||
|
extends PhabricatorConfigModule {
|
||||||
|
|
||||||
|
public function getModuleKey() {
|
||||||
|
return 'searchengine';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getModuleName() {
|
||||||
|
return pht('SearchEngine Extensions');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderModuleStatus(AphrontRequest $request) {
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
|
||||||
|
$extensions = PhabricatorSearchEngineExtension::getAllExtensions();
|
||||||
|
|
||||||
|
$rows = array();
|
||||||
|
foreach ($extensions as $extension) {
|
||||||
|
$rows[] = array(
|
||||||
|
$extension->getExtensionKey(),
|
||||||
|
get_class($extension),
|
||||||
|
$extension->getExtensionName(),
|
||||||
|
$extension->isExtensionEnabled()
|
||||||
|
? pht('Yes')
|
||||||
|
: pht('No'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = id(new AphrontTableView($rows))
|
||||||
|
->setHeaders(
|
||||||
|
array(
|
||||||
|
pht('Key'),
|
||||||
|
pht('Class'),
|
||||||
|
pht('Name'),
|
||||||
|
pht('Enabled'),
|
||||||
|
))
|
||||||
|
->setColumnClasses(
|
||||||
|
array(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
'wide pri',
|
||||||
|
null,
|
||||||
|
));
|
||||||
|
|
||||||
|
return id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText(pht('SearchEngine Extensions'))
|
||||||
|
->setTable($table);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -205,6 +205,14 @@ abstract class PhabricatorSearchField extends Phobject {
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getValueExistsInConduitRequest(array $constraints) {
|
||||||
|
return array_key_exists($this->getKey(), $constraints);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function readValueFromConduitRequest(array $constraints) {
|
||||||
|
return idx($constraints, $this->getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( Rendering Controls )------------------------------------------------- */
|
/* -( Rendering Controls )------------------------------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorSpacesSearchEngineExtension
|
||||||
|
extends PhabricatorSearchEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'spaces';
|
||||||
|
|
||||||
|
public function isExtensionEnabled() {
|
||||||
|
return PhabricatorApplication::isClassInstalled(
|
||||||
|
'PhabricatorSpacesApplication');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExtensionName() {
|
||||||
|
return pht('Support for Spaces');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
return ($object instanceof PhabricatorSpacesInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldSpecificationsForConduit($object) {
|
||||||
|
return array(
|
||||||
|
'spacePHID' => array(
|
||||||
|
'type' => 'phid?',
|
||||||
|
'description' => pht(
|
||||||
|
'PHID of the policy space this object is part of.'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldValuesForConduit($object) {
|
||||||
|
return array(
|
||||||
|
'spacePHID' => $object->getSpacePHID(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue