@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.

Use ApplicationTransactions/CustomField to power Differential global search

Summary:
Ref T2222. Ref T3886. Ref T418. A few changes:

- CustomField can now index into global search.
- Use CustomField fields instead of older custom fields for Differential global search. (This slightly breaks any custom fields which exist, but they are presumably very rare, and probably do not exist; this break is also very mild.)
- Automatically perform CustomField and Subscribable indexing on applicable object types.

Test Plan: Used `bin/search index` to reindex a bunch of stuff, then searched for it. Debug-dumped abstract documents to inspect them.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T418, T3886, T2222

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

+118 -81
+11
src/applications/differential/customfield/DifferentialSummaryField.php
··· 78 78 $xaction->getNewValue()); 79 79 } 80 80 81 + public function shouldAppearInGlobalSearch() { 82 + return true; 83 + } 84 + 85 + public function updateAbstractDocument( 86 + PhabricatorSearchAbstractDocument $document) { 87 + if (strlen($this->getValue())) { 88 + $document->addField('body', $this->getValue()); 89 + } 90 + } 91 + 81 92 }
+12
src/applications/differential/customfield/DifferentialTestPlanField.php
··· 92 92 $xaction->getNewValue()); 93 93 } 94 94 95 + 96 + public function shouldAppearInGlobalSearch() { 97 + return true; 98 + } 99 + 100 + public function updateAbstractDocument( 101 + PhabricatorSearchAbstractDocument $document) { 102 + if (strlen($this->getValue())) { 103 + $document->addField('plan', $this->getValue()); 104 + } 105 + } 106 + 95 107 }
+18 -54
src/applications/differential/search/DifferentialSearchIndexer.php
··· 1 1 <?php 2 2 3 - /** 4 - * @group differential 5 - */ 6 3 final class DifferentialSearchIndexer 7 4 extends PhabricatorSearchDocumentIndexer { 8 5 ··· 10 7 return new DifferentialRevision(); 11 8 } 12 9 10 + protected function loadDocumentByPHID($phid) { 11 + $object = id(new DifferentialRevisionQuery()) 12 + ->setViewer($this->getViewer()) 13 + ->withPHIDs(array($phid)) 14 + ->needReviewerStatus(true) 15 + ->executeOne(); 16 + if (!$object) { 17 + throw new Exception("Unable to load object by phid '{$phid}'!"); 18 + } 19 + return $object; 20 + } 21 + 13 22 protected function buildAbstractDocumentByPHID($phid) { 14 23 $rev = $this->loadDocumentByPHID($phid); 15 24 ··· 20 29 $doc->setDocumentCreated($rev->getDateCreated()); 21 30 $doc->setDocumentModified($rev->getDateModified()); 22 31 23 - $aux_fields = DifferentialFieldSelector::newSelector() 24 - ->getFieldSpecifications(); 25 - foreach ($aux_fields as $key => $aux_field) { 26 - $aux_field->setUser(PhabricatorUser::getOmnipotentUser()); 27 - if (!$aux_field->shouldAddToSearchIndex()) { 28 - unset($aux_fields[$key]); 29 - } 30 - } 31 - 32 - $aux_fields = DifferentialAuxiliaryField::loadFromStorage( 33 - $rev, 34 - $aux_fields); 35 - foreach ($aux_fields as $aux_field) { 36 - $doc->addField( 37 - $aux_field->getKeyForSearchIndex(), 38 - $aux_field->getValueForSearchIndex()); 39 - } 40 - 41 32 $doc->addRelationship( 42 33 PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR, 43 34 $rev->getAuthorPHID(), ··· 52 43 DifferentialPHIDTypeRevision::TYPECONST, 53 44 time()); 54 45 55 - $comments = id(new DifferentialCommentQuery()) 56 - ->withRevisionPHIDs(array($rev->getPHID())) 57 - ->execute(); 58 - 59 - $inlines = id(new DifferentialInlineCommentQuery()) 60 - ->withRevisionIDs(array($rev->getID())) 61 - ->withNotDraft(true) 62 - ->execute(); 63 - 64 - foreach (array_merge($comments, $inlines) as $comment) { 65 - if (strlen($comment->getContent())) { 66 - $doc->addField( 67 - PhabricatorSearchField::FIELD_COMMENT, 68 - $comment->getContent()); 69 - } 70 - } 71 - 72 - $rev->loadRelationships(); 46 + $this->indexTransactions( 47 + $doc, 48 + new DifferentialTransactionQuery(), 49 + array($rev->getPHID())); 73 50 74 51 // If a revision needs review, the owners are the reviewers. Otherwise, the 75 52 // owner is the author (e.g., accepted, rejected, closed). 76 53 if ($rev->getStatus() == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) { 77 - $reviewers = $rev->getReviewers(); 54 + $reviewers = $rev->getReviewerStatus(); 55 + $reviewers = mpull($reviewers, 'getReviewerPHID', 'getReviewerPHID'); 78 56 if ($reviewers) { 79 57 foreach ($reviewers as $phid) { 80 58 $doc->addRelationship( ··· 96 74 $rev->getAuthorPHID(), 97 75 PhabricatorPHIDConstants::PHID_TYPE_VOID, 98 76 $rev->getDateCreated()); 99 - } 100 - 101 - $ccphids = $rev->getCCPHIDs(); 102 - $handles = id(new PhabricatorHandleQuery()) 103 - ->setViewer(PhabricatorUser::getOmnipotentUser()) 104 - ->withPHIDs($ccphids) 105 - ->execute(); 106 - 107 - foreach ($handles as $phid => $handle) { 108 - $doc->addRelationship( 109 - PhabricatorSearchRelationship::RELATIONSHIP_SUBSCRIBER, 110 - $phid, 111 - $handle->getType(), 112 - $rev->getDateModified()); // Bogus timestamp. 113 77 } 114 78 115 79 return $doc;
-2
src/applications/maniphest/search/ManiphestSearchIndexer.php
··· 81 81 time()); 82 82 } 83 83 84 - $this->indexCustomFields($doc, $task); 85 - 86 84 return $doc; 87 85 } 88 86 }
-2
src/applications/people/search/PhabricatorUserSearchIndexer.php
··· 25 25 PhabricatorPeoplePHIDTypeUser::TYPECONST, 26 26 time()); 27 27 28 - $this->indexCustomFields($doc, $user); 29 - 30 28 return $doc; 31 29 } 32 30 }
-2
src/applications/ponder/search/PonderSearchIndexer.php
··· 46 46 new PonderAnswerTransactionQuery(), 47 47 mpull($answers, 'getPHID')); 48 48 49 - $this->indexSubscribers($doc); 50 - 51 49 return $doc; 52 50 } 53 51 }
-3
src/applications/project/search/PhabricatorProjectSearchIndexer.php
··· 17 17 $doc->setDocumentCreated($project->getDateCreated()); 18 18 $doc->setDocumentModified($project->getDateModified()); 19 19 20 - $this->indexSubscribers($doc); 21 - $this->indexCustomFields($doc, $project); 22 - 23 20 $doc->addRelationship( 24 21 $project->isArchived() 25 22 ? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED
+19 -7
src/applications/search/index/PhabricatorSearchDocumentIndexer.php
··· 37 37 try { 38 38 $document = $this->buildAbstractDocumentByPHID($phid); 39 39 40 + $object = $this->loadDocumentByPHID($phid); 41 + 42 + // Automatically rebuild CustomField indexes if the object uses custom 43 + // fields. 44 + if ($object instanceof PhabricatorCustomFieldInterface) { 45 + $this->indexCustomFields($document, $object); 46 + } 47 + 48 + // Automatically rebuild subscriber indexes if the object is subscribable. 49 + if ($object instanceof PhabricatorSubscribableInterface) { 50 + $this->indexSubscribers($document); 51 + } 52 + 40 53 $engine = PhabricatorSearchEngineSelector::newSelector()->newEngine(); 41 54 try { 42 55 $engine->reindexAbstractDocument($document); ··· 107 120 } 108 121 109 122 protected function indexCustomFields( 110 - PhabricatorSearchAbstractDocument $doc, 123 + PhabricatorSearchAbstractDocument $document, 111 124 PhabricatorCustomFieldInterface $object) { 112 125 113 126 // Rebuild the ApplicationSearch indexes. These are internal and not part of ··· 116 129 117 130 $field_list = PhabricatorCustomField::getObjectFields( 118 131 $object, 119 - PhabricatorCustomField::ROLE_APPLICATIONSEARCH); 132 + PhabricatorCustomField::ROLE_DEFAULT); 120 133 121 134 $field_list->setViewer($this->getViewer()); 122 135 $field_list->readFieldsFromStorage($object); 136 + 137 + // Rebuild ApplicationSearch indexes. 123 138 $field_list->rebuildIndexes($object); 124 139 125 - // We could also allow fields to provide fulltext content, and index it 126 - // here on the document. No one has asked for this yet, though, and the 127 - // existing "search" key isn't a good fit to interpret to mean we should 128 - // index stuff here, since it can be set on a lot of fields which don't 129 - // contain anything resembling fulltext. 140 + // Rebuild global search indexes. 141 + $field_list->updateAbstractDocument($document); 130 142 } 131 143 132 144 private function dispatchDidUpdateIndexEvent(
+40 -10
src/infrastructure/customfield/field/PhabricatorCustomField.php
··· 1 1 <?php 2 2 3 3 /** 4 - * @task apps Building Applications with Custom Fields 5 - * @task core Core Properties and Field Identity 6 - * @task proxy Field Proxies 7 - * @task context Contextual Data 8 - * @task storage Field Storage 9 - * @task appsearch Integration with ApplicationSearch 10 - * @task appxaction Integration with ApplicationTransactions 11 - * @task edit Integration with edit views 12 - * @task view Integration with property views 13 - * @task list Integration with list views 4 + * @task apps Building Applications with Custom Fields 5 + * @task core Core Properties and Field Identity 6 + * @task proxy Field Proxies 7 + * @task context Contextual Data 8 + * @task storage Field Storage 9 + * @task edit Integration with Edit Views 10 + * @task view Integration with Property Views 11 + * @task list Integration with List views 12 + * @task appsearch Integration with ApplicationSearch 13 + * @task appxaction Integration with ApplicationTransactions 14 + * @task globalsearch Integration with Global Search 14 15 */ 15 16 abstract class PhabricatorCustomField { 16 17 ··· 25 26 const ROLE_EDIT = 'edit'; 26 27 const ROLE_VIEW = 'view'; 27 28 const ROLE_LIST = 'list'; 29 + const ROLE_GLOBALSEARCH = 'GlobalSearch'; 28 30 29 31 30 32 /* -( Building Applications with Custom Fields )--------------------------- */ ··· 253 255 return $this->shouldAppearInPropertyView(); 254 256 case self::ROLE_LIST: 255 257 return $this->shouldAppearInListView(); 258 + case self::ROLE_GLOBALSEARCH: 259 + return $this->shouldAppearInGlobalSearch(); 256 260 case self::ROLE_DEFAULT: 257 261 return true; 258 262 default: ··· 1088 1092 return $this->proxy->renderOnListItem($view); 1089 1093 } 1090 1094 throw new PhabricatorCustomFieldImplementationIncompleteException($this); 1095 + } 1096 + 1097 + 1098 + /* -( Global Search )------------------------------------------------------ */ 1099 + 1100 + 1101 + /** 1102 + * @task globalsearch 1103 + */ 1104 + public function shouldAppearInGlobalSearch() { 1105 + if ($this->proxy) { 1106 + return $this->proxy->shouldAppearInGlobalSearch(); 1107 + } 1108 + return false; 1109 + } 1110 + 1111 + 1112 + /** 1113 + * @task globalsearch 1114 + */ 1115 + public function updateAbstractDocument( 1116 + PhabricatorSearchAbstractDocument $document) { 1117 + if ($this->proxy) { 1118 + return $this->proxy->updateAbstractDocument($document); 1119 + } 1120 + return $document; 1091 1121 } 1092 1122 1093 1123
+18 -1
src/infrastructure/customfield/field/PhabricatorCustomFieldList.php
··· 52 52 } 53 53 54 54 if (!$keys) { 55 - return; 55 + return $this; 56 56 } 57 57 58 58 // NOTE: We assume all fields share the same storage. This isn't guaranteed ··· 79 79 $field->setValueFromStorage(null); 80 80 } 81 81 } 82 + 83 + return $this; 82 84 } 83 85 84 86 public function appendFieldsToForm(AphrontFormView $form) { ··· 303 305 304 306 $any_index->saveTransaction(); 305 307 } 308 + 309 + public function updateAbstractDocument( 310 + PhabricatorSearchAbstractDocument $document) { 311 + 312 + $role = PhabricatorCustomField::ROLE_GLOBALSEARCH; 313 + foreach ($this->getFields() as $field) { 314 + if (!$field->shouldEnableForRole($role)) { 315 + continue; 316 + } 317 + $field->updateAbstractDocument($document); 318 + } 319 + 320 + return $document; 321 + } 322 + 306 323 307 324 }