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 @@ -2529,6 +2529,7 @@ 'PhabricatorSearchSelectField' => 'applications/search/field/PhabricatorSearchSelectField.php', 'PhabricatorSearchSpacesField' => 'applications/search/field/PhabricatorSearchSpacesField.php', 'PhabricatorSearchStringListField' => 'applications/search/field/PhabricatorSearchStringListField.php', + 'PhabricatorSearchSubscribersField' => 'applications/search/field/PhabricatorSearchSubscribersField.php', 'PhabricatorSearchTextField' => 'applications/search/field/PhabricatorSearchTextField.php', 'PhabricatorSearchThreeStateField' => 'applications/search/field/PhabricatorSearchThreeStateField.php', 'PhabricatorSearchTokenizerField' => 'applications/search/field/PhabricatorSearchTokenizerField.php', @@ -6031,6 +6032,7 @@ 'PhabricatorSearchSelectField' => 'PhabricatorSearchField', 'PhabricatorSearchSpacesField' => 'PhabricatorSearchTokenizerField', 'PhabricatorSearchStringListField' => 'PhabricatorSearchField', + 'PhabricatorSearchSubscribersField' => 'PhabricatorSearchTokenizerField', 'PhabricatorSearchTextField' => 'PhabricatorSearchField', 'PhabricatorSearchThreeStateField' => 'PhabricatorSearchField', 'PhabricatorSearchTokenizerField' => 'PhabricatorSearchField', diff --git a/src/applications/files/query/PhabricatorFileSearchEngine.php b/src/applications/files/query/PhabricatorFileSearchEngine.php --- a/src/applications/files/query/PhabricatorFileSearchEngine.php +++ b/src/applications/files/query/PhabricatorFileSearchEngine.php @@ -37,6 +37,14 @@ ); } + protected function getDefaultFieldOrder() { + return array( + '...', + 'createdStart', + 'createdEnd', + ); + } + public function buildQueryFromParameters(array $map) { $query = id(new PhabricatorFileQuery()); diff --git a/src/applications/paste/query/PhabricatorPasteSearchEngine.php b/src/applications/paste/query/PhabricatorPasteSearchEngine.php --- a/src/applications/paste/query/PhabricatorPasteSearchEngine.php +++ b/src/applications/paste/query/PhabricatorPasteSearchEngine.php @@ -56,6 +56,14 @@ ); } + protected function getDefaultFieldOrder() { + return array( + '...', + 'createdStart', + 'createdEnd', + ); + } + protected function getURI($path) { return '/paste/'.$path; } diff --git a/src/applications/project/query/PhabricatorProjectQuery.php b/src/applications/project/query/PhabricatorProjectQuery.php --- a/src/applications/project/query/PhabricatorProjectQuery.php +++ b/src/applications/project/query/PhabricatorProjectQuery.php @@ -120,29 +120,7 @@ protected function loadPage() { $table = new PhabricatorProject(); - $conn_r = $table->establishConnection('r'); - - // NOTE: Because visibility checks for projects depend on whether or not - // the user is a project member, we always load their membership. If we're - // loading all members anyway we can piggyback on that; otherwise we - // do an explicit join. - - $select_clause = ''; - if (!$this->needMembers) { - $select_clause = ', vm.dst viewerIsMember'; - } - - $data = queryfx_all( - $conn_r, - 'SELECT p.* %Q FROM %T p %Q %Q %Q %Q %Q', - $select_clause, - $table->getTableName(), - $this->buildJoinClause($conn_r), - $this->buildWhereClause($conn_r), - $this->buildGroupClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - + $data = $this->loadStandardPageRows($table); $projects = $table->loadAllFromArray($data); if ($projects) { @@ -240,8 +218,22 @@ return $projects; } - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { - $where = array(); + protected function buildSelectClauseParts(AphrontDatabaseConnection $conn) { + $select = parent::buildSelectClauseParts($conn); + + // NOTE: Because visibility checks for projects depend on whether or not + // the user is a project member, we always load their membership. If we're + // loading all members anyway we can piggyback on that; otherwise we + // do an explicit join. + if (!$this->needMembers) { + $select[] = 'vm.dst viewerIsMember'; + } + + return $select; + } + + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); if ($this->status != self::STATUS_ANY) { switch ($this->status) { @@ -264,86 +256,83 @@ $this->status)); } $where[] = qsprintf( - $conn_r, + $conn, 'status IN (%Ld)', $filter); } if ($this->ids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'phid IN (%Ls)', $this->phids); } if ($this->memberPHIDs !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'e.dst IN (%Ls)', $this->memberPHIDs); } if ($this->slugs !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'slug.slug IN (%Ls)', $this->slugs); } if ($this->phrictionSlugs !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'phrictionSlug IN (%Ls)', $this->phrictionSlugs); } if ($this->names !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'name IN (%Ls)', $this->names); } if ($this->icons !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'icon IN (%Ls)', $this->icons); } if ($this->colors !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'color IN (%Ls)', $this->colors); } - $where[] = $this->buildPagingClause($conn_r); - - return $this->formatWhereClause($where); + return $where; } - protected function buildGroupClause(AphrontDatabaseConnection $conn_r) { + protected function shouldGroupQueryResultRows() { if ($this->memberPHIDs || $this->nameTokens) { - return 'GROUP BY p.id'; - } else { - return $this->buildApplicationSearchGroupClause($conn_r); + return true; } + return parent::shouldGroupQueryResultRows(); } - protected function buildJoinClause(AphrontDatabaseConnection $conn_r) { - $joins = array(); + protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { + $joins = parent::buildJoinClauseParts($conn); if (!$this->needMembers !== null) { $joins[] = qsprintf( - $conn_r, + $conn, 'LEFT JOIN %T vm ON vm.src = p.phid AND vm.type = %d AND vm.dst = %s', PhabricatorEdgeConfig::TABLE_NAME_EDGE, PhabricatorProjectProjectHasMemberEdgeType::EDGECONST, @@ -352,7 +341,7 @@ if ($this->memberPHIDs !== null) { $joins[] = qsprintf( - $conn_r, + $conn, 'JOIN %T e ON e.src = p.phid AND e.type = %d', PhabricatorEdgeConfig::TABLE_NAME_EDGE, PhabricatorProjectProjectHasMemberEdgeType::EDGECONST); @@ -360,7 +349,7 @@ if ($this->slugs !== null) { $joins[] = qsprintf( - $conn_r, + $conn, 'JOIN %T slug on slug.projectPHID = p.phid', id(new PhabricatorProjectSlug())->getTableName()); } @@ -369,7 +358,7 @@ foreach ($this->nameTokens as $key => $token) { $token_table = 'token_'.$key; $joins[] = qsprintf( - $conn_r, + $conn, 'JOIN %T %T ON %T.projectID = p.id AND %T.token LIKE %>', PhabricatorProject::TABLE_DATASOURCE_TOKEN, $token_table, @@ -379,9 +368,7 @@ } } - $joins[] = $this->buildApplicationSearchJoinClause($conn_r); - - return implode(' ', $joins); + return $joins; } public function getQueryApplicationClass() { diff --git a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php --- a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php +++ b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php @@ -113,6 +113,15 @@ return $query; } + if ($object instanceof PhabricatorSubscribableInterface) { + if (!empty($parameters['subscriberPHIDs'])) { + $query->withEdgeLogicPHIDs( + PhabricatorObjectHasSubscriberEdgeType::EDGECONST, + PhabricatorQueryConstraint::OPERATOR_OR, + $parameters['subscriberPHIDs']); + } + } + if ($object instanceof PhabricatorProjectInterface) { if (!empty($parameters['projectPHIDs'])) { $query->withEdgeLogicConstraints( @@ -180,6 +189,13 @@ return $fields; } + if ($object instanceof PhabricatorSubscribableInterface) { + $fields[] = id(new PhabricatorSearchSubscribersField()) + ->setLabel(pht('Subscribers')) + ->setKey('subscriberPHIDs') + ->setAliases(array('subscriber', 'subscribers')); + } + if ($object instanceof PhabricatorProjectInterface) { $fields[] = id(new PhabricatorSearchProjectsField()) ->setKey('projectPHIDs') diff --git a/src/applications/search/field/PhabricatorSearchSubscribersField.php b/src/applications/search/field/PhabricatorSearchSubscribersField.php new file mode 100644 --- /dev/null +++ b/src/applications/search/field/PhabricatorSearchSubscribersField.php @@ -0,0 +1,21 @@ +getUsersFromRequest($request, $key, $allow_types); + } + + protected function newDatasource() { + return new PhabricatorMetaMTAMailableFunctionDatasource(); + } + +} diff --git a/src/applications/search/field/PhabricatorSearchTokenizerField.php b/src/applications/search/field/PhabricatorSearchTokenizerField.php --- a/src/applications/search/field/PhabricatorSearchTokenizerField.php +++ b/src/applications/search/field/PhabricatorSearchTokenizerField.php @@ -26,9 +26,11 @@ abstract protected function newDatasource(); - protected function getUsersFromRequest(AphrontRequest $request, $key) { + protected function getUsersFromRequest( + AphrontRequest $request, + $key, + array $allow_types = array()) { $list = $this->getListFromRequest($request, $key); - $allow_types = array(); $phids = array(); $names = array(); diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -76,7 +76,12 @@ return $this->beforeID; } - public function loadStandardPage(PhabricatorLiskDAO $table) { + protected function loadStandardPage(PhabricatorLiskDAO $table) { + $rows = $this->loadStandardPageRows($table); + return $table->loadAllFromArray($rows); + } + + protected function loadStandardPageRows(PhabricatorLiskDAO $table) { $conn = $table->establishConnection('r'); $rows = queryfx_all( @@ -92,7 +97,7 @@ $this->buildOrderClause($conn), $this->buildLimitClause($conn)); - return $table->loadAllFromArray($rows); + return $rows; } /**