@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator

Implement a basic project.search third-generation API method

Summary: Ref T10010. This still needs support for attachments (to get members) and more constraints (like slugs), but mostly works.

Test Plan: Ran query, saw basically sensible results.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10010

Differential Revision: https://secure.phabricator.com/D14889

+85 -3
+3
src/__phutil_library_map__.php
··· 3747 3747 'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php', 3748 3748 'ProjectRemarkupRuleTestCase' => 'applications/project/remarkup/__tests__/ProjectRemarkupRuleTestCase.php', 3749 3749 'ProjectReplyHandler' => 'applications/project/mail/ProjectReplyHandler.php', 3750 + 'ProjectSearchConduitAPIMethod' => 'applications/project/conduit/ProjectSearchConduitAPIMethod.php', 3750 3751 'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php', 3751 3752 'ReleephAuthorFieldSpecification' => 'applications/releeph/field/specification/ReleephAuthorFieldSpecification.php', 3752 3753 'ReleephBranch' => 'applications/releeph/storage/ReleephBranch.php', ··· 7146 7147 'PhabricatorCustomFieldInterface', 7147 7148 'PhabricatorDestructibleInterface', 7148 7149 'PhabricatorFulltextInterface', 7150 + 'PhabricatorConduitResultInterface', 7149 7151 ), 7150 7152 'PhabricatorProjectAddHeraldAction' => 'PhabricatorProjectHeraldAction', 7151 7153 'PhabricatorProjectApplication' => 'PhabricatorApplication', ··· 8296 8298 'ProjectRemarkupRule' => 'PhabricatorObjectRemarkupRule', 8297 8299 'ProjectRemarkupRuleTestCase' => 'PhabricatorTestCase', 8298 8300 'ProjectReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 8301 + 'ProjectSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 8299 8302 'QueryFormattingTestCase' => 'PhabricatorTestCase', 8300 8303 'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification', 8301 8304 'ReleephBranch' => array(
+24
src/applications/project/conduit/ProjectSearchConduitAPIMethod.php
··· 1 + <?php 2 + 3 + final class ProjectSearchConduitAPIMethod 4 + extends PhabricatorSearchEngineAPIMethod { 5 + 6 + public function getAPIMethodName() { 7 + return 'project.search'; 8 + } 9 + 10 + public function newSearchEngine() { 11 + return new PhabricatorProjectSearchEngine(); 12 + } 13 + 14 + public function getMethodSummary() { 15 + return pht('Read information about projects.'); 16 + } 17 + 18 + protected function getCustomQueryMaps($query) { 19 + return array( 20 + 'slugMap' => $query->getSlugMap(), 21 + ); 22 + } 23 + 24 + }
+30 -1
src/applications/project/storage/PhabricatorProject.php
··· 9 9 PhabricatorSubscribableInterface, 10 10 PhabricatorCustomFieldInterface, 11 11 PhabricatorDestructibleInterface, 12 - PhabricatorFulltextInterface { 12 + PhabricatorFulltextInterface, 13 + PhabricatorConduitResultInterface { 13 14 14 15 protected $name; 15 16 protected $status = PhabricatorProjectStatus::STATUS_ACTIVE; ··· 523 524 524 525 public function newFulltextEngine() { 525 526 return new PhabricatorProjectFulltextEngine(); 527 + } 528 + 529 + 530 + /* -( PhabricatorConduitResultInterface )---------------------------------- */ 531 + 532 + 533 + public function getFieldSpecificationsForConduit() { 534 + return array( 535 + id(new PhabricatorConduitSearchFieldSpecification()) 536 + ->setKey('name') 537 + ->setType('string') 538 + ->setDescription(pht('The name of the project.')), 539 + id(new PhabricatorConduitSearchFieldSpecification()) 540 + ->setKey('slug') 541 + ->setType('string') 542 + ->setDescription(pht('Primary slug/hashtag.')), 543 + ); 544 + } 545 + 546 + public function getFieldValuesForConduit() { 547 + return array( 548 + 'name' => $this->getName(), 549 + 'slug' => $this->getPrimarySlug(), 550 + ); 551 + } 552 + 553 + public function getConduitSearchAttachments() { 554 + return array(); 526 555 } 527 556 528 557 }
+10 -1
src/applications/search/engine/PhabricatorApplicationSearchEngine.php
··· 1081 1081 return $fields; 1082 1082 } 1083 1083 1084 - public function buildConduitResponse(ConduitAPIRequest $request) { 1084 + public function buildConduitResponse( 1085 + ConduitAPIRequest $request, 1086 + ConduitAPIMethod $method) { 1085 1087 $viewer = $this->requireViewer(); 1086 1088 1087 1089 $query_key = $request->getValue('queryKey'); ··· 1172 1174 $attachment_specs[$key]); 1173 1175 } 1174 1176 1177 + // If this is empty, we still want to emit a JSON object, not a 1178 + // JSON list. 1179 + if (!$attachment_map) { 1180 + $attachment_map = (object)$attachment_map; 1181 + } 1182 + 1175 1183 $id = (int)$object->getID(); 1176 1184 $phid = $object->getPHID(); 1177 1185 ··· 1187 1195 1188 1196 return array( 1189 1197 'data' => $data, 1198 + 'maps' => $method->getQueryMaps($query), 1190 1199 'query' => array( 1191 1200 'queryKey' => $saved_query->getQueryKey(), 1192 1201 ),
+18 -1
src/applications/search/engine/PhabricatorSearchEngineAPIMethod.php
··· 5 5 6 6 abstract public function newSearchEngine(); 7 7 8 + final public function getQueryMaps($query) { 9 + $maps = $this->getCustomQueryMaps($query); 10 + 11 + // Make sure we emit empty maps as objects, not lists. 12 + foreach ($maps as $key => $map) { 13 + if (!$map) { 14 + $maps[$key] = (object)$map; 15 + } 16 + } 17 + 18 + return $maps; 19 + } 20 + 21 + protected function getCustomQueryMaps($query) { 22 + return array(); 23 + } 24 + 8 25 public function getApplication() { 9 26 $engine = $this->newSearchEngine(); 10 27 $class = $engine->getApplicationClassName(); ··· 36 53 $engine = $this->newSearchEngine() 37 54 ->setViewer($request->getUser()); 38 55 39 - return $engine->buildConduitResponse($request); 56 + return $engine->buildConduitResponse($request, $this); 40 57 } 41 58 42 59 final public function getMethodDescription() {