mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-25 22:18:19 +01:00
Make Subscribers automatically provide working SearchFields
Summary: Ref T8441. Ref T7715. For modern Query classes, automatically make subscriber queries and SearchField integrations work. In particular, we can just drive this query with EdgeLogic and don't need to do anything specific on these Query classes beyond making sure they're implemented in a way that picks up all of the EdgeLogic clauses. Test Plan: - Searched for subscribers in Pholio, Files, Paste, and Projects. - Searched for all other fields in Projects to check that Query changes are OK. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T7715, T8441 Differential Revision: https://secure.phabricator.com/D13191
This commit is contained in:
parent
3e2b0c35f9
commit
3cdaf52ce9
8 changed files with 103 additions and 54 deletions
|
@ -2529,6 +2529,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSearchSelectField' => 'applications/search/field/PhabricatorSearchSelectField.php',
|
'PhabricatorSearchSelectField' => 'applications/search/field/PhabricatorSearchSelectField.php',
|
||||||
'PhabricatorSearchSpacesField' => 'applications/search/field/PhabricatorSearchSpacesField.php',
|
'PhabricatorSearchSpacesField' => 'applications/search/field/PhabricatorSearchSpacesField.php',
|
||||||
'PhabricatorSearchStringListField' => 'applications/search/field/PhabricatorSearchStringListField.php',
|
'PhabricatorSearchStringListField' => 'applications/search/field/PhabricatorSearchStringListField.php',
|
||||||
|
'PhabricatorSearchSubscribersField' => 'applications/search/field/PhabricatorSearchSubscribersField.php',
|
||||||
'PhabricatorSearchTextField' => 'applications/search/field/PhabricatorSearchTextField.php',
|
'PhabricatorSearchTextField' => 'applications/search/field/PhabricatorSearchTextField.php',
|
||||||
'PhabricatorSearchThreeStateField' => 'applications/search/field/PhabricatorSearchThreeStateField.php',
|
'PhabricatorSearchThreeStateField' => 'applications/search/field/PhabricatorSearchThreeStateField.php',
|
||||||
'PhabricatorSearchTokenizerField' => 'applications/search/field/PhabricatorSearchTokenizerField.php',
|
'PhabricatorSearchTokenizerField' => 'applications/search/field/PhabricatorSearchTokenizerField.php',
|
||||||
|
@ -6031,6 +6032,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSearchSelectField' => 'PhabricatorSearchField',
|
'PhabricatorSearchSelectField' => 'PhabricatorSearchField',
|
||||||
'PhabricatorSearchSpacesField' => 'PhabricatorSearchTokenizerField',
|
'PhabricatorSearchSpacesField' => 'PhabricatorSearchTokenizerField',
|
||||||
'PhabricatorSearchStringListField' => 'PhabricatorSearchField',
|
'PhabricatorSearchStringListField' => 'PhabricatorSearchField',
|
||||||
|
'PhabricatorSearchSubscribersField' => 'PhabricatorSearchTokenizerField',
|
||||||
'PhabricatorSearchTextField' => 'PhabricatorSearchField',
|
'PhabricatorSearchTextField' => 'PhabricatorSearchField',
|
||||||
'PhabricatorSearchThreeStateField' => 'PhabricatorSearchField',
|
'PhabricatorSearchThreeStateField' => 'PhabricatorSearchField',
|
||||||
'PhabricatorSearchTokenizerField' => 'PhabricatorSearchField',
|
'PhabricatorSearchTokenizerField' => 'PhabricatorSearchField',
|
||||||
|
|
|
@ -37,6 +37,14 @@ final class PhabricatorFileSearchEngine
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getDefaultFieldOrder() {
|
||||||
|
return array(
|
||||||
|
'...',
|
||||||
|
'createdStart',
|
||||||
|
'createdEnd',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function buildQueryFromParameters(array $map) {
|
public function buildQueryFromParameters(array $map) {
|
||||||
$query = id(new PhabricatorFileQuery());
|
$query = id(new PhabricatorFileQuery());
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,14 @@ final class PhabricatorPasteSearchEngine
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getDefaultFieldOrder() {
|
||||||
|
return array(
|
||||||
|
'...',
|
||||||
|
'createdStart',
|
||||||
|
'createdEnd',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
protected function getURI($path) {
|
protected function getURI($path) {
|
||||||
return '/paste/'.$path;
|
return '/paste/'.$path;
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,29 +120,7 @@ final class PhabricatorProjectQuery
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$table = new PhabricatorProject();
|
$table = new PhabricatorProject();
|
||||||
$conn_r = $table->establishConnection('r');
|
$data = $this->loadStandardPageRows($table);
|
||||||
|
|
||||||
// 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));
|
|
||||||
|
|
||||||
$projects = $table->loadAllFromArray($data);
|
$projects = $table->loadAllFromArray($data);
|
||||||
|
|
||||||
if ($projects) {
|
if ($projects) {
|
||||||
|
@ -240,8 +218,22 @@ final class PhabricatorProjectQuery
|
||||||
return $projects;
|
return $projects;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
protected function buildSelectClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
$where = array();
|
$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) {
|
if ($this->status != self::STATUS_ANY) {
|
||||||
switch ($this->status) {
|
switch ($this->status) {
|
||||||
|
@ -264,86 +256,83 @@ final class PhabricatorProjectQuery
|
||||||
$this->status));
|
$this->status));
|
||||||
}
|
}
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'status IN (%Ld)',
|
'status IN (%Ld)',
|
||||||
$filter);
|
$filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->ids !== null) {
|
if ($this->ids !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'id IN (%Ld)',
|
'id IN (%Ld)',
|
||||||
$this->ids);
|
$this->ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->phids !== null) {
|
if ($this->phids !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'phid IN (%Ls)',
|
'phid IN (%Ls)',
|
||||||
$this->phids);
|
$this->phids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->memberPHIDs !== null) {
|
if ($this->memberPHIDs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'e.dst IN (%Ls)',
|
'e.dst IN (%Ls)',
|
||||||
$this->memberPHIDs);
|
$this->memberPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->slugs !== null) {
|
if ($this->slugs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'slug.slug IN (%Ls)',
|
'slug.slug IN (%Ls)',
|
||||||
$this->slugs);
|
$this->slugs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->phrictionSlugs !== null) {
|
if ($this->phrictionSlugs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'phrictionSlug IN (%Ls)',
|
'phrictionSlug IN (%Ls)',
|
||||||
$this->phrictionSlugs);
|
$this->phrictionSlugs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->names !== null) {
|
if ($this->names !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'name IN (%Ls)',
|
'name IN (%Ls)',
|
||||||
$this->names);
|
$this->names);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->icons !== null) {
|
if ($this->icons !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'icon IN (%Ls)',
|
'icon IN (%Ls)',
|
||||||
$this->icons);
|
$this->icons);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->colors !== null) {
|
if ($this->colors !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'color IN (%Ls)',
|
'color IN (%Ls)',
|
||||||
$this->colors);
|
$this->colors);
|
||||||
}
|
}
|
||||||
|
|
||||||
$where[] = $this->buildPagingClause($conn_r);
|
return $where;
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildGroupClause(AphrontDatabaseConnection $conn_r) {
|
protected function shouldGroupQueryResultRows() {
|
||||||
if ($this->memberPHIDs || $this->nameTokens) {
|
if ($this->memberPHIDs || $this->nameTokens) {
|
||||||
return 'GROUP BY p.id';
|
return true;
|
||||||
} else {
|
|
||||||
return $this->buildApplicationSearchGroupClause($conn_r);
|
|
||||||
}
|
}
|
||||||
|
return parent::shouldGroupQueryResultRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildJoinClause(AphrontDatabaseConnection $conn_r) {
|
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
$joins = array();
|
$joins = parent::buildJoinClauseParts($conn);
|
||||||
|
|
||||||
if (!$this->needMembers !== null) {
|
if (!$this->needMembers !== null) {
|
||||||
$joins[] = qsprintf(
|
$joins[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'LEFT JOIN %T vm ON vm.src = p.phid AND vm.type = %d AND vm.dst = %s',
|
'LEFT JOIN %T vm ON vm.src = p.phid AND vm.type = %d AND vm.dst = %s',
|
||||||
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
|
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
|
||||||
PhabricatorProjectProjectHasMemberEdgeType::EDGECONST,
|
PhabricatorProjectProjectHasMemberEdgeType::EDGECONST,
|
||||||
|
@ -352,7 +341,7 @@ final class PhabricatorProjectQuery
|
||||||
|
|
||||||
if ($this->memberPHIDs !== null) {
|
if ($this->memberPHIDs !== null) {
|
||||||
$joins[] = qsprintf(
|
$joins[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'JOIN %T e ON e.src = p.phid AND e.type = %d',
|
'JOIN %T e ON e.src = p.phid AND e.type = %d',
|
||||||
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
|
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
|
||||||
PhabricatorProjectProjectHasMemberEdgeType::EDGECONST);
|
PhabricatorProjectProjectHasMemberEdgeType::EDGECONST);
|
||||||
|
@ -360,7 +349,7 @@ final class PhabricatorProjectQuery
|
||||||
|
|
||||||
if ($this->slugs !== null) {
|
if ($this->slugs !== null) {
|
||||||
$joins[] = qsprintf(
|
$joins[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'JOIN %T slug on slug.projectPHID = p.phid',
|
'JOIN %T slug on slug.projectPHID = p.phid',
|
||||||
id(new PhabricatorProjectSlug())->getTableName());
|
id(new PhabricatorProjectSlug())->getTableName());
|
||||||
}
|
}
|
||||||
|
@ -369,7 +358,7 @@ final class PhabricatorProjectQuery
|
||||||
foreach ($this->nameTokens as $key => $token) {
|
foreach ($this->nameTokens as $key => $token) {
|
||||||
$token_table = 'token_'.$key;
|
$token_table = 'token_'.$key;
|
||||||
$joins[] = qsprintf(
|
$joins[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'JOIN %T %T ON %T.projectID = p.id AND %T.token LIKE %>',
|
'JOIN %T %T ON %T.projectID = p.id AND %T.token LIKE %>',
|
||||||
PhabricatorProject::TABLE_DATASOURCE_TOKEN,
|
PhabricatorProject::TABLE_DATASOURCE_TOKEN,
|
||||||
$token_table,
|
$token_table,
|
||||||
|
@ -379,9 +368,7 @@ final class PhabricatorProjectQuery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$joins[] = $this->buildApplicationSearchJoinClause($conn_r);
|
return $joins;
|
||||||
|
|
||||||
return implode(' ', $joins);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueryApplicationClass() {
|
public function getQueryApplicationClass() {
|
||||||
|
|
|
@ -113,6 +113,15 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($object instanceof PhabricatorSubscribableInterface) {
|
||||||
|
if (!empty($parameters['subscriberPHIDs'])) {
|
||||||
|
$query->withEdgeLogicPHIDs(
|
||||||
|
PhabricatorObjectHasSubscriberEdgeType::EDGECONST,
|
||||||
|
PhabricatorQueryConstraint::OPERATOR_OR,
|
||||||
|
$parameters['subscriberPHIDs']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($object instanceof PhabricatorProjectInterface) {
|
if ($object instanceof PhabricatorProjectInterface) {
|
||||||
if (!empty($parameters['projectPHIDs'])) {
|
if (!empty($parameters['projectPHIDs'])) {
|
||||||
$query->withEdgeLogicConstraints(
|
$query->withEdgeLogicConstraints(
|
||||||
|
@ -180,6 +189,13 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($object instanceof PhabricatorSubscribableInterface) {
|
||||||
|
$fields[] = id(new PhabricatorSearchSubscribersField())
|
||||||
|
->setLabel(pht('Subscribers'))
|
||||||
|
->setKey('subscriberPHIDs')
|
||||||
|
->setAliases(array('subscriber', 'subscribers'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($object instanceof PhabricatorProjectInterface) {
|
if ($object instanceof PhabricatorProjectInterface) {
|
||||||
$fields[] = id(new PhabricatorSearchProjectsField())
|
$fields[] = id(new PhabricatorSearchProjectsField())
|
||||||
->setKey('projectPHIDs')
|
->setKey('projectPHIDs')
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorSearchSubscribersField
|
||||||
|
extends PhabricatorSearchTokenizerField {
|
||||||
|
|
||||||
|
protected function getDefaultValue() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getValueFromRequest(AphrontRequest $request, $key) {
|
||||||
|
$allow_types = array(
|
||||||
|
PhabricatorProjectProjectPHIDType::TYPECONST,
|
||||||
|
);
|
||||||
|
return $this->getUsersFromRequest($request, $key, $allow_types);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newDatasource() {
|
||||||
|
return new PhabricatorMetaMTAMailableFunctionDatasource();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,9 +26,11 @@ abstract class PhabricatorSearchTokenizerField
|
||||||
abstract protected function newDatasource();
|
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);
|
$list = $this->getListFromRequest($request, $key);
|
||||||
$allow_types = array();
|
|
||||||
|
|
||||||
$phids = array();
|
$phids = array();
|
||||||
$names = array();
|
$names = array();
|
||||||
|
|
|
@ -76,7 +76,12 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
|
||||||
return $this->beforeID;
|
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');
|
$conn = $table->establishConnection('r');
|
||||||
|
|
||||||
$rows = queryfx_all(
|
$rows = queryfx_all(
|
||||||
|
@ -92,7 +97,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
|
||||||
$this->buildOrderClause($conn),
|
$this->buildOrderClause($conn),
|
||||||
$this->buildLimitClause($conn));
|
$this->buildLimitClause($conn));
|
||||||
|
|
||||||
return $table->loadAllFromArray($rows);
|
return $rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Reference in a new issue