1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-03 11:21:01 +01:00

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
This commit is contained in:
epriestley 2014-02-26 11:18:06 -08:00
parent bcf255e9c9
commit cd080b092e
10 changed files with 118 additions and 81 deletions

View file

@ -78,4 +78,15 @@ final class DifferentialSummaryField
$xaction->getNewValue()); $xaction->getNewValue());
} }
public function shouldAppearInGlobalSearch() {
return true;
}
public function updateAbstractDocument(
PhabricatorSearchAbstractDocument $document) {
if (strlen($this->getValue())) {
$document->addField('body', $this->getValue());
}
}
} }

View file

@ -92,4 +92,16 @@ final class DifferentialTestPlanField
$xaction->getNewValue()); $xaction->getNewValue());
} }
public function shouldAppearInGlobalSearch() {
return true;
}
public function updateAbstractDocument(
PhabricatorSearchAbstractDocument $document) {
if (strlen($this->getValue())) {
$document->addField('plan', $this->getValue());
}
}
} }

View file

@ -1,8 +1,5 @@
<?php <?php
/**
* @group differential
*/
final class DifferentialSearchIndexer final class DifferentialSearchIndexer
extends PhabricatorSearchDocumentIndexer { extends PhabricatorSearchDocumentIndexer {
@ -10,6 +7,18 @@ final class DifferentialSearchIndexer
return new DifferentialRevision(); return new DifferentialRevision();
} }
protected function loadDocumentByPHID($phid) {
$object = id(new DifferentialRevisionQuery())
->setViewer($this->getViewer())
->withPHIDs(array($phid))
->needReviewerStatus(true)
->executeOne();
if (!$object) {
throw new Exception("Unable to load object by phid '{$phid}'!");
}
return $object;
}
protected function buildAbstractDocumentByPHID($phid) { protected function buildAbstractDocumentByPHID($phid) {
$rev = $this->loadDocumentByPHID($phid); $rev = $this->loadDocumentByPHID($phid);
@ -20,24 +29,6 @@ final class DifferentialSearchIndexer
$doc->setDocumentCreated($rev->getDateCreated()); $doc->setDocumentCreated($rev->getDateCreated());
$doc->setDocumentModified($rev->getDateModified()); $doc->setDocumentModified($rev->getDateModified());
$aux_fields = DifferentialFieldSelector::newSelector()
->getFieldSpecifications();
foreach ($aux_fields as $key => $aux_field) {
$aux_field->setUser(PhabricatorUser::getOmnipotentUser());
if (!$aux_field->shouldAddToSearchIndex()) {
unset($aux_fields[$key]);
}
}
$aux_fields = DifferentialAuxiliaryField::loadFromStorage(
$rev,
$aux_fields);
foreach ($aux_fields as $aux_field) {
$doc->addField(
$aux_field->getKeyForSearchIndex(),
$aux_field->getValueForSearchIndex());
}
$doc->addRelationship( $doc->addRelationship(
PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR, PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR,
$rev->getAuthorPHID(), $rev->getAuthorPHID(),
@ -52,29 +43,16 @@ final class DifferentialSearchIndexer
DifferentialPHIDTypeRevision::TYPECONST, DifferentialPHIDTypeRevision::TYPECONST,
time()); time());
$comments = id(new DifferentialCommentQuery()) $this->indexTransactions(
->withRevisionPHIDs(array($rev->getPHID())) $doc,
->execute(); new DifferentialTransactionQuery(),
array($rev->getPHID()));
$inlines = id(new DifferentialInlineCommentQuery())
->withRevisionIDs(array($rev->getID()))
->withNotDraft(true)
->execute();
foreach (array_merge($comments, $inlines) as $comment) {
if (strlen($comment->getContent())) {
$doc->addField(
PhabricatorSearchField::FIELD_COMMENT,
$comment->getContent());
}
}
$rev->loadRelationships();
// If a revision needs review, the owners are the reviewers. Otherwise, the // If a revision needs review, the owners are the reviewers. Otherwise, the
// owner is the author (e.g., accepted, rejected, closed). // owner is the author (e.g., accepted, rejected, closed).
if ($rev->getStatus() == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) { if ($rev->getStatus() == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) {
$reviewers = $rev->getReviewers(); $reviewers = $rev->getReviewerStatus();
$reviewers = mpull($reviewers, 'getReviewerPHID', 'getReviewerPHID');
if ($reviewers) { if ($reviewers) {
foreach ($reviewers as $phid) { foreach ($reviewers as $phid) {
$doc->addRelationship( $doc->addRelationship(
@ -98,20 +76,6 @@ final class DifferentialSearchIndexer
$rev->getDateCreated()); $rev->getDateCreated());
} }
$ccphids = $rev->getCCPHIDs();
$handles = id(new PhabricatorHandleQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs($ccphids)
->execute();
foreach ($handles as $phid => $handle) {
$doc->addRelationship(
PhabricatorSearchRelationship::RELATIONSHIP_SUBSCRIBER,
$phid,
$handle->getType(),
$rev->getDateModified()); // Bogus timestamp.
}
return $doc; return $doc;
} }
} }

View file

@ -81,8 +81,6 @@ final class ManiphestSearchIndexer
time()); time());
} }
$this->indexCustomFields($doc, $task);
return $doc; return $doc;
} }
} }

