public function executeSearch(PhabricatorSearchQuery $query) { $spec = array(); $filter = array(); if ($query->getQuery()) { $spec[] = array('field' => array('field.corpus' => $query->getQuery())); } $exclude = $query->getParameter('exclude'); if ($exclude) { $filter[] = array('not' => array('ids' => array('values' => array($exclude)))); } $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'; } $rel_mapping = array('author' => PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR, 'open' => PhabricatorSearchRelationship::RELATIONSHIP_OPEN, 'owner' => PhabricatorSearchRelationship::RELATIONSHIP_OWNER, 'project' => PhabricatorSearchRelationship::RELATIONSHIP_PROJECT, 'repository' => PhabricatorSearchRelationship::RELATIONSHIP_REPOSITORY); foreach ($rel_mapping as $name => $field) { $param = $query->getParameter($name); if (is_array($param)) { $should = array(); foreach ($param as $val) { $should[] = array('text' => array("relationship.{$field}.phid" => array('query' => $val, 'type' => 'phrase'))); } // We couldn't solve it by minimum_number_should_match because it can // match multiple owners without matching author. $spec[] = array('bool' => array('should' => $should)); } else { if ($param) { $filter[] = array('exists' => array('field' => "relationship.{$field}.phid")); } } } if ($spec) { $spec = array('query' => array('bool' => array('must' => $spec))); } if ($filter) { $filter = array('filter' => array('and' => $filter)); if ($spec) { $spec = array('query' => array('filtered' => $spec + $filter)); } else { $spec = $filter; } } $spec['from'] = (int) $query->getParameter('offset', 0); $spec['size'] = (int) $query->getParameter('limit', 25); $response = $this->executeRequest($uri, $spec); $phids = ipull($response['hits']['hits'], '_id'); return $phids; }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($this->key) { $query = id(new PhabricatorSearchQuery())->loadOneWhere('queryKey = %s', $this->key); if (!$query) { return new Aphront404Response(); } } else { $query = new PhabricatorSearchQuery(); 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::jumpPostResponse($query_str); } else { $response = null; } if ($response) { return $response; } else { $query->setQuery($query_str); if ($request->getStr('scope')) { switch ($request->getStr('scope')) { case PhabricatorSearchScope::SCOPE_OPEN_REVISIONS: $query->setParameter('open', 1); $query->setParameter('type', PhabricatorPHIDConstants::PHID_TYPE_DREV); break; case PhabricatorSearchScope::SCOPE_OPEN_TASKS: $query->setParameter('open', 1); $query->setParameter('type', PhabricatorPHIDConstants::PHID_TYPE_TASK); break; case PhabricatorSearchScope::SCOPE_WIKI: $query->setParameter('type', PhabricatorPHIDConstants::PHID_TYPE_WIKI); break; case PhabricatorSearchScope::SCOPE_COMMITS: $query->setParameter('type', PhabricatorPHIDConstants::PHID_TYPE_CMIT); 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->getInt('open')) { $query->setParameter('open', $request->getInt('open')); } if ($request->getArr('project')) { $query->setParameter('project', $request->getArr('project')); } } $query->save(); 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('project', array())); $handles = $this->loadViewerHandles($phids); $author_value = array_select_keys($handles, $query->getParameter('author', array())); $author_value = mpull($author_value, 'getFullName', 'getPHID'); $owner_value = array_select_keys($handles, $query->getParameter('owner', array())); $owner_value = mpull($owner_value, 'getFullName', 'getPHID'); $project_value = array_select_keys($handles, $query->getParameter('project', array())); $project_value = mpull($project_value, 'getFullName', 'getPHID'); $search_form = new AphrontFormView(); $search_form->setUser($user)->setAction('/search/')->appendChild(phutil_render_tag('input', array('type' => 'hidden', 'name' => 'jump', 'value' => 'no')))->appendChild(id(new AphrontFormTextControl())->setLabel('Search')->setName('query')->setValue($query->getQuery()))->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('project')->setLabel('Project')->setDatasource('/typeahead/common/projects/')->setValue($project_value))->appendChild(id(new AphrontFormSubmitControl())->setValue('Search')); $search_panel = new AphrontPanelView(); $search_panel->setHeader('Search Phabricator'); $search_panel->appendChild($search_form); require_celerity_resource('phabricator-search-results-css'); if ($query->getID()) { $limit = 20; $pager = new AphrontPagerView(); $pager->setURI($request->getRequestURI(), 'page'); $pager->setPageSize($limit); $pager->setOffset($request->getInt('page')); $query->setParameter('limit', $limit + 1); $query->setParameter('offset', $pager->getOffset()); $engine = PhabricatorSearchEngineSelector::newSelector()->newEngine(); $results = $engine->executeSearch($query); $results = $pager->sliceResults($results); if (!$request->getInt('page')) { $jump = PhabricatorPHID::fromObjectName($query->getQuery()); if ($jump) { array_unshift($results, $jump); } } if ($results) { $loader = new PhabricatorObjectHandleData($results); $handles = $loader->loadHandles(); $objects = $loader->loadObjects(); $results = array(); foreach ($handles as $phid => $handle) { $view = new PhabricatorSearchResultView(); $view->setHandle($handle); $view->setQuery($query); $view->setObject(idx($objects, $phid)); $results[] = $view->render(); } $results = '<div class="phabricator-search-result-list">' . implode("\n", $results) . '<div class="search-results-pager">' . $pager->render() . '</div>' . '</div>'; } else { $results = '<div class="phabricator-search-result-list">' . '<p class="phabricator-search-no-results">No search results.</p>' . '</div>'; } } else { $results = null; } return $this->buildStandardPageResponse(array($search_panel, $results), array('title' => 'Search Results')); }
public static function loadTasks(PhabricatorSearchQuery $search_query) { $any_project = false; $search_text = $search_query->getParameter('fullTextSearch'); $user_phids = $search_query->getParameter('userPHIDs', array()); $project_phids = $search_query->getParameter('projectPHIDs', array()); $task_ids = $search_query->getParameter('taskIDs', array()); $xproject_phids = $search_query->getParameter('excludeProjectPHIDs', array()); $owner_phids = $search_query->getParameter('ownerPHIDs', array()); $author_phids = $search_query->getParameter('authorPHIDs', array()); $low_priority = $search_query->getParameter('lowPriority'); $low_priority = nonempty($low_priority, ManiphestTaskPriority::getLowestPriority()); $high_priority = $search_query->getParameter('highPriority'); $high_priority = nonempty($high_priority, ManiphestTaskPriority::getHighestPriority()); $query = new ManiphestTaskQuery(); $query->withProjects($project_phids); $query->withTaskIDs($task_ids); if ($xproject_phids) { $query->withoutProjects($xproject_phids); } if ($owner_phids) { $query->withOwners($owner_phids); } if ($author_phids) { $query->withAuthors($author_phids); } $status = $search_query->getParameter('status', 'all'); if (!empty($status['open']) && !empty($status['closed'])) { $query->withStatus(ManiphestTaskQuery::STATUS_ANY); } else { if (!empty($status['open'])) { $query->withStatus(ManiphestTaskQuery::STATUS_OPEN); } else { $query->withStatus(ManiphestTaskQuery::STATUS_CLOSED); } } switch ($search_query->getParameter('view')) { case 'action': $query->withOwners($user_phids); break; case 'created': $query->withAuthors($user_phids); break; case 'subscribed': $query->withSubscribers($user_phids); break; case 'triage': $query->withOwners($user_phids); $query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE); break; case 'alltriage': $query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE); break; case 'all': break; case 'projecttriage': $query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE); $any_project = true; break; case 'projectall': $any_project = true; break; case 'custom': $query->withPrioritiesBetween($low_priority, $high_priority); break; } $query->withAnyProject($any_project); $query->withFullTextSearch($search_text); $order_map = array('priority' => ManiphestTaskQuery::ORDER_PRIORITY, 'created' => ManiphestTaskQuery::ORDER_CREATED, 'title' => ManiphestTaskQuery::ORDER_TITLE); $query->setOrderBy(idx($order_map, $search_query->getParameter('order'), ManiphestTaskQuery::ORDER_MODIFIED)); $group_map = array('priority' => ManiphestTaskQuery::GROUP_PRIORITY, 'owner' => ManiphestTaskQuery::GROUP_OWNER, 'status' => ManiphestTaskQuery::GROUP_STATUS, 'project' => ManiphestTaskQuery::GROUP_PROJECT); $query->setGroupBy(idx($group_map, $search_query->getParameter('group'), ManiphestTaskQuery::GROUP_NONE)); $query->setCalculateRows(true); $query->setLimit($search_query->getParameter('limit')); $query->setOffset($search_query->getParameter('offset')); $data = $query->execute(); $total_row_count = $query->getRowCount(); $project_group_phids = array(); if ($search_query->getParameter('group') == 'project') { foreach ($data as $task) { foreach ($task->getProjectPHIDs() as $phid) { $project_group_phids[] = $phid; } } } $handle_phids = mpull($data, 'getOwnerPHID'); $handle_phids = array_merge($handle_phids, $project_phids, $user_phids, $xproject_phids, $owner_phids, $author_phids, $project_group_phids, array_mergev(mpull($data, 'getProjectPHIDs'))); $handles = id(new PhabricatorObjectHandleData($handle_phids))->loadHandles(); switch ($search_query->getParameter('group')) { case 'priority': $data = mgroup($data, 'getPriority'); // If we have invalid priorities, they'll all map to "???". Merge // arrays to prevent them from overwriting each other. $out = array(); foreach ($data as $pri => $tasks) { $out[ManiphestTaskPriority::getTaskPriorityName($pri)][] = $tasks; } foreach ($out as $pri => $tasks) { $out[$pri] = array_mergev($tasks); } $data = $out; break; case 'status': $data = mgroup($data, 'getStatus'); $out = array(); foreach ($data as $status => $tasks) { $out[ManiphestTaskStatus::getTaskStatusFullName($status)] = $tasks; } $data = $out; break; case 'owner': $data = mgroup($data, 'getOwnerPHID'); $out = array(); foreach ($data as $phid => $tasks) { if ($phid) { $out[$handles[$phid]->getFullName()] = $tasks; } else { $out['Unassigned'] = $tasks; } } $data = $out; ksort($data); // Move "Unassigned" to the top of the list. if (isset($data['Unassigned'])) { $data = array('Unassigned' => $out['Unassigned']) + $out; } break; case 'project': $grouped = array(); foreach ($query->getGroupByProjectResults() as $project => $tasks) { foreach ($tasks as $task) { $group = $project ? $handles[$project]->getName() : 'No Project'; $grouped[$group][$task->getID()] = $task; } } $data = $grouped; ksort($data); // Move "No Project" to the end of the list. if (isset($data['No Project'])) { $noproject = $data['No Project']; unset($data['No Project']); $data += array('No Project' => $noproject); } break; default: $data = array('Tasks' => $data); break; } return array($data, $handles, $total_row_count); }
protected function joinRelationship(AphrontDatabaseConnection $conn, PhabricatorSearchQuery $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; } $sql = qsprintf($conn, '%T AS %C ON %C.phid = document.phid AND %C.relation = %s', id(new PhabricatorSearchDocumentRelationship())->getTableName(), $field, $field, $field, $type); if (!$is_existence) { $sql .= qsprintf($conn, ' AND %C.relatedPHID in (%Ls)', $field, $phids); } return $sql; }
public function executeSearch(PhabricatorSearchQuery $query) { $where = array(); $join = array(); $order = 'ORDER BY documentCreated DESC'; $dao_doc = new PhabricatorSearchDocument(); $dao_field = new PhabricatorSearchDocumentField(); $t_doc = $dao_doc->getTableName(); $t_field = $dao_field->getTableName(); $conn_r = $dao_doc->establishConnection('r'); $q = $query->getQuery(); if (strlen($q)) { $join[] = qsprintf($conn_r, "{$t_field} field ON field.phid = document.phid"); $where[] = qsprintf($conn_r, 'MATCH(corpus) AGAINST (%s IN BOOLEAN MODE)', $q); // When searching for a string, promote user listings above other // listings. $order = qsprintf($conn_r, 'ORDER BY IF(documentType = %s, 0, 1) ASC, MAX(MATCH(corpus) AGAINST (%s)) DESC', 'USER', $q); $field = $query->getParameter('field'); if ($field) { $where[] = qsprintf($conn_r, 'field.field = %s', $field); } } $exclude = $query->getParameter('exclude'); if ($exclude) { $where[] = qsprintf($conn_r, 'document.phid != %s', $exclude); } if ($query->getParameter('type')) { 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')); } $where[] = qsprintf($conn_r, 'document.documentType = %s', $query->getParameter('type')); } $join[] = $this->joinRelationship($conn_r, $query, 'author', PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR); $join[] = $this->joinRelationship($conn_r, $query, 'open', PhabricatorSearchRelationship::RELATIONSHIP_OPEN); $join[] = $this->joinRelationship($conn_r, $query, 'owner', PhabricatorSearchRelationship::RELATIONSHIP_OWNER); $join[] = $this->joinRelationship($conn_r, $query, 'project', PhabricatorSearchRelationship::RELATIONSHIP_PROJECT); $join[] = $this->joinRelationship($conn_r, $query, 'repository', PhabricatorSearchRelationship::RELATIONSHIP_REPOSITORY); /* $join[] = $this->joinRelationship( $conn_r, $query, 'reviewer', AdjutantRelationship::RELATIONSHIP_REVIEWER); $join[] = $this->joinRelationship( $conn_r, $query, 'subscriber', AdjutantRelationship::RELATIONSHIP_SUBSCRIBER); $join[] = $this->joinRelationship( $conn_r, $query, 'repository', AdjutantRelationship::RELATIONSHIP_REPOSITORY); */ $join = array_filter($join); foreach ($join as $key => $clause) { $join[$key] = ' JOIN ' . $clause; } $join = implode(' ', $join); if ($where) { $where = 'WHERE ' . implode(' AND ', $where); } else { $where = ''; } $offset = (int) $query->getParameter('offset', 0); $limit = (int) $query->getParameter('limit', 25); $hits = queryfx_all($conn_r, 'SELECT document.phid, document.documentType, document.documentTitle, document.documentCreated FROM %T document %Q %Q GROUP BY document.phid %Q LIMIT %d, %d', $t_doc, $join, $where, $order, $offset, $limit); return $hits; }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($this->id) { $query = id(new PhabricatorSearchQuery())->load($this->id); if (!$query) { return new Aphront404Response(); } } else { $query = new PhabricatorSearchQuery(); if ($request->isFormPost()) { $query->setQuery($request->getStr('query')); 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->getInt('open')) { $query->setParameter('open', $request->getInt('open')); } if ($request->getArr('project')) { $query->setParameter('project', $request->getArr('project')); } $query->save(); return id(new AphrontRedirectResponse())->setURI('/search/' . $query->getID() . '/'); } } $more = PhabricatorEnv::getEnvConfig('search.more-document-types', array()); $options = array('' => 'All Documents', PhabricatorPHIDConstants::PHID_TYPE_DREV => 'Differential Revisions', PhabricatorPHIDConstants::PHID_TYPE_CMIT => 'Repository Commits', PhabricatorPHIDConstants::PHID_TYPE_TASK => 'Maniphest Tasks', PhabricatorPHIDConstants::PHID_TYPE_WIKI => 'Phriction Documents', PhabricatorPHIDConstants::PHID_TYPE_USER => 'Phabricator Users') + $more; $status_options = array(0 => 'Open and Closed Documents', 1 => 'Open Documents'); $phids = array_merge($query->getParameter('author', array()), $query->getParameter('owner', array()), $query->getParameter('project', array())); $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); $author_value = array_select_keys($handles, $query->getParameter('author', array())); $author_value = mpull($author_value, 'getFullName', 'getPHID'); $owner_value = array_select_keys($handles, $query->getParameter('owner', array())); $owner_value = mpull($owner_value, 'getFullName', 'getPHID'); $project_value = array_select_keys($handles, $query->getParameter('project', array())); $project_value = mpull($project_value, 'getFullName', 'getPHID'); $search_form = new AphrontFormView(); $search_form->setUser($user)->setAction('/search/')->appendChild(id(new AphrontFormTextControl())->setLabel('Search')->setName('query')->setValue($query->getQuery()))->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('project')->setLabel('Project')->setDatasource('/typeahead/common/projects/')->setValue($project_value))->appendChild(id(new AphrontFormSubmitControl())->setValue('Search')); $search_panel = new AphrontPanelView(); $search_panel->setHeader('Search Phabricator'); $search_panel->appendChild($search_form); require_celerity_resource('phabricator-search-results-css'); if ($query->getID()) { $limit = 20; $pager = new AphrontPagerView(); $pager->setURI($request->getRequestURI(), 'page'); $pager->setPageSize($limit); $pager->setOffset($request->getInt('page')); $query->setParameter('limit', $limit + 1); $query->setParameter('offset', $pager->getOffset()); $executor = new PhabricatorSearchMySQLExecutor(); $results = $executor->executeSearch($query); $results = ipull($results, 'phid'); $results = $pager->sliceResults($results); if ($results) { $loader = new PhabricatorObjectHandleData($results); $handles = $loader->loadHandles(); $objects = $loader->loadObjects(); $results = array(); foreach ($handles as $phid => $handle) { $view = new PhabricatorSearchResultView(); $view->setHandle($handle); $view->setQuery($query); $view->setObject($objects[$phid]); $results[] = $view->render(); } $results = '<div class="phabricator-search-result-list">' . implode("\n", $results) . '<div class="search-results-pager">' . $pager->render() . '</div>' . '</div>'; } else { $results = '<div class="phabricator-search-result-list">' . '<p class="phabricator-search-no-results">No search results.</p>' . '</div>'; } } else { $results = null; } return $this->buildStandardPageResponse(array($search_panel, $results), array('title' => 'Results: what')); }
public function executeSearch(PhabricatorSearchQuery $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'; } 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->getQuery()) { throw $ex; } $query = clone $query; $query->setQuery(addcslashes($query->getQuery(), '+-&|!(){}[]^"~*?:\\')); $response = $this->executeRequest($uri, $this->buildSpec($query)); } $phids = ipull($response['hits']['hits'], '_id'); return $phids; }