Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15407745
D8123.id18371.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
30 KB
Referenced Files
None
Subscribers
None
D8123.id18371.diff
View Options
diff --git a/src/applications/search/application/PhabricatorApplicationSearch.php b/src/applications/search/application/PhabricatorApplicationSearch.php
--- a/src/applications/search/application/PhabricatorApplicationSearch.php
+++ b/src/applications/search/application/PhabricatorApplicationSearch.php
@@ -29,8 +29,7 @@
public function getRoutes() {
return array(
'/search/' => array(
- '' => 'PhabricatorSearchController',
- '(?P<key>[^/]+)/' => 'PhabricatorSearchController',
+ '(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorSearchController',
'attach/(?P<phid>[^/]+)/(?P<type>\w+)/(?:(?P<action>\w+)/)?'
=> 'PhabricatorSearchAttachController',
'select/(?P<type>\w+)/'
diff --git a/src/applications/search/controller/PhabricatorSearchController.php b/src/applications/search/controller/PhabricatorSearchController.php
--- a/src/applications/search/controller/PhabricatorSearchController.php
+++ b/src/applications/search/controller/PhabricatorSearchController.php
@@ -1,298 +1,98 @@
<?php
-/**
- * @group search
- */
final class PhabricatorSearchController
- extends PhabricatorSearchBaseController {
+ extends PhabricatorSearchBaseController
+ implements PhabricatorApplicationSearchResultsControllerInterface {
- private $key;
+ private $queryKey;
public function shouldAllowPublic() {
return true;
}
public function willProcessRequest(array $data) {
- $this->key = idx($data, 'key');
+ $this->queryKey = idx($data, 'queryKey');
}
public function processRequest() {
$request = $this->getRequest();
- $user = $request->getUser();
-
- if ($this->key) {
- $query = id(new PhabricatorSavedQuery())->loadOneWhere(
- 'queryKey = %s',
- $this->key);
- if (!$query) {
- return new Aphront404Response();
- }
- } else {
- $query = id(new PhabricatorSavedQuery())
- ->setEngineClassName('PhabricatorSearchApplicationSearchEngine');
-
- if ($request->isFormPost()) {
- $query_str = $request->getStr('query');
-
- $pref_jump = PhabricatorUserPreferences::PREFERENCE_SEARCHBAR_JUMP;
- if ($request->getStr('jump') != 'no' &&
- $user && $user->loadPreferences()->getPreference($pref_jump, 1)) {
- $response = PhabricatorJumpNavHandler::getJumpResponse(
- $user,
- $query_str);
- } else {
- $response = null;
- }
+ $viewer = $request->getUser();
+
+ if ($request->getStr('jump') != 'no') {
+ $pref_jump = PhabricatorUserPreferences::PREFERENCE_SEARCHBAR_JUMP;
+ if ($viewer->loadPreferences($pref_jump, 1)) {
+ $response = PhabricatorJumpNavHandler::getJumpResponse(
+ $viewer,
+ $request->getStr('query'));
if ($response) {
return $response;
- } else {
- $query->setParameter('query', $query_str);
-
- if ($request->getStr('scope')) {
- switch ($request->getStr('scope')) {
- case PhabricatorSearchScope::SCOPE_OPEN_REVISIONS:
- $query->setParameter('open', 1);
- $query->setParameter(
- 'type',
- DifferentialPHIDTypeRevision::TYPECONST);
- break;
- case PhabricatorSearchScope::SCOPE_OPEN_TASKS:
- $query->setParameter('open', 1);
- $query->setParameter(
- 'type',
- ManiphestPHIDTypeTask::TYPECONST);
- break;
- case PhabricatorSearchScope::SCOPE_WIKI:
- $query->setParameter(
- 'type',
- PhrictionPHIDTypeDocument::TYPECONST);
- break;
- case PhabricatorSearchScope::SCOPE_COMMITS:
- $query->setParameter(
- 'type',
- PhabricatorRepositoryPHIDTypeCommit::TYPECONST);
- break;
- default:
- break;
- }
- } else {
- if (strlen($request->getStr('type'))) {
- $query->setParameter('type', $request->getStr('type'));
- }
-
- if ($request->getArr('author')) {
- $query->setParameter('author', $request->getArr('author'));
- }
-
- if ($request->getArr('owner')) {
- $query->setParameter('owner', $request->getArr('owner'));
- }
-
- if ($request->getArr('subscribers')) {
- $query->setParameter('subscribers',
- $request->getArr('subscribers'));
- }
-
- if ($request->getInt('open')) {
- $query->setParameter('open', $request->getInt('open'));
- }
-
- if ($request->getArr('project')) {
- $query->setParameter('project', $request->getArr('project'));
- }
- }
-
- try {
- $query->save();
- } catch (AphrontQueryDuplicateKeyException $ex) {
- // Someone has already executed this query.
- }
- return id(new AphrontRedirectResponse())
- ->setURI('/search/'.$query->getQueryKey().'/');
}
}
}
- $options = array(
- '' => 'All Documents',
- ) + PhabricatorSearchAbstractDocument::getSupportedTypes();
-
- $status_options = array(
- 0 => 'Open and Closed Documents',
- 1 => 'Open Documents',
- );
-
- $phids = array_merge(
- $query->getParameter('author', array()),
- $query->getParameter('owner', array()),
- $query->getParameter('subscribers', array()),
- $query->getParameter('project', array()));
-
- $handles = $this->loadViewerHandles($phids);
+ $controller = id(new PhabricatorApplicationSearchController($request))
+ ->setQueryKey($this->queryKey)
+ ->setSearchEngine(new PhabricatorSearchApplicationSearchEngine())
+ ->setUseOffsetPaging(true)
+ ->setNavigation($this->buildSideNavView());
- $author_value = array_select_keys(
- $handles,
- $query->getParameter('author', array()));
-
- $owner_value = array_select_keys(
- $handles,
- $query->getParameter('owner', array()));
-
- $subscribers_value = array_select_keys(
- $handles,
- $query->getParameter('subscribers', array()));
-
- $project_value = array_select_keys(
- $handles,
- $query->getParameter('project', array()));
-
- $search_form = new AphrontFormView();
- $search_form
- ->setUser($user)
- ->setAction('/search/')
- ->appendChild(
- phutil_tag(
- 'input',
- array(
- 'type' => 'hidden',
- 'name' => 'jump',
- 'value' => 'no',
- )))
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel('Search')
- ->setName('query')
- ->setValue($query->getParameter('query')))
- ->appendChild(
- id(new AphrontFormSelectControl())
- ->setLabel('Document Type')
- ->setName('type')
- ->setOptions($options)
- ->setValue($query->getParameter('type')))
- ->appendChild(
- id(new AphrontFormSelectControl())
- ->setLabel('Document Status')
- ->setName('open')
- ->setOptions($status_options)
- ->setValue($query->getParameter('open')))
- ->appendChild(
- id(new AphrontFormTokenizerControl())
- ->setName('author')
- ->setLabel('Author')
- ->setDatasource('/typeahead/common/users/')
- ->setValue($author_value))
- ->appendChild(
- id(new AphrontFormTokenizerControl())
- ->setName('owner')
- ->setLabel('Owner')
- ->setDatasource('/typeahead/common/searchowner/')
- ->setValue($owner_value)
- ->setCaption(
- 'Tip: search for "Up For Grabs" to find unowned documents.'))
- ->appendChild(
- id(new AphrontFormTokenizerControl())
- ->setName('subscribers')
- ->setLabel('Subscribers')
- ->setDatasource('/typeahead/common/users/')
- ->setValue($subscribers_value))
- ->appendChild(
- id(new AphrontFormTokenizerControl())
- ->setName('project')
- ->setLabel('Project')
- ->setDatasource('/typeahead/common/projects/')
- ->setValue($project_value))
- ->appendChild(
- id(new AphrontFormSubmitControl())
- ->setValue('Search'));
-
- $search_panel = new AphrontListFilterView();
- $search_panel->appendChild($search_form);
-
- require_celerity_resource('phabricator-search-results-css');
+ return $this->delegateToController($controller);
+ }
- if ($query->getID()) {
+ public function buildSideNavView($for_app = false) {
+ $viewer = $this->getRequest()->getUser();
- $limit = 20;
+ $nav = new AphrontSideNavFilterView();
+ $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
- $pager = new AphrontPagerView();
- $pager->setURI($request->getRequestURI(), 'page');
- $pager->setPageSize($limit);
- $pager->setOffset($request->getInt('page'));
+ id(new PhabricatorSearchApplicationSearchEngine())
+ ->setViewer($viewer)
+ ->addNavigationItems($nav->getMenu());
- $query->setParameter('limit', $limit + 1);
- $query->setParameter('offset', $pager->getOffset());
+ $nav->selectFilter(null);
- $engine = PhabricatorSearchEngineSelector::newSelector()->newEngine();
- $results = $engine->executeSearch($query);
- $results = $pager->sliceResults($results);
+ return $nav;
+ }
- // If there are any objects which match the query by name, and we're
- // not paging through the results, prefix the results with the named
- // objects.
- if (!$request->getInt('page')) {
- $named = id(new PhabricatorObjectQuery())
- ->setViewer($user)
- ->withNames(array($query->getParameter('queyr')))
- ->execute();
- if ($named) {
- $results = array_merge(array_keys($named), $results);
- }
+ public function renderResultsList(
+ array $results,
+ PhabricatorSavedQuery $query) {
+
+ $viewer = $this->getRequest()->getUser();
+
+ if ($results) {
+ $objects = id(new PhabricatorObjectQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(mpull($results, 'getPHID'))
+ ->execute();
+
+ $output = array();
+ foreach ($results as $phid => $handle) {
+ $view = id(new PhabricatorSearchResultView())
+ ->setHandle($handle)
+ ->setQuery($query)
+ ->setObject(idx($objects, $phid));
+ $output[] = $view->render();
}
- if ($results) {
- $handles = id(new PhabricatorHandleQuery())
- ->setViewer($user)
- ->withPHIDs($results)
- ->execute();
- $objects = id(new PhabricatorObjectQuery())
- ->setViewer($user)
- ->withPHIDs($results)
- ->execute();
- $results = array();
- foreach ($handles as $phid => $handle) {
- $view = id(new PhabricatorSearchResultView())
- ->setHandle($handle)
- ->setQuery($query)
- ->setObject(idx($objects, $phid));
- $results[] = $view->render();
- }
-
- $results = phutil_tag_div('phabricator-search-result-list', array(
- phutil_implode_html("\n", $results),
- phutil_tag_div('search-results-pager', $pager->render()),
- ));
- } else {
- $results = phutil_tag_div(
- 'phabricator-search-result-list',
- phutil_tag(
- 'p',
- array('class' => 'phabricator-search-no-results'),
- pht('No search results.')));
- }
- $results = id(new PHUIBoxView())
- ->addMargin(PHUI::MARGIN_LARGE)
- ->addPadding(PHUI::PADDING_LARGE)
- ->setShadow(true)
- ->appendChild($results)
- ->addClass('phabricator-search-result-box');
+ $results = phutil_tag_div(
+ 'phabricator-search-result-list',
+ $output);
} else {
- $results = null;
+ $results = phutil_tag_div(
+ 'phabricator-search-result-list',
+ phutil_tag(
+ 'p',
+ array('class' => 'phabricator-search-no-results'),
+ pht('No search results.')));
}
- $crumbs = $this->buildApplicationCrumbs();
- $crumbs->addTextCrumb(pht('Search'));
-
- return $this->buildApplicationPage(
- array(
- $crumbs,
- $search_panel,
- $results,
- ),
- array(
- 'title' => pht('Search Results'),
- 'device' => true,
- ));
+ return id(new PHUIBoxView())
+ ->addMargin(PHUI::MARGIN_LARGE)
+ ->addPadding(PHUI::PADDING_LARGE)
+ ->setShadow(true)
+ ->appendChild($results)
+ ->addClass('phabricator-search-result-box');
}
-
}
diff --git a/src/applications/search/engine/PhabricatorSearchEngineElastic.php b/src/applications/search/engine/PhabricatorSearchEngineElastic.php
--- a/src/applications/search/engine/PhabricatorSearchEngineElastic.php
+++ b/src/applications/search/engine/PhabricatorSearchEngineElastic.php
@@ -114,17 +114,41 @@
);
}
- $rel_mapping = array(
- 'author' => PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR,
- 'open' => PhabricatorSearchRelationship::RELATIONSHIP_OPEN,
- 'owner' => PhabricatorSearchRelationship::RELATIONSHIP_OWNER,
- 'subscribers' => PhabricatorSearchRelationship::RELATIONSHIP_SUBSCRIBER,
- 'project' => PhabricatorSearchRelationship::RELATIONSHIP_PROJECT,
- 'repository' => PhabricatorSearchRelationship::RELATIONSHIP_REPOSITORY,
+ $relationship_map = array(
+ PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR =>
+ $query->getParameter('authorPHIDs', array()),
+ PhabricatorSearchRelationship::RELATIONSHIP_OWNER =>
+ $query->getParameter('ownerPHIDs', array()),
+ PhabricatorSearchRelationship::RELATIONSHIP_SUBSCRIBER =>
+ $query->getParameter('subscriberPHIDs', array()),
+ PhabricatorSearchRelationship::RELATIONSHIP_PROJECT =>
+ $query->getParameter('projectPHIDs', array()),
+ PhabricatorSearchRelationship::RELATIONSHIP_REPOSITORY =>
+ $query->getParameter('repositoryPHIDs', array()),
);
- foreach ($rel_mapping as $name => $field) {
- $param = $query->getParameter($name);
- if (is_array($param)) {
+
+ $statuses = $query->getParameter('statuses', array());
+ $statuses = array_fuse($statuses);
+
+ $rel_open = PhabricatorSearchRelationship::RELATIONSHIP_OPEN;
+ $rel_closed = PhabricatorSearchRelationship::RELATIONSHIP_CLOSED;
+ $rel_unowned = PhabricatorSearchRelationship::RELATIONSHIP_UNOWNED;
+
+ $include_open = !empty($statuses[$rel_open]);
+ $include_closed = !empty($statuses[$rel_closed]);
+
+ if ($include_open && !$include_closed) {
+ $relationship_map[$rel_open] = true;
+ } else if (!$include_open && $include_closed) {
+ $relationship_map[$rel_closed] = true;
+ }
+
+ if ($query->getParameter('withUnowned')) {
+ $relationship_map[$rel_unowned] = true;
+ }
+
+ foreach ($relationship_map as $field => $param) {
+ if (is_array($param) && $param) {
$should = array();
foreach ($param as $val) {
$should[] = array(
@@ -177,24 +201,24 @@
}
public function executeSearch(PhabricatorSavedQuery $query) {
- $type = $query->getParameter('type');
- if ($type) {
- $uri = "/phabricator/{$type}/_search";
- } else {
- // Don't use '/phabricator/_search' for the case that there is something
- // else in the index (for example if 'phabricator' is only an alias to
- // some bigger index).
- $types = PhabricatorSearchAbstractDocument::getSupportedTypes();
- $uri = '/phabricator/' . implode(',', array_keys($types)) . '/_search';
+ $types = $query->getParameter('types');
+ if (!$types) {
+ $types = array_keys(
+ PhabricatorSearchApplicationSearchEngine::getIndexableDocumentTypes());
}
+ // Don't use '/phabricator/_search' for the case that there is something
+ // else in the index (for example if 'phabricator' is only an alias to
+ // some bigger index).
+ $uri = '/phabricator/'.implode(',', array_keys($types)).'/_search';
+
try {
$response = $this->executeRequest($uri, $this->buildSpec($query));
} catch (HTTPFutureResponseStatusHTTP $ex) {
// elasticsearch probably uses Lucene query syntax:
// http://lucene.apache.org/core/3_6_1/queryparsersyntax.html
// Try literal search if operator search fails.
- if (!$query->getParameter('query')) {
+ if (!strlen($query->getParameter('query'))) {
throw $ex;
}
$query = clone $query;
diff --git a/src/applications/search/engine/PhabricatorSearchEngineMySQL.php b/src/applications/search/engine/PhabricatorSearchEngineMySQL.php
--- a/src/applications/search/engine/PhabricatorSearchEngineMySQL.php
+++ b/src/applications/search/engine/PhabricatorSearchEngineMySQL.php
@@ -179,7 +179,7 @@
$q);
$field = $query->getParameter('field');
- if ($field/* && $field != AdjutantQuery::FIELD_ALL*/) {
+ if ($field) {
$where[] = qsprintf(
$conn_r,
'field.field = %s',
@@ -192,49 +192,74 @@
$where[] = qsprintf($conn_r, 'document.phid != %s', $exclude);
}
- if ($query->getParameter('type')) {
+ $types = $query->getParameter('types');
+ if ($types) {
if (strlen($q)) {
- // TODO: verify that this column actually does something useful in query
- // plans once we have nontrivial amounts of data.
$where[] = qsprintf(
$conn_r,
- 'field.phidType = %s',
- $query->getParameter('type'));
+ 'field.phidType IN (%Ls)',
+ $types);
}
$where[] = qsprintf(
$conn_r,
- 'document.documentType = %s',
- $query->getParameter('type'));
+ 'document.documentType IN (%Ls)',
+ $types);
}
$join[] = $this->joinRelationship(
$conn_r,
$query,
- 'author',
+ 'authorPHIDs',
PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR);
- $join[] = $this->joinRelationship(
- $conn_r,
- $query,
- 'open',
- PhabricatorSearchRelationship::RELATIONSHIP_OPEN);
+ $statuses = $query->getParameter('statuses', array());
+ $statuses = array_fuse($statuses);
+ $open_rel = PhabricatorSearchRelationship::RELATIONSHIP_OPEN;
+ $closed_rel = PhabricatorSearchRelationship::RELATIONSHIP_CLOSED;
+ $include_open = !empty($statuses[$open_rel]);
+ $include_closed = !empty($statuses[$closed_rel]);
- $join[] = $this->joinRelationship(
- $conn_r,
- $query,
- 'owner',
- PhabricatorSearchRelationship::RELATIONSHIP_OWNER);
+ if ($include_open && !$include_closed) {
+ $join[] = $this->joinRelationship(
+ $conn_r,
+ $query,
+ 'statuses',
+ $open_rel,
+ true);
+ } else if ($include_closed && !$include_open) {
+ $join[] = $this->joinRelationship(
+ $conn_r,
+ $query,
+ 'statuses',
+ $closed_rel,
+ true);
+ }
+
+ if ($query->getParameter('withUnowned')) {
+ $join[] = $this->joinRelationship(
+ $conn_r,
+ $query,
+ 'withUnowned',
+ PhabricatorSearchRelationship::RELATIONSHIP_UNOWNED,
+ true);
+ } else {
+ $join[] = $this->joinRelationship(
+ $conn_r,
+ $query,
+ 'ownerPHIDs',
+ PhabricatorSearchRelationship::RELATIONSHIP_OWNER);
+ }
$join[] = $this->joinRelationship(
$conn_r,
$query,
- 'subscribers',
+ 'subscriberPHIDs',
PhabricatorSearchRelationship::RELATIONSHIP_SUBSCRIBER);
$join[] = $this->joinRelationship(
$conn_r,
$query,
- 'project',
+ 'projectPHIDs',
PhabricatorSearchRelationship::RELATIONSHIP_PROJECT);
$join[] = $this->joinRelationship(
@@ -283,19 +308,8 @@
AphrontDatabaseConnection $conn,
PhabricatorSavedQuery $query,
$field,
- $type) {
-
- $phids = $query->getParameter($field, array());
- if (!$phids) {
- return null;
- }
-
- $is_existence = false;
- switch ($type) {
- case PhabricatorSearchRelationship::RELATIONSHIP_OPEN:
- $is_existence = true;
- break;
- }
+ $type,
+ $is_existence = false) {
$sql = qsprintf(
$conn,
@@ -307,6 +321,10 @@
$type);
if (!$is_existence) {
+ $phids = $query->getParameter($field, array());
+ if (!$phids) {
+ return null;
+ }
$sql .= qsprintf(
$conn,
' AND %C.relatedPHID in (%Ls)',
diff --git a/src/applications/search/index/PhabricatorSearchAbstractDocument.php b/src/applications/search/index/PhabricatorSearchAbstractDocument.php
--- a/src/applications/search/index/PhabricatorSearchAbstractDocument.php
+++ b/src/applications/search/index/PhabricatorSearchAbstractDocument.php
@@ -1,8 +1,5 @@
<?php
-/**
- * @group search
- */
final class PhabricatorSearchAbstractDocument {
private $phid;
@@ -13,17 +10,6 @@
private $fields = array();
private $relationships = array();
- public static function getSupportedTypes() {
- return array(
- DifferentialPHIDTypeRevision::TYPECONST => 'Differential Revisions',
- PhabricatorRepositoryPHIDTypeCommit::TYPECONST => 'Repository Commits',
- ManiphestPHIDTypeTask::TYPECONST => 'Maniphest Tasks',
- PhrictionPHIDTypeDocument::TYPECONST => 'Phriction Documents',
- PhabricatorPeoplePHIDTypeUser::TYPECONST => 'Phabricator Users',
- PonderPHIDTypeQuestion::TYPECONST => 'Ponder Questions',
- );
- }
-
public function setPHID($phid) {
$this->phid = $phid;
return $this;
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
@@ -6,19 +6,155 @@
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
+ $saved->setParameter('query', $request->getStr('query'));
+ $saved->setParameter(
+ 'statuses',
+ $this->readListFromRequest($request, 'statuses'));
+ $saved->setParameter(
+ 'types',
+ $this->readListFromRequest($request, 'types'));
+
+ $saved->setParameter(
+ 'authorPHIDs',
+ $this->readUsersFromRequest($request, 'authorPHIDs'));
+
+ $saved->setParameter(
+ 'ownerPHIDs',
+ $this->readUsersFromRequest($request, 'ownerPHIDs'));
+
+ $saved->setParameter(
+ 'withUnowned',
+ $this->readBoolFromRequest($request, 'withUnowned'));
+
+ $saved->setParameter(
+ 'subscriberPHIDs',
+ $this->readPHIDsFromRequest($request, 'subscriberPHIDs'));
+
+ $saved->setParameter(
+ 'projectPHIDs',
+ $this->readPHIDsFromRequest($request, 'projectPHIDs'));
+
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
- $query = id(new PhabricatorSearchDocumentQuery());
-
+ $query = id(new PhabricatorSearchDocumentQuery())
+ ->withSavedQuery($saved);
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
- PhabricatorSavedQuery $saved_query) {
- return;
+ PhabricatorSavedQuery $saved) {
+
+ $options = array();
+ $author_value = null;
+ $owner_value = null;
+ $subscribers_value = null;
+ $project_value = null;
+
+ $author_phids = $saved->getParameter('authorPHIDs', array());
+ $owner_phids = $saved->getParameter('ownerPHIDs', array());
+ $subscriber_phids = $saved->getParameter('subscriberPHIDs', array());
+ $project_phids = $saved->getParameter('projectPHIDs', array());
+
+ $all_phids = array_merge(
+ $author_phids,
+ $owner_phids,
+ $subscriber_phids,
+ $project_phids);
+
+ $all_handles = id(new PhabricatorHandleQuery())
+ ->setViewer($this->requireViewer())
+ ->withPHIDs($all_phids)
+ ->execute();
+
+ $author_handles = array_select_keys($all_handles, $author_phids);
+ $owner_handles = array_select_keys($all_handles, $owner_phids);
+ $subscriber_handles = array_select_keys($all_handles, $subscriber_phids);
+ $project_handles = array_select_keys($all_handles, $project_phids);
+
+ $with_unowned = $saved->getParameter('withUnowned', array());
+
+ $status_values = $saved->getParameter('statuses', array());
+ $status_values = array_fuse($status_values);
+
+ $statuses = array(
+ PhabricatorSearchRelationship::RELATIONSHIP_OPEN => pht('Open'),
+ PhabricatorSearchRelationship::RELATIONSHIP_CLOSED => pht('Closed'),
+ );
+ $status_control = id(new AphrontFormCheckboxControl())
+ ->setLabel(pht('Document Status'));
+ foreach ($statuses as $status => $name) {
+ $status_control->addCheckbox(
+ 'statuses[]',
+ $status,
+ $name,
+ isset($status_values[$status]));
+ }
+
+ $type_values = $saved->getParameter('types', array());
+ $type_values = array_fuse($type_values);
+
+ $types = self::getIndexableDocumentTypes();
+
+ $types_control = id(new AphrontFormCheckboxControl())
+ ->setLabel(pht('Document Types'));
+ foreach ($types as $type => $name) {
+ $types_control->addCheckbox(
+ 'types[]',
+ $type,
+ $name,
+ isset($type_values[$type]));
+ }
+
+ $form
+ ->appendChild(
+ phutil_tag(
+ 'input',
+ array(
+ 'type' => 'hidden',
+ 'name' => 'jump',
+ 'value' => 'no',
+ )))
+ ->appendChild(
+ id(new AphrontFormTextControl())
+ ->setLabel('Query')
+ ->setName('query')
+ ->setValue($saved->getParameter('query')))
+ ->appendChild($status_control)
+ ->appendChild($types_control)
+ ->appendChild(
+ id(new AphrontFormTokenizerControl())
+ ->setName('authorPHIDs')
+ ->setLabel('Authors')
+ ->setDatasource('/typeahead/common/users/')
+ ->setValue($author_handles))
+ ->appendChild(
+ id(new AphrontFormTokenizerControl())
+ ->setName('ownerPHIDs')
+ ->setLabel('Owners')
+ ->setDatasource('/typeahead/common/searchowner/')
+ ->setValue($owner_handles))
+ ->appendChild(
+ id(new AphrontFormCheckboxControl())
+ ->addCheckbox(
+ 'withUnowned',
+ 1,
+ pht('Show only unowned documents.'),
+ $with_unowned))
+ ->appendChild(
+ id(new AphrontFormTokenizerControl())
+ ->setName('subscriberPHIDs')
+ ->setLabel('Subscribers')
+ ->setDatasource('/typeahead/common/users/')
+ ->setValue($subscriber_handles))
+ ->appendChild(
+ id(new AphrontFormTokenizerControl())
+ ->setName('projectPHIDs')
+ ->setLabel('In Any Project')
+ ->setDatasource('/typeahead/common/projects/')
+ ->setValue($project_handles));
}
protected function getURI($path) {
@@ -28,6 +164,8 @@
public function getBuiltinQueryNames() {
$names = array(
'all' => pht('All Documents'),
+ 'open' => pht('Open Documents'),
+ 'open-tasks' => pht('Open Tasks'),
);
return $names;
@@ -41,9 +179,45 @@
switch ($query_key) {
case 'all':
return $query;
+ case 'open':
+ return $query->setParameter('statuses', array('open'));
+ case 'open-tasks':
+ return $query
+ ->setParameter('statuses', array('open'))
+ ->setParameter('types', array(ManiphestPHIDTypeTask::TYPECONST));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
+ public static function getIndexableDocumentTypes() {
+ // TODO: This is inelegant and not very efficient, but gets us reasonable
+ // results. It would be nice to do this more elegantly.
+
+ // TODO: We should hide types associated with applications the user can
+ // not access. There's no reasonable way to do this right now.
+
+ $indexers = id(new PhutilSymbolLoader())
+ ->setAncestorClass('PhabricatorSearchDocumentIndexer')
+ ->loadObjects();
+
+ $types = PhabricatorPHIDType::getAllTypes();
+
+ $results = array();
+ foreach ($types as $type) {
+ $typeconst = $type->getTypeConstant();
+ foreach ($indexers as $indexer) {
+ $fake_phid = 'PHID-'.$typeconst.'-fake';
+ if ($indexer->shouldIndexDocumentByPHID($fake_phid)) {
+ $results[$typeconst] = $type->getTypeName();
+ }
+ }
+ }
+
+ asort($results);
+
+ return $results;
+ }
+
+
}
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
@@ -3,12 +3,66 @@
final class PhabricatorSearchDocumentQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
+ private $savedQuery;
+
+ public function withSavedQuery(PhabricatorSavedQuery $query) {
+ $this->savedQuery = $query;
+ return $this;
+ }
+
protected function loadPage() {
- return array();
+ $phids = $this->loadDocumentPHIDsWithoutPolicyChecks();
+
+ $handles = id(new PhabricatorHandleQuery())
+ ->setViewer($this->getViewer())
+ ->withPHIDs($phids)
+ ->execute();
+
+ // Retain engine order.
+ $handles = array_select_keys($handles, $phids);
+
+ return $handles;
+ }
+
+ protected function willFilterPage(array $handles) {
+ foreach ($handles as $key => $handle) {
+ if (!$handle->isComplete()) {
+ unset($handles[$key]);
+ continue;
+ }
+ if ($handle->getPolicyFiltered()) {
+ unset($handles[$key]);
+ continue;
+ }
+ }
+
+ return $handles;
+ }
+
+ public function loadDocumentPHIDsWithoutPolicyChecks() {
+ $query = id(clone($this->savedQuery))
+ ->setParameter('offset', $this->getOffset())
+ ->setParameter('limit', $this->getRawResultLimit());
+
+ $engine = PhabricatorSearchEngineSelector::newSelector()->newEngine();
+
+ return $engine->executeSearch($query);
}
public function getQueryApplicationClass() {
return 'PhabricatorApplicationSearch';
}
+ protected function getPagingValue($result) {
+ throw new Exception(
+ pht(
+ 'This query does not support cursor paging; it must be offset '.
+ 'paged.'));
+ }
+
+ protected function nextPage(array $page) {
+ $this->setOffset($this->getOffset() + count($page));
+ return $this;
+ }
+
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Mar 19, 7:18 PM (2 d, 18 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7711855
Default Alt Text
D8123.id18371.diff (30 KB)
Attached To
Mode
D8123: Use ApplicationSearch to power primary search
Attached
Detach File
Event Timeline
Log In to Comment