View file

@ -25,8 +25,6 @@ final class PhabricatorUserSearchIndexer
PhabricatorPeoplePHIDTypeUser::TYPECONST, PhabricatorPeoplePHIDTypeUser::TYPECONST,
time()); time());
$this->indexCustomFields($doc, $user);
return $doc; return $doc;
} }
} }

View file

@ -46,8 +46,6 @@ final class PonderSearchIndexer
new PonderAnswerTransactionQuery(), new PonderAnswerTransactionQuery(),
mpull($answers, 'getPHID')); mpull($answers, 'getPHID'));
$this->indexSubscribers($doc);
return $doc; return $doc;
} }
} }

View file

@ -17,9 +17,6 @@ final class PhabricatorProjectSearchIndexer
$doc->setDocumentCreated($project->getDateCreated()); $doc->setDocumentCreated($project->getDateCreated());
$doc->setDocumentModified($project->getDateModified()); $doc->setDocumentModified($project->getDateModified());
$this->indexSubscribers($doc);
$this->indexCustomFields($doc, $project);
$doc->addRelationship( $doc->addRelationship(
$project->isArchived() $project->isArchived()
? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED ? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED

View file

@ -37,6 +37,19 @@ abstract class PhabricatorSearchDocumentIndexer {
try { try {
$document = $this->buildAbstractDocumentByPHID($phid); $document = $this->buildAbstractDocumentByPHID($phid);
$object = $this->loadDocumentByPHID($phid);
// Automatically rebuild CustomField indexes if the object uses custom
// fields.
if ($object instanceof PhabricatorCustomFieldInterface) {
$this->indexCustomFields($document, $object);
}
// Automatically rebuild subscriber indexes if the object is subscribable.
if ($object instanceof PhabricatorSubscribableInterface) {
$this->indexSubscribers($document);
}
$engine = PhabricatorSearchEngineSelector::newSelector()->newEngine(); $engine = PhabricatorSearchEngineSelector::newSelector()->newEngine();
try { try {
$engine->reindexAbstractDocument($document); $engine->reindexAbstractDocument($document);
@ -107,7 +120,7 @@ abstract class PhabricatorSearchDocumentIndexer {
} }
protected function indexCustomFields( protected function indexCustomFields(
PhabricatorSearchAbstractDocument $doc, PhabricatorSearchAbstractDocument $document,
PhabricatorCustomFieldInterface $object) { PhabricatorCustomFieldInterface $object) {
// Rebuild the ApplicationSearch indexes. These are internal and not part of // Rebuild the ApplicationSearch indexes. These are internal and not part of
@ -116,17 +129,16 @@ abstract class PhabricatorSearchDocumentIndexer {
$field_list = PhabricatorCustomField::getObjectFields( $field_list = PhabricatorCustomField::getObjectFields(
$object, $object,
PhabricatorCustomField::ROLE_APPLICATIONSEARCH); PhabricatorCustomField::ROLE_DEFAULT);
$field_list->setViewer($this->getViewer()); $field_list->setViewer($this->getViewer());
$field_list->readFieldsFromStorage($object); $field_list->readFieldsFromStorage($object);
// Rebuild ApplicationSearch indexes.
$field_list->rebuildIndexes($object); $field_list->rebuildIndexes($object);
// We could also allow fields to provide fulltext content, and index it // Rebuild global search indexes.
// here on the document. No one has asked for this yet, though, and the $field_list->updateAbstractDocument($document);
// existing "search" key isn't a good fit to interpret to mean we should
// index stuff here, since it can be set on a lot of fields which don't
// contain anything resembling fulltext.
} }
private function dispatchDidUpdateIndexEvent( private function dispatchDidUpdateIndexEvent(

View file

@ -1,16 +1,17 @@
<?php <?php
/** /**
* @task apps Building Applications with Custom Fields * @task apps Building Applications with Custom Fields
* @task core Core Properties and Field Identity * @task core Core Properties and Field Identity
* @task proxy Field Proxies * @task proxy Field Proxies
* @task context Contextual Data * @task context Contextual Data
* @task storage Field Storage * @task storage Field Storage
* @task appsearch Integration with ApplicationSearch * @task edit Integration with Edit Views
* @task appxaction Integration with ApplicationTransactions * @task view Integration with Property Views
* @task edit Integration with edit views * @task list Integration with List views
* @task view Integration with property views * @task appsearch Integration with ApplicationSearch
* @task list Integration with list views * @task appxaction Integration with ApplicationTransactions
* @task globalsearch Integration with Global Search
*/ */
abstract class PhabricatorCustomField { abstract class PhabricatorCustomField {
@ -25,6 +26,7 @@ abstract class PhabricatorCustomField {
const ROLE_EDIT = 'edit'; const ROLE_EDIT = 'edit';
const ROLE_VIEW = 'view'; const ROLE_VIEW = 'view';
const ROLE_LIST = 'list'; const ROLE_LIST = 'list';
const ROLE_GLOBALSEARCH = 'GlobalSearch';
/* -( Building Applications with Custom Fields )--------------------------- */ /* -( Building Applications with Custom Fields )--------------------------- */
@ -253,6 +255,8 @@ abstract class PhabricatorCustomField {
return $this->shouldAppearInPropertyView(); return $this->shouldAppearInPropertyView();
case self::ROLE_LIST: case self::ROLE_LIST:
return $this->shouldAppearInListView(); return $this->shouldAppearInListView();
case self::ROLE_GLOBALSEARCH:
return $this->shouldAppearInGlobalSearch();
case self::ROLE_DEFAULT: case self::ROLE_DEFAULT:
return true; return true;
default: default:
@ -1091,4 +1095,30 @@ abstract class PhabricatorCustomField {
} }
/* -( Global Search )------------------------------------------------------ */
/**
* @task globalsearch
*/
public function shouldAppearInGlobalSearch() {
if ($this->proxy) {
return $this->proxy->shouldAppearInGlobalSearch();
}
return false;
}
/**
* @task globalsearch
*/
public function updateAbstractDocument(
PhabricatorSearchAbstractDocument $document) {
if ($this->proxy) {
return $this->proxy->updateAbstractDocument($document);
}
return $document;
}
} }

View file

@ -52,7 +52,7 @@ final class PhabricatorCustomFieldList extends Phobject {
} }
if (!$keys) { if (!$keys) {
return; return $this;
} }
// NOTE: We assume all fields share the same storage. This isn't guaranteed // NOTE: We assume all fields share the same storage. This isn't guaranteed
@ -79,6 +79,8 @@ final class PhabricatorCustomFieldList extends Phobject {
$field->setValueFromStorage(null); $field->setValueFromStorage(null);
} }
} }
return $this;
} }
public function appendFieldsToForm(AphrontFormView $form) { public function appendFieldsToForm(AphrontFormView $form) {
@ -304,4 +306,19 @@ final class PhabricatorCustomFieldList extends Phobject {
$any_index->saveTransaction(); $any_index->saveTransaction();
} }
public function updateAbstractDocument(
PhabricatorSearchAbstractDocument $document) {
$role = PhabricatorCustomField::ROLE_GLOBALSEARCH;
foreach ($this->getFields() as $field) {
if (!$field->shouldEnableForRole($role)) {
continue;
}
$field->updateAbstractDocument($document);
}
return $document;
}
} }