@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
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add "owners.search" Conduit API endpoint, with CustomField support

Summary:
Ref T9964. Adds a new-style "owners.search" endpoint, and an extension for customfields.

Puts enough indirection in place to give us nice, consistent "custom.key" user-facing keys instead of "std:custom:owners:na0shf9a8dfdsafl" junk.

Test Plan:
- Searched Owners via API.
- Searched by ID.
- Ordered by custom fields.
- Reviewed API docs.
- Used normal search with ordering.
- Viewed custom field values in search results.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9964

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

+198 -14
+6 -1
src/__phutil_library_map__.php
··· 1417 1417 'OwnersEditConduitAPIMethod' => 'applications/owners/conduit/OwnersEditConduitAPIMethod.php', 1418 1418 'OwnersPackageReplyHandler' => 'applications/owners/mail/OwnersPackageReplyHandler.php', 1419 1419 'OwnersQueryConduitAPIMethod' => 'applications/owners/conduit/OwnersQueryConduitAPIMethod.php', 1420 + 'OwnersSearchConduitAPIMethod' => 'applications/owners/conduit/OwnersSearchConduitAPIMethod.php', 1420 1421 'PHIDConduitAPIMethod' => 'applications/phid/conduit/PHIDConduitAPIMethod.php', 1421 1422 'PHIDInfoConduitAPIMethod' => 'applications/phid/conduit/PHIDInfoConduitAPIMethod.php', 1422 1423 'PHIDLookupConduitAPIMethod' => 'applications/phid/conduit/PHIDLookupConduitAPIMethod.php', ··· 1993 1994 'PhabricatorCustomFieldAttachment' => 'infrastructure/customfield/field/PhabricatorCustomFieldAttachment.php', 1994 1995 'PhabricatorCustomFieldConfigOptionType' => 'infrastructure/customfield/config/PhabricatorCustomFieldConfigOptionType.php', 1995 1996 'PhabricatorCustomFieldDataNotAvailableException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldDataNotAvailableException.php', 1996 - 'PhabricatorCustomFieldEditEngineExtension' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditEngineExtension.php', 1997 + 'PhabricatorCustomFieldEditEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldEditEngineExtension.php', 1997 1998 'PhabricatorCustomFieldEditField' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditField.php', 1998 1999 'PhabricatorCustomFieldEditType' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditType.php', 1999 2000 'PhabricatorCustomFieldHeraldField' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldField.php', ··· 2006 2007 'PhabricatorCustomFieldNotAttachedException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldNotAttachedException.php', 2007 2008 'PhabricatorCustomFieldNotProxyException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldNotProxyException.php', 2008 2009 'PhabricatorCustomFieldNumericIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldNumericIndexStorage.php', 2010 + 'PhabricatorCustomFieldSearchEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldSearchEngineExtension.php', 2009 2011 'PhabricatorCustomFieldStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStorage.php', 2010 2012 'PhabricatorCustomFieldStringIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStringIndexStorage.php', 2011 2013 'PhabricatorCustomHeaderConfigType' => 'applications/config/custom/PhabricatorCustomHeaderConfigType.php', ··· 5439 5441 'OwnersEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 5440 5442 'OwnersPackageReplyHandler' => 'PhabricatorMailReplyHandler', 5441 5443 'OwnersQueryConduitAPIMethod' => 'OwnersConduitAPIMethod', 5444 + 'OwnersSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 5442 5445 'PHIDConduitAPIMethod' => 'ConduitAPIMethod', 5443 5446 'PHIDInfoConduitAPIMethod' => 'PHIDConduitAPIMethod', 5444 5447 'PHIDLookupConduitAPIMethod' => 'PHIDConduitAPIMethod', ··· 6116 6119 'PhabricatorCustomFieldNotAttachedException' => 'Exception', 6117 6120 'PhabricatorCustomFieldNotProxyException' => 'Exception', 6118 6121 'PhabricatorCustomFieldNumericIndexStorage' => 'PhabricatorCustomFieldIndexStorage', 6122 + 'PhabricatorCustomFieldSearchEngineExtension' => 'PhabricatorSearchEngineExtension', 6119 6123 'PhabricatorCustomFieldStorage' => 'PhabricatorLiskDAO', 6120 6124 'PhabricatorCustomFieldStringIndexStorage' => 'PhabricatorCustomFieldIndexStorage', 6121 6125 'PhabricatorCustomHeaderConfigType' => 'PhabricatorConfigOptionType', ··· 6791 6795 'PhabricatorApplicationTransactionInterface', 6792 6796 'PhabricatorCustomFieldInterface', 6793 6797 'PhabricatorDestructibleInterface', 6798 + 'PhabricatorConduitResultInterface', 6794 6799 ), 6795 6800 'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource', 6796 6801 'PhabricatorOwnersPackageEditEngine' => 'PhabricatorEditEngine',
+18
src/applications/owners/conduit/OwnersSearchConduitAPIMethod.php
··· 1 + <?php 2 + 3 + final class OwnersSearchConduitAPIMethod 4 + extends PhabricatorSearchEngineAPIMethod { 5 + 6 + public function getAPIMethodName() { 7 + return 'owners.search'; 8 + } 9 + 10 + public function newSearchEngine() { 11 + return new PhabricatorOwnersPackageSearchEngine(); 12 + } 13 + 14 + public function getMethodSummary() { 15 + return pht('Read information about Owners packages.'); 16 + } 17 + 18 + }
+31 -1
src/applications/owners/storage/PhabricatorOwnersPackage.php
··· 6 6 PhabricatorPolicyInterface, 7 7 PhabricatorApplicationTransactionInterface, 8 8 PhabricatorCustomFieldInterface, 9 - PhabricatorDestructibleInterface { 9 + PhabricatorDestructibleInterface, 10 + PhabricatorConduitResultInterface { 10 11 11 12 protected $name; 12 13 protected $originalName; ··· 363 364 364 365 $this->delete(); 365 366 $this->saveTransaction(); 367 + } 368 + 369 + 370 + /* -( PhabricatorConduitResultInterface )---------------------------------- */ 371 + 372 + 373 + public function getFieldSpecificationsForConduit() { 374 + return array( 375 + 'name' => array( 376 + 'type' => 'string', 377 + 'description' => pht('The name of the package.'), 378 + ), 379 + 'description' => array( 380 + 'type' => 'string', 381 + 'description' => pht('The package description.'), 382 + ), 383 + 'status' => array( 384 + 'type' => 'string', 385 + 'description' => pht('Active or archived status of the package.'), 386 + ), 387 + ); 388 + } 389 + 390 + public function getFieldValuesForConduit() { 391 + return array( 392 + 'name' => $this->getName(), 393 + 'description' => $this->getDescription(), 394 + 'status' => $this->getStatus(), 395 + ); 366 396 } 367 397 368 398 }
+31
src/applications/search/engine/PhabricatorApplicationSearchEngine.php
··· 1174 1174 1175 1175 public function getSearchFieldsForConduit() { 1176 1176 $fields = $this->buildSearchFields(); 1177 + 1178 + // These are handled separately for Conduit, so don't show them as 1179 + // supported. 1180 + unset($fields['ids']); 1181 + unset($fields['phids']); 1182 + unset($fields['order']); 1183 + unset($fields['limit']); 1184 + 1177 1185 return $fields; 1178 1186 } 1179 1187 ··· 1220 1228 $query = $this->buildQueryFromSavedQuery($saved_query); 1221 1229 $pager = $this->newPagerForSavedQuery($saved_query); 1222 1230 1231 + $this->setAutomaticConstraintsForConduit($query, $request, $constraints); 1223 1232 $this->setQueryOrderForConduit($query, $request); 1224 1233 $this->setPagerLimitForConduit($pager, $request); 1225 1234 $this->setPagerOffsetsForConduit($pager, $request); ··· 1269 1278 1270 1279 $field_extensions = array(); 1271 1280 foreach ($extensions as $key => $extension) { 1281 + $extension->setViewer($this->requireViewer()); 1282 + 1283 + if (!$extension->supportsObject($object)) { 1284 + continue; 1285 + } 1286 + 1272 1287 if ($extension->getFieldSpecificationsForConduit($object)) { 1273 1288 $field_extensions[$key] = $extension; 1274 1289 } 1275 1290 } 1276 1291 1277 1292 return $field_extensions; 1293 + } 1294 + 1295 + private function setAutomaticConstraintsForConduit( 1296 + $query, 1297 + ConduitAPIRequest $request, 1298 + array $constraints) { 1299 + 1300 + $with_ids = idx($constraints, 'ids'); 1301 + if ($with_ids) { 1302 + $query->withIDs($with_ids); 1303 + } 1304 + 1305 + $with_phids = idx($constraints, 'phids'); 1306 + if ($with_phids) { 1307 + $query->withPHIDs($with_phids); 1308 + } 1278 1309 } 1279 1310 1280 1311 private function setQueryOrderForConduit($query, ConduitAPIRequest $request) {
+6 -1
src/applications/search/engine/PhabricatorSearchEngineAPIMethod.php
··· 143 143 $head_type = pht('Type'); 144 144 $head_desc = pht('Description'); 145 145 146 + $desc_ids = pht('Search for specific objects by ID.'); 147 + $desc_phids = pht('Search for specific objects by PHID.'); 148 + 146 149 $fields = $engine->getSearchFieldsForConduit(); 147 150 148 151 $table = array(); 149 152 $table[] = "| {$head_key} | {$head_label} | {$head_type} | {$head_desc} |"; 150 153 $table[] = '|-------------|---------------|--------------|--------------|'; 154 + $table[] = "| `ids` | **IDs** | `list<int>` | {$desc_ids} |"; 155 + $table[] = "| `phids` | **PHIDs** | `list<phid>` | {$desc_phids} |"; 151 156 foreach ($fields as $field) { 152 - $key = $field->getKey(); 157 + $key = $field->getKeyForConduit(); 153 158 $label = $field->getLabel(); 154 159 155 160 // TODO: Support generating and surfacing this information.
+8
src/applications/search/field/PhabricatorSearchCustomFieldProxyField.php
··· 26 26 return $this; 27 27 } 28 28 29 + public function getLabel() { 30 + return $this->getCustomField()->getFieldName(); 31 + } 32 + 29 33 public function getCustomField() { 30 34 return $this->customField; 31 35 } 32 36 33 37 protected function getDefaultValue() { 34 38 return null; 39 + } 40 + 41 + public function getKeyForConduit() { 42 + return $this->getCustomField()->getModernFieldKey(); 35 43 } 36 44 37 45 protected function getValueExistsInRequest(AphrontRequest $request, $key) {
+10
src/applications/search/field/PhabricatorSearchField.php
··· 271 271 272 272 return $list; 273 273 } 274 + 275 + 276 + public function getKeyForConduit() { 277 + // TODO: This shouldn't really be different, but internal handling of 278 + // custom field keys is a bit of a mess for now. 279 + return $this->getKey(); 280 + } 281 + 282 + 283 + 274 284 }
src/infrastructure/customfield/editor/PhabricatorCustomFieldEditEngineExtension.php src/infrastructure/customfield/engineextension/PhabricatorCustomFieldEditEngineExtension.php
+58
src/infrastructure/customfield/engineextension/PhabricatorCustomFieldSearchEngineExtension.php
··· 1 + <?php 2 + 3 + final class PhabricatorCustomFieldSearchEngineExtension 4 + extends PhabricatorSearchEngineExtension { 5 + 6 + const EXTENSIONKEY = 'customfield'; 7 + 8 + public function isExtensionEnabled() { 9 + return true; 10 + } 11 + 12 + public function getExtensionName() { 13 + return pht('Support for Custom Fields'); 14 + } 15 + 16 + public function supportsObject($object) { 17 + return ($object instanceof PhabricatorCustomFieldInterface); 18 + } 19 + 20 + public function getFieldSpecificationsForConduit($object) { 21 + $fields = PhabricatorCustomField::getObjectFields( 22 + $object, 23 + PhabricatorCustomField::ROLE_CONDUIT); 24 + 25 + $map = array(); 26 + foreach ($fields->getFields() as $field) { 27 + $key = $field->getModernFieldKey(); 28 + $map[$key] = array( 29 + 'type' => 'wild', 30 + 'description' => $field->getFieldDescription(), 31 + ); 32 + } 33 + 34 + return $map; 35 + } 36 + 37 + public function getFieldValuesForConduit($object) { 38 + // TODO: This is currently very inefficient. We should bulk-load these 39 + // field values instead. 40 + 41 + $fields = PhabricatorCustomField::getObjectFields( 42 + $object, 43 + PhabricatorCustomField::ROLE_CONDUIT); 44 + 45 + $fields 46 + ->setViewer($this->getViewer()) 47 + ->readFieldsFromStorage($object); 48 + 49 + $map = array(); 50 + foreach ($fields->getFields() as $field) { 51 + $key = $field->getModernFieldKey(); 52 + $map[$key] = $field->getConduitDictionaryValue(); 53 + } 54 + 55 + return $map; 56 + } 57 + 58 + }
+9 -2
src/infrastructure/customfield/field/PhabricatorCustomField.php
··· 188 188 $field_key_is_incomplete = true); 189 189 } 190 190 191 + public function getModernFieldKey() { 192 + if ($this->proxy) { 193 + return $this->proxy->getModernFieldKey(); 194 + } 195 + return $this->getFieldKey(); 196 + } 197 + 191 198 192 199 /** 193 200 * Return a human-readable field name. ··· 199 206 if ($this->proxy) { 200 207 return $this->proxy->getFieldName(); 201 208 } 202 - return $this->getFieldKey(); 209 + return $this->getModernFieldKey(); 203 210 } 204 211 205 212 ··· 1109 1116 1110 1117 return $this->newEditField() 1111 1118 ->setKey($this->getFieldKey()) 1112 - ->setEditTypeKey('custom.'.$this->getFieldKey()) 1119 + ->setEditTypeKey($this->getModernFieldKey()) 1113 1120 ->setLabel($this->getFieldName()) 1114 1121 ->setDescription($this->getFieldDescription()) 1115 1122 ->setTransactionType($this->getApplicationTransactionType())
+13 -1
src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php
··· 440 440 } 441 441 442 442 protected function newStandardEditField() { 443 - $short = 'custom.'.$this->getRawStandardFieldKey(); 443 + $short = $this->getModernFieldKey(); 444 444 445 445 return parent::newStandardEditField() 446 446 ->setEditTypeKey($short) ··· 449 449 450 450 public function shouldAppearInConduitTransactions() { 451 451 return true; 452 + } 453 + 454 + public function shouldAppearInConduitDictionary() { 455 + return true; 456 + } 457 + 458 + public function getModernFieldKey() { 459 + return 'custom.'.$this->getRawStandardFieldKey(); 460 + } 461 + 462 + public function getConduitDictionaryValue() { 463 + return $this->getFieldValue(); 452 464 } 453 465 454 466 }
+8 -8
src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php
··· 716 716 continue; 717 717 } 718 718 719 - $key = $field->getFieldKey(); 720 - $digest = $field->getFieldIndex(); 719 + $legacy_key = 'custom:'.$field->getFieldKey(); 720 + $modern_key = $field->getModernFieldKey(); 721 721 722 - $full_key = 'custom:'.$key; 723 - $orders[$full_key] = array( 724 - 'vector' => array($full_key, 'id'), 722 + $orders[$modern_key] = array( 723 + 'vector' => array($modern_key, 'id'), 725 724 'name' => $field->getFieldName(), 725 + 'aliases' => array($legacy_key), 726 726 ); 727 727 } 728 728 } ··· 903 903 continue; 904 904 } 905 905 906 - $key = $field->getFieldKey(); 907 906 $digest = $field->getFieldIndex(); 908 907 909 - $full_key = 'custom:'.$key; 910 - $columns[$full_key] = array( 908 + $key = $field->getModernFieldKey(); 909 + 910 + $columns[$key] = array( 911 911 'table' => 'appsearch_order_'.$digest, 912 912 'column' => 'indexValue', 913 913 'type' => $index->getIndexValueType(),