Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15193825
D17608.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
16 KB
Referenced Files
None
Subscribers
None
D17608.diff
View Options
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -103,7 +103,7 @@
'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd',
'rsrc/css/application/releeph/releeph-request-typeahead.css' => '667a48ae',
'rsrc/css/application/search/application-search-view.css' => '66ee5d46',
- 'rsrc/css/application/search/search-results.css' => '64ad079a',
+ 'rsrc/css/application/search/search-results.css' => '9fc45e8d',
'rsrc/css/application/slowvote/slowvote.css' => 'a94b7230',
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
'rsrc/css/application/uiexample/example.css' => '528b19de',
@@ -794,7 +794,7 @@
'phabricator-phtize' => 'd254d646',
'phabricator-prefab' => '8d40ae75',
'phabricator-remarkup-css' => '17c0fb37',
- 'phabricator-search-results-css' => '64ad079a',
+ 'phabricator-search-results-css' => '9fc45e8d',
'phabricator-shaped-request' => '7cbe244b',
'phabricator-slowvote-css' => 'a94b7230',
'phabricator-source-code-view-css' => '4383192f',
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2833,6 +2833,7 @@
'PhabricatorFulltextEngineExtensionModule' => 'applications/search/index/PhabricatorFulltextEngineExtensionModule.php',
'PhabricatorFulltextIndexEngineExtension' => 'applications/search/engineextension/PhabricatorFulltextIndexEngineExtension.php',
'PhabricatorFulltextInterface' => 'applications/search/interface/PhabricatorFulltextInterface.php',
+ 'PhabricatorFulltextResult' => 'applications/search/fulltextstorage/PhabricatorFulltextResult.php',
'PhabricatorFulltextStorageEngine' => 'applications/search/fulltextstorage/PhabricatorFulltextStorageEngine.php',
'PhabricatorFundApplication' => 'applications/fund/application/PhabricatorFundApplication.php',
'PhabricatorGDSetupCheck' => 'applications/config/check/PhabricatorGDSetupCheck.php',
@@ -3807,6 +3808,8 @@
'PhabricatorSearchRelationshipSourceController' => 'applications/search/controller/PhabricatorSearchRelationshipSourceController.php',
'PhabricatorSearchResultBucket' => 'applications/search/buckets/PhabricatorSearchResultBucket.php',
'PhabricatorSearchResultBucketGroup' => 'applications/search/buckets/PhabricatorSearchResultBucketGroup.php',
+ 'PhabricatorSearchResultEngineExtension' => 'applications/search/engineextension/PhabricatorSearchResultEngineExtension.php',
+ 'PhabricatorSearchResultHighlightsEngineExtension' => 'applications/search/engineextension/PhabricatorSearchResultHighlightsEngineExtension.php',
'PhabricatorSearchResultView' => 'applications/search/view/PhabricatorSearchResultView.php',
'PhabricatorSearchSchemaSpec' => 'applications/search/storage/PhabricatorSearchSchemaSpec.php',
'PhabricatorSearchScopeSetting' => 'applications/settings/setting/PhabricatorSearchScopeSetting.php',
@@ -7960,6 +7963,7 @@
'PhabricatorFulltextEngineExtension' => 'Phobject',
'PhabricatorFulltextEngineExtensionModule' => 'PhabricatorConfigModule',
'PhabricatorFulltextIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
+ 'PhabricatorFulltextResult' => 'PhabricatorPolicyInterface',
'PhabricatorFulltextStorageEngine' => 'Phobject',
'PhabricatorFundApplication' => 'PhabricatorApplication',
'PhabricatorGDSetupCheck' => 'PhabricatorSetupCheck',
@@ -9127,6 +9131,8 @@
'PhabricatorSearchRelationshipSourceController' => 'PhabricatorSearchBaseController',
'PhabricatorSearchResultBucket' => 'Phobject',
'PhabricatorSearchResultBucketGroup' => 'Phobject',
+ 'PhabricatorSearchResultEngineExtension' => 'Phobject',
+ 'PhabricatorSearchResultHighlightsEngineExtension' => 'PhabricatorSearchResultEngineExtension',
'PhabricatorSearchResultView' => 'AphrontView',
'PhabricatorSearchSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorSearchScopeSetting' => 'PhabricatorInternalSetting',
diff --git a/src/applications/maniphest/query/ManiphestTaskQuery.php b/src/applications/maniphest/query/ManiphestTaskQuery.php
--- a/src/applications/maniphest/query/ManiphestTaskQuery.php
+++ b/src/applications/maniphest/query/ManiphestTaskQuery.php
@@ -524,6 +524,8 @@
if (empty($fulltext_results)) {
$fulltext_results = array(null);
+ } else {
+ $fulltext_results = array_keys($fulltext_results);
}
return qsprintf(
diff --git a/src/applications/search/engineextension/PhabricatorSearchResultEngineExtension.php b/src/applications/search/engineextension/PhabricatorSearchResultEngineExtension.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/engineextension/PhabricatorSearchResultEngineExtension.php
@@ -0,0 +1,63 @@
+<?php
+
+abstract class PhabricatorSearchResultEngineExtension 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 canRenderItemView(PhabricatorFulltextResult $result);
+
+ public function getExtensionOrder() {
+ return 5000;
+ }
+
+ public function willRenderItemView(array $objects) {
+ return null;
+ }
+
+ abstract public function renderItemView(
+ PHUIObjectItemView $item,
+ PhabricatorFulltextResult $result);
+
+
+ final public static function getAllExtensions() {
+ return id(new PhutilClassMapQuery())
+ ->setAncestorClass(__CLASS__)
+ ->setUniqueMethod('getExtensionKey')
+ ->setSortMethod('getExtensionOrder')
+ ->execute();
+ }
+
+ /**
+ * @return PhabricatorSearchResultEngineExtension[]
+ */
+ final public static function getAllEnabledExtensions() {
+ $extensions = self::getAllExtensions();
+
+ foreach ($extensions as $key => $extension) {
+ if (!$extension->isExtensionEnabled()) {
+ unset($extensions[$key]);
+ }
+ }
+
+ return $extensions;
+ }
+
+
+}
diff --git a/src/applications/search/engineextension/PhabricatorSearchResultHighlightsEngineExtension.php b/src/applications/search/engineextension/PhabricatorSearchResultHighlightsEngineExtension.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/engineextension/PhabricatorSearchResultHighlightsEngineExtension.php
@@ -0,0 +1,42 @@
+<?php
+
+class PhabricatorSearchResultHighlightsEngineExtension
+ extends PhabricatorSearchResultEngineExtension {
+
+ const EXTENSIONKEY = 'highlights';
+
+ public function isExtensionEnabled() {
+ return true;
+ }
+
+ public function getExtensionName() {
+ return 'SearchResultHighlights';
+ }
+
+ public function canRenderItemView(PhabricatorFulltextResult $result) {
+ return true;
+ }
+
+ public function renderItemView(
+ PHUIObjectItemView $item,
+ PhabricatorFulltextResult $result) {
+
+ $highlights = $result->getHighlights('body');
+ if ($highlights) {
+ $highlight_view = phutil_tag_div('phui-oi-subhead',
+ array(
+ phutil_tag('span', array(
+ 'class' => 'visual-only phui-icon-view phui-font-fa fa-quote-left',
+ )),
+ ' ',
+ phutil_safe_html($highlights),
+ ' ... ',
+ ));
+ $item->appendChild($highlight_view);
+
+ }
+
+ return $item;
+ }
+
+}
diff --git a/src/applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php b/src/applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php
--- a/src/applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php
+++ b/src/applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php
@@ -142,6 +142,10 @@
}
private function buildSpec(PhabricatorSavedQuery $query) {
+ $field_title = PhabricatorSearchDocumentFieldType::FIELD_TITLE;
+ $field_body = PhabricatorSearchDocumentFieldType::FIELD_BODY;
+ $field_comment = PhabricatorSearchDocumentFieldType::FIELD_COMMENT;
+
$q = new PhabricatorElasticsearchQueryBuilder('bool');
$query_string = $query->getParameter('query');
if (strlen($query_string)) {
@@ -153,9 +157,10 @@
'simple_query_string' => array(
'query' => $query_string,
'fields' => array(
- PhabricatorSearchDocumentFieldType::FIELD_TITLE.'.*',
- PhabricatorSearchDocumentFieldType::FIELD_BODY.'.*',
- PhabricatorSearchDocumentFieldType::FIELD_COMMENT.'.*',
+ $field_title.'.*',
+ $field_body,
+ $field_body.'.*',
+ $field_comment.'.*',
),
'default_operator' => 'AND',
),
@@ -170,12 +175,12 @@
'query' => $query_string,
'fields' => array(
'*.raw',
- PhabricatorSearchDocumentFieldType::FIELD_TITLE.'^4',
- PhabricatorSearchDocumentFieldType::FIELD_BODY.'^3',
- PhabricatorSearchDocumentFieldType::FIELD_COMMENT.'^1.2',
+ $field_title.'^4',
+ $field_body.'^3',
+ $field_comment.'^1.2',
),
'analyzer' => 'english_exact',
- 'default_operator' => 'and',
+ 'default_operator' => 'AND',
),
));
@@ -268,6 +273,20 @@
$spec['from'] = $offset;
$spec['size'] = $limit;
+ $spec['highlight'] = array(
+ 'pre_tags' => array('<strong>'),
+ 'post_tags' => array('</strong>'),
+ 'fields' => array(
+ $field_body => array(
+ 'matched_fields' => array(
+ $field_body.'.raw',
+ $field_body.'.keywords',
+ $field_body.'.stems',
+ ),
+ ),
+ ),
+ );
+
return $spec;
}
@@ -289,8 +308,18 @@
foreach ($this->service->getAllHostsForRole('read') as $host) {
try {
$response = $this->executeRequest($host, $uri, $spec);
- $phids = ipull($response['hits']['hits'], '_id');
- return $phids;
+
+ $hits = array();
+ foreach ($response['hits']['hits'] as $hit) {
+ $phid = $hit['_id'];
+ $result = new PhabricatorFulltextResult($phid);
+ if (isset($hit['highlight'])) {
+ $result->setHighlights($hit['highlight']);
+ }
+ $hits[$phid] = $result;
+ }
+ // phlog($hits);
+ return $hits;
} catch (Exception $e) {
$exceptions[] = $e;
}
diff --git a/src/applications/search/fulltextstorage/PhabricatorFulltextResult.php b/src/applications/search/fulltextstorage/PhabricatorFulltextResult.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/fulltextstorage/PhabricatorFulltextResult.php
@@ -0,0 +1,74 @@
+<?php
+
+class PhabricatorFulltextResult
+ implements PhabricatorPolicyInterface {
+
+ protected $handle;
+ protected $fields = array();
+ protected $phid;
+ protected $type;
+
+ public function __construct($phid) {
+ $this->setPHID($phid);
+ }
+
+ public function setPHID($phid) {
+ $this->phid = $phid;
+ $this->type = phid_get_type($phid);
+ return $this;
+ }
+
+ public function getPHID() {
+ return $this->phid;
+ }
+
+ public function getType() {
+ return $this->type;
+ }
+
+ /**
+ * @return PhabricatorObjectHandle
+ */
+ public function getHandle() {
+ return $this->handle;
+ }
+
+ public function setHandle($handle) {
+ $this->handle = $handle;
+ return $this;
+ }
+
+ public function setHighlights($highlights) {
+ if (!$highlights) {
+ return;
+ }
+
+ foreach ($highlights as $field => $values) {
+ $this->fields[$field] = implode(' ... ', array_slice($values, 0, 2));
+ }
+ }
+
+ public function getHighlights($field = 'all') {
+ if ($field == 'all') {
+ return phutil_safe_html(implode('<br/>', $this->fields));
+ } else if (!isset($this->fields[$field])) {
+ return '';
+ }
+ return phutil_safe_html($this->fields[$field]);
+ }
+
+/* -( PhabricatorPolicyInterface )----------------------------------------- */
+
+ public function getCapabilities() {
+ return $this->handle->getCapabilities();
+ }
+
+ public function getPolicy($capability) {
+ return $this->handle->getPolicy($capability);
+ }
+
+ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+ return $this->handle->hasAutomaticCapability($capability, $viewer);
+ }
+
+}
diff --git a/src/applications/search/query/PhabricatorSearchApplicationSearchEngine.php b/src/applications/search/query/PhabricatorSearchApplicationSearchEngine.php
--- a/src/applications/search/query/PhabricatorSearchApplicationSearchEngine.php
+++ b/src/applications/search/query/PhabricatorSearchApplicationSearchEngine.php
@@ -253,9 +253,9 @@
->withPHIDs(mpull($results, 'getPHID'))
->execute();
- foreach ($results as $phid => $handle) {
+ foreach ($results as $phid => $result) {
$view = id(new PhabricatorSearchResultView())
- ->setHandle($handle)
+ ->setFulltextResult($result)
->setQuery($query)
->setObject(idx($objects, $phid))
->render();
diff --git a/src/applications/search/query/PhabricatorSearchDocumentQuery.php b/src/applications/search/query/PhabricatorSearchDocumentQuery.php
--- a/src/applications/search/query/PhabricatorSearchDocumentQuery.php
+++ b/src/applications/search/query/PhabricatorSearchDocumentQuery.php
@@ -24,7 +24,8 @@
}
protected function loadPage() {
- $phids = $this->loadDocumentPHIDsWithoutPolicyChecks();
+ $results = $this->loadDocumentHitsWithoutPolicyChecks();
+ $phids = array_keys($results);
$handles = id(new PhabricatorHandleQuery())
->setViewer($this->getViewer())
@@ -32,13 +33,14 @@
->withPHIDs($phids)
->execute();
- // Retain engine order.
- $handles = array_select_keys($handles, $phids);
+ foreach ($phids as $phid) {
+ $results[$phid]->setHandle($handles[$phid]);
+ }
- return $handles;
+ return $results;
}
- protected function willFilterPage(array $handles) {
+ protected function willFilterPage(array $results) {
// NOTE: This is used by the object selector dialog to exclude the object
// you're looking at, so that, e.g., a task can't be set as a dependency
// of itself in the UI.
@@ -51,25 +53,26 @@
$exclude = array_fuse($exclude_phids);
}
- foreach ($handles as $key => $handle) {
+ foreach ($results as $key => $result) {
+ $handle = $result->getHandle();
if (!$handle->isComplete()) {
- unset($handles[$key]);
+ unset($results[$key]);
continue;
}
if ($handle->getPolicyFiltered()) {
- unset($handles[$key]);
+ unset($results[$key]);
continue;
}
if (isset($exclude[$handle->getPHID()])) {
- unset($handles[$key]);
+ unset($results[$key]);
continue;
}
}
- return $handles;
+ return $results;
}
- public function loadDocumentPHIDsWithoutPolicyChecks() {
+ public function loadDocumentHitsWithoutPolicyChecks() {
$query = id(clone($this->savedQuery))
->setParameter('offset', $this->getOffset())
->setParameter('limit', $this->getRawResultLimit());
diff --git a/src/applications/search/view/PhabricatorSearchResultView.php b/src/applications/search/view/PhabricatorSearchResultView.php
--- a/src/applications/search/view/PhabricatorSearchResultView.php
+++ b/src/applications/search/view/PhabricatorSearchResultView.php
@@ -5,12 +5,19 @@
private $handle;
private $query;
private $object;
+ private $result;
public function setHandle(PhabricatorObjectHandle $handle) {
$this->handle = $handle;
return $this;
}
+ public function setFulltextResult(PhabricatorFulltextResult $result) {
+ $this->result = $result;
+ $this->setHandle($result->getHandle());
+ return $this;
+ }
+
public function setQuery(PhabricatorSavedQuery $query) {
$this->query = $query;
return $this;
@@ -46,6 +53,13 @@
$item->addAttribute(pht('Closed'));
}
+ $ext = PhabricatorSearchResultEngineExtension::getAllEnabledExtensions();
+ foreach ($ext as $extension) {
+ if ($extension->canRenderItemView($this->result)) {
+ $item = $extension->renderItemView($item, $this->result);
+ }
+ }
+
return $item;
}
diff --git a/webroot/rsrc/css/application/search/search-results.css b/webroot/rsrc/css/application/search/search-results.css
--- a/webroot/rsrc/css/application/search/search-results.css
+++ b/webroot/rsrc/css/application/search/search-results.css
@@ -2,7 +2,7 @@
* @provides phabricator-search-results-css
*/
-.phui-oi-link strong {
+.phui-oi-link strong, .phui-oi-subhead strong {
color: {$fire};
text-decoration: underline;
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Feb 23, 6:53 AM (6 h, 36 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7185154
Default Alt Text
D17608.diff (16 KB)
Attached To
Mode
D17608: Add highlighting support to Elasticsearch fulltext engine
Attached
Detach File
Event Timeline
Log In to Comment