mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-18 21:02:41 +01:00
Support ordering in SearchField
Summary: Ref T8441. Ref T7715. Automatically generate a modern "Order" control in ApplicationSearch for engines which fully support SearchField. Notably, this allows the standard "Order" control to automatically support custom field orders. We do this in Maniphest today, but in an ad-hoc way. Test Plan: Performed order-by queries in Almanac (Services), Pholio, Files, People, Projects, and Paste. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T7715, T8441 Differential Revision: https://secure.phabricator.com/D13193
This commit is contained in:
parent
3cdaf52ce9
commit
bf87976d25
17 changed files with 229 additions and 154 deletions
|
@ -2520,6 +2520,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSearchManagementInitWorkflow' => 'applications/search/management/PhabricatorSearchManagementInitWorkflow.php',
|
'PhabricatorSearchManagementInitWorkflow' => 'applications/search/management/PhabricatorSearchManagementInitWorkflow.php',
|
||||||
'PhabricatorSearchManagementWorkflow' => 'applications/search/management/PhabricatorSearchManagementWorkflow.php',
|
'PhabricatorSearchManagementWorkflow' => 'applications/search/management/PhabricatorSearchManagementWorkflow.php',
|
||||||
'PhabricatorSearchOrderController' => 'applications/search/controller/PhabricatorSearchOrderController.php',
|
'PhabricatorSearchOrderController' => 'applications/search/controller/PhabricatorSearchOrderController.php',
|
||||||
|
'PhabricatorSearchOrderField' => 'applications/search/field/PhabricatorSearchOrderField.php',
|
||||||
'PhabricatorSearchOwnersField' => 'applications/search/field/PhabricatorSearchOwnersField.php',
|
'PhabricatorSearchOwnersField' => 'applications/search/field/PhabricatorSearchOwnersField.php',
|
||||||
'PhabricatorSearchPreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorSearchPreferencesSettingsPanel.php',
|
'PhabricatorSearchPreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorSearchPreferencesSettingsPanel.php',
|
||||||
'PhabricatorSearchProjectsField' => 'applications/search/field/PhabricatorSearchProjectsField.php',
|
'PhabricatorSearchProjectsField' => 'applications/search/field/PhabricatorSearchProjectsField.php',
|
||||||
|
@ -6024,6 +6025,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSearchManagementInitWorkflow' => 'PhabricatorSearchManagementWorkflow',
|
'PhabricatorSearchManagementInitWorkflow' => 'PhabricatorSearchManagementWorkflow',
|
||||||
'PhabricatorSearchManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
'PhabricatorSearchManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
'PhabricatorSearchOrderController' => 'PhabricatorSearchBaseController',
|
'PhabricatorSearchOrderController' => 'PhabricatorSearchBaseController',
|
||||||
|
'PhabricatorSearchOrderField' => 'PhabricatorSearchField',
|
||||||
'PhabricatorSearchOwnersField' => 'PhabricatorSearchTokenizerField',
|
'PhabricatorSearchOwnersField' => 'PhabricatorSearchTokenizerField',
|
||||||
'PhabricatorSearchPreferencesSettingsPanel' => 'PhabricatorSettingsPanel',
|
'PhabricatorSearchPreferencesSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||||
'PhabricatorSearchProjectsField' => 'PhabricatorSearchTokenizerField',
|
'PhabricatorSearchProjectsField' => 'PhabricatorSearchTokenizerField',
|
||||||
|
|
|
@ -60,47 +60,35 @@ final class AlmanacServiceQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$table = new AlmanacService();
|
return $this->loadStandardPage(new AlmanacService());
|
||||||
$conn_r = $table->establishConnection('r');
|
|
||||||
|
|
||||||
$data = queryfx_all(
|
|
||||||
$conn_r,
|
|
||||||
'SELECT service.* FROM %T service %Q %Q %Q %Q',
|
|
||||||
$table->getTableName(),
|
|
||||||
$this->buildJoinClause($conn_r),
|
|
||||||
$this->buildWhereClause($conn_r),
|
|
||||||
$this->buildOrderClause($conn_r),
|
|
||||||
$this->buildLimitClause($conn_r));
|
|
||||||
|
|
||||||
return $table->loadAllFromArray($data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildJoinClause(AphrontDatabaseConnection $conn_r) {
|
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
$joins = array();
|
$joins = parent::buildJoinClauseParts($conn);
|
||||||
|
|
||||||
if ($this->devicePHIDs !== null) {
|
if ($this->devicePHIDs !== null) {
|
||||||
$joins[] = qsprintf(
|
$joins[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'JOIN %T binding ON service.phid = binding.servicePHID',
|
'JOIN %T binding ON service.phid = binding.servicePHID',
|
||||||
id(new AlmanacBinding())->getTableName());
|
id(new AlmanacBinding())->getTableName());
|
||||||
}
|
}
|
||||||
|
|
||||||
return implode(' ', $joins);
|
return $joins;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
$where = array();
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
if ($this->ids !== null) {
|
if ($this->ids !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'service.id IN (%Ld)',
|
'service.id IN (%Ld)',
|
||||||
$this->ids);
|
$this->ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->phids !== null) {
|
if ($this->phids !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'service.phid IN (%Ls)',
|
'service.phid IN (%Ls)',
|
||||||
$this->phids);
|
$this->phids);
|
||||||
}
|
}
|
||||||
|
@ -112,49 +100,47 @@ final class AlmanacServiceQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'service.nameIndex IN (%Ls)',
|
'service.nameIndex IN (%Ls)',
|
||||||
$hashes);
|
$hashes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->serviceClasses !== null) {
|
if ($this->serviceClasses !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'service.serviceClass IN (%Ls)',
|
'service.serviceClass IN (%Ls)',
|
||||||
$this->serviceClasses);
|
$this->serviceClasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->devicePHIDs !== null) {
|
if ($this->devicePHIDs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'binding.devicePHID IN (%Ls)',
|
'binding.devicePHID IN (%Ls)',
|
||||||
$this->devicePHIDs);
|
$this->devicePHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->locked !== null) {
|
if ($this->locked !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'service.isLocked = %d',
|
'service.isLocked = %d',
|
||||||
(int)$this->locked);
|
(int)$this->locked);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->namePrefix !== null) {
|
if ($this->namePrefix !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'service.name LIKE %>',
|
'service.name LIKE %>',
|
||||||
$this->namePrefix);
|
$this->namePrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->nameSuffix !== null) {
|
if ($this->nameSuffix !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'service.name LIKE %<',
|
'service.name LIKE %<',
|
||||||
$this->nameSuffix);
|
$this->nameSuffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
$where[] = $this->buildPagingClause($conn_r);
|
return $where;
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function willFilterPage(array $services) {
|
protected function willFilterPage(array $services) {
|
||||||
|
@ -192,10 +178,14 @@ final class AlmanacServiceQuery
|
||||||
return parent::didFilterPage($services);
|
return parent::didFilterPage($services);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPrimaryTableAlias() {
|
||||||
|
return 'service';
|
||||||
|
}
|
||||||
|
|
||||||
public function getOrderableColumns() {
|
public function getOrderableColumns() {
|
||||||
return parent::getOrderableColumns() + array(
|
return parent::getOrderableColumns() + array(
|
||||||
'name' => array(
|
'name' => array(
|
||||||
'table' => 'service',
|
'table' => $this->getPrimaryTableAlias(),
|
||||||
'column' => 'name',
|
'column' => 'name',
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'unique' => true,
|
'unique' => true,
|
||||||
|
|
|
@ -11,30 +11,26 @@ final class AlmanacServiceSearchEngine
|
||||||
return 'PhabricatorAlmanacApplication';
|
return 'PhabricatorAlmanacApplication';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
public function newQuery() {
|
||||||
$saved = new PhabricatorSavedQuery();
|
return new AlmanacServiceQuery();
|
||||||
|
|
||||||
$this->saveQueryOrder($saved, $request);
|
|
||||||
|
|
||||||
return $saved;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
public function newResultObject() {
|
||||||
$query = id(new AlmanacServiceQuery());
|
// NOTE: We need to attach a service type in order to generate custom
|
||||||
|
// field definitions.
|
||||||
|
return AlmanacService::initializeNewService()
|
||||||
|
->attachServiceType(new AlmanacCustomServiceType());
|
||||||
|
}
|
||||||
|
|
||||||
$this->setQueryOrder($query, $saved);
|
protected function buildQueryFromParameters(array $map) {
|
||||||
|
$query = $this->newQuery();
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildSearchForm(
|
|
||||||
AphrontFormView $form,
|
|
||||||
PhabricatorSavedQuery $saved) {
|
|
||||||
|
|
||||||
$this->appendOrderFieldsToForm(
|
protected function buildCustomSearchFields() {
|
||||||
$form,
|
return array();
|
||||||
$saved,
|
|
||||||
new AlmanacServiceQuery());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getURI($path) {
|
protected function getURI($path) {
|
||||||
|
@ -62,12 +58,6 @@ final class AlmanacServiceSearchEngine
|
||||||
return parent::buildSavedQueryFromBuiltin($query_key);
|
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getRequiredHandlePHIDsForResultList(
|
|
||||||
array $services,
|
|
||||||
PhabricatorSavedQuery $query) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function renderResultList(
|
protected function renderResultList(
|
||||||
array $services,
|
array $services,
|
||||||
PhabricatorSavedQuery $query,
|
PhabricatorSavedQuery $query,
|
||||||
|
|
|
@ -117,6 +117,10 @@ final class PhabricatorFileQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new PhabricatorFile();
|
||||||
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$files = $this->loadStandardPage(new PhabricatorFile());
|
$files = $this->loadStandardPage(new PhabricatorFile());
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ final class PhabricatorFileSearchEngine
|
||||||
return 'PhabricatorFilesApplication';
|
return 'PhabricatorFilesApplication';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newResultObject() {
|
public function newQuery() {
|
||||||
return new PhabricatorFile();
|
return new PhabricatorFileQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildCustomSearchFields() {
|
protected function buildCustomSearchFields() {
|
||||||
|
@ -46,7 +46,7 @@ final class PhabricatorFileSearchEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildQueryFromParameters(array $map) {
|
public function buildQueryFromParameters(array $map) {
|
||||||
$query = id(new PhabricatorFileQuery());
|
$query = $this->newQuery();
|
||||||
|
|
||||||
if ($map['authorPHIDs']) {
|
if ($map['authorPHIDs']) {
|
||||||
$query->withAuthorPHIDs($map['authorPHIDs']);
|
$query->withAuthorPHIDs($map['authorPHIDs']);
|
||||||
|
|
|
@ -193,7 +193,7 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newResultObject() {
|
public function newResultObject() {
|
||||||
return new ManiphestTask();
|
return new ManiphestTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ final class PhabricatorPasteQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newResultObject() {
|
public function newResultObject() {
|
||||||
return new PhabricatorPaste();
|
return new PhabricatorPaste();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,13 @@ final class PhabricatorPasteSearchEngine
|
||||||
return 'PhabricatorPasteApplication';
|
return 'PhabricatorPasteApplication';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newResultObject() {
|
public function newQuery() {
|
||||||
return new PhabricatorPaste();
|
return id(new PhabricatorPasteQuery())
|
||||||
|
->needContent(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildQueryFromParameters(array $map) {
|
protected function buildQueryFromParameters(array $map) {
|
||||||
$query = id(new PhabricatorPasteQuery())
|
$query = $this->newQuery();
|
||||||
->needContent(true);
|
|
||||||
|
|
||||||
if ($map['authorPHIDs']) {
|
if ($map['authorPHIDs']) {
|
||||||
$query->withAuthorPHIDs($map['authorPHIDs']);
|
$query->withAuthorPHIDs($map['authorPHIDs']);
|
||||||
|
|
|
@ -113,19 +113,13 @@ final class PhabricatorPeopleQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
public function newResultObject() {
|
||||||
$table = new PhabricatorUser();
|
return new PhabricatorUser();
|
||||||
$conn_r = $table->establishConnection('r');
|
}
|
||||||
|
|
||||||
$data = queryfx_all(
|
protected function loadPage() {
|
||||||
$conn_r,
|
$table = new PhabricatorUser();
|
||||||
'SELECT * FROM %T user %Q %Q %Q %Q %Q',
|
$data = $this->loadStandardPageRows($table);
|
||||||
$table->getTableName(),
|
|
||||||
$this->buildJoinsClause($conn_r),
|
|
||||||
$this->buildWhereClause($conn_r),
|
|
||||||
$this->buildGroupClause($conn_r),
|
|
||||||
$this->buildOrderClause($conn_r),
|
|
||||||
$this->buildLimitClause($conn_r));
|
|
||||||
|
|
||||||
if ($this->needPrimaryEmail) {
|
if ($this->needPrimaryEmail) {
|
||||||
$table->putInSet(new LiskDAOSet());
|
$table->putInSet(new LiskDAOSet());
|
||||||
|
@ -225,23 +219,21 @@ final class PhabricatorPeopleQuery
|
||||||
return $users;
|
return $users;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildGroupClause(AphrontDatabaseConnection $conn) {
|
protected function shouldGroupQueryResultRows() {
|
||||||
if ($this->nameTokens) {
|
if ($this->nameTokens) {
|
||||||
return qsprintf(
|
return true;
|
||||||
$conn,
|
|
||||||
'GROUP BY user.id');
|
|
||||||
} else {
|
|
||||||
return $this->buildApplicationSearchGroupClause($conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return parent::shouldGroupQueryResultRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildJoinsClause($conn_r) {
|
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
$joins = array();
|
$joins = parent::buildJoinClauseParts($conn);
|
||||||
|
|
||||||
if ($this->emails) {
|
if ($this->emails) {
|
||||||
$email_table = new PhabricatorUserEmail();
|
$email_table = new PhabricatorUserEmail();
|
||||||
$joins[] = qsprintf(
|
$joins[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'JOIN %T email ON email.userPHID = user.PHID',
|
'JOIN %T email ON email.userPHID = user.PHID',
|
||||||
$email_table->getTableName());
|
$email_table->getTableName());
|
||||||
}
|
}
|
||||||
|
@ -250,7 +242,7 @@ final class PhabricatorPeopleQuery
|
||||||
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.userID = user.id AND %T.token LIKE %>',
|
'JOIN %T %T ON %T.userID = user.id AND %T.token LIKE %>',
|
||||||
PhabricatorUser::NAMETOKEN_TABLE,
|
PhabricatorUser::NAMETOKEN_TABLE,
|
||||||
$token_table,
|
$token_table,
|
||||||
|
@ -260,110 +252,105 @@ final class PhabricatorPeopleQuery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$joins[] = $this->buildApplicationSearchJoinClause($conn_r);
|
|
||||||
|
|
||||||
$joins = implode(' ', $joins);
|
|
||||||
return $joins;
|
return $joins;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
$where = array();
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
if ($this->usernames !== null) {
|
if ($this->usernames !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'user.userName IN (%Ls)',
|
'user.userName IN (%Ls)',
|
||||||
$this->usernames);
|
$this->usernames);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->emails !== null) {
|
if ($this->emails !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'email.address IN (%Ls)',
|
'email.address IN (%Ls)',
|
||||||
$this->emails);
|
$this->emails);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->realnames !== null) {
|
if ($this->realnames !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'user.realName IN (%Ls)',
|
'user.realName IN (%Ls)',
|
||||||
$this->realnames);
|
$this->realnames);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->phids !== null) {
|
if ($this->phids !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'user.phid IN (%Ls)',
|
'user.phid IN (%Ls)',
|
||||||
$this->phids);
|
$this->phids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->ids !== null) {
|
if ($this->ids !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'user.id IN (%Ld)',
|
'user.id IN (%Ld)',
|
||||||
$this->ids);
|
$this->ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->dateCreatedAfter) {
|
if ($this->dateCreatedAfter) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'user.dateCreated >= %d',
|
'user.dateCreated >= %d',
|
||||||
$this->dateCreatedAfter);
|
$this->dateCreatedAfter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->dateCreatedBefore) {
|
if ($this->dateCreatedBefore) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'user.dateCreated <= %d',
|
'user.dateCreated <= %d',
|
||||||
$this->dateCreatedBefore);
|
$this->dateCreatedBefore);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isAdmin !== null) {
|
if ($this->isAdmin !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'user.isAdmin = %d',
|
'user.isAdmin = %d',
|
||||||
(int)$this->isAdmin);
|
(int)$this->isAdmin);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isDisabled !== null) {
|
if ($this->isDisabled !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'user.isDisabled = %d',
|
'user.isDisabled = %d',
|
||||||
(int)$this->isDisabled);
|
(int)$this->isDisabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isApproved !== null) {
|
if ($this->isApproved !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'user.isApproved = %d',
|
'user.isApproved = %d',
|
||||||
(int)$this->isApproved);
|
(int)$this->isApproved);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isSystemAgent !== null) {
|
if ($this->isSystemAgent !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'user.isSystemAgent = %d',
|
'user.isSystemAgent = %d',
|
||||||
(int)$this->isSystemAgent);
|
(int)$this->isSystemAgent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isMailingList !== null) {
|
if ($this->isMailingList !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'user.isMailingList = %d',
|
'user.isMailingList = %d',
|
||||||
(int)$this->isMailingList);
|
(int)$this->isMailingList);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen($this->nameLike)) {
|
if (strlen($this->nameLike)) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'user.username LIKE %~ OR user.realname LIKE %~',
|
'user.username LIKE %~ OR user.realname LIKE %~',
|
||||||
$this->nameLike,
|
$this->nameLike,
|
||||||
$this->nameLike);
|
$this->nameLike);
|
||||||
}
|
}
|
||||||
|
|
||||||
$where[] = $this->buildPagingClause($conn_r);
|
return $where;
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getPrimaryTableAlias() {
|
protected function getPrimaryTableAlias() {
|
||||||
|
|
|
@ -11,8 +11,10 @@ final class PhabricatorPeopleSearchEngine
|
||||||
return 'PhabricatorPeopleApplication';
|
return 'PhabricatorPeopleApplication';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newResultObject() {
|
public function newQuery() {
|
||||||
return new PhabricatorUser();
|
return id(new PhabricatorPeopleQuery())
|
||||||
|
->needPrimaryEmail(true)
|
||||||
|
->needProfileImage(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildCustomSearchFields() {
|
protected function buildCustomSearchFields() {
|
||||||
|
@ -77,9 +79,7 @@ final class PhabricatorPeopleSearchEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildQueryFromParameters(array $map) {
|
public function buildQueryFromParameters(array $map) {
|
||||||
$query = id(new PhabricatorPeopleQuery())
|
$query = $this->newQuery();
|
||||||
->needPrimaryEmail(true)
|
|
||||||
->needProfileImage(true);
|
|
||||||
|
|
||||||
$viewer = $this->requireViewer();
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,10 @@ final class PholioMockQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new PholioMock();
|
||||||
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$mocks = $this->loadStandardPage(new PholioMock());
|
$mocks = $this->loadStandardPage(new PholioMock());
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,14 @@ final class PholioMockSearchEngine extends PhabricatorApplicationSearchEngine {
|
||||||
return 'PhabricatorPholioApplication';
|
return 'PhabricatorPholioApplication';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newResultObject() {
|
public function newQuery() {
|
||||||
return new PholioMock();
|
return id(new PholioMockQuery())
|
||||||
|
->needCoverFiles(true)
|
||||||
|
->needImages(true)
|
||||||
|
->needTokenCounts(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildCustomSearchFields() {
|
protected function buildCustomSearchFields() {
|
||||||
return array(
|
return array(
|
||||||
id(new PhabricatorSearchUsersField())
|
id(new PhabricatorSearchUsersField())
|
||||||
->setKey('authorPHIDs')
|
->setKey('authorPHIDs')
|
||||||
|
@ -30,10 +33,7 @@ final class PholioMockSearchEngine extends PhabricatorApplicationSearchEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildQueryFromParameters(array $map) {
|
public function buildQueryFromParameters(array $map) {
|
||||||
$query = id(new PholioMockQuery())
|
$query = $this->newQuery();
|
||||||
->needCoverFiles(true)
|
|
||||||
->needImages(true)
|
|
||||||
->needTokenCounts(true);
|
|
||||||
|
|
||||||
if ($map['authorPHIDs']) {
|
if ($map['authorPHIDs']) {
|
||||||
$query->withAuthorPHIDs($map['authorPHIDs']);
|
$query->withAuthorPHIDs($map['authorPHIDs']);
|
||||||
|
|
|
@ -95,12 +95,25 @@ final class PhabricatorProjectQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new PhabricatorProject();
|
||||||
|
}
|
||||||
|
|
||||||
protected function getDefaultOrderVector() {
|
protected function getDefaultOrderVector() {
|
||||||
return array('name');
|
return array('name');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOrderableColumns() {
|
public function getBuiltinOrders() {
|
||||||
return array(
|
return array(
|
||||||
|
'name' => array(
|
||||||
|
'vector' => array('name'),
|
||||||
|
'name' => pht('Name'),
|
||||||
|
),
|
||||||
|
) + parent::getBuiltinOrders();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOrderableColumns() {
|
||||||
|
return parent::getOrderableColumns() + array(
|
||||||
'name' => array(
|
'name' => array(
|
||||||
'table' => $this->getPrimaryTableAlias(),
|
'table' => $this->getPrimaryTableAlias(),
|
||||||
'column' => 'name',
|
'column' => 'name',
|
||||||
|
|
|
@ -11,8 +11,9 @@ final class PhabricatorProjectSearchEngine
|
||||||
return 'PhabricatorProjectApplication';
|
return 'PhabricatorProjectApplication';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newResultObject() {
|
public function newQuery() {
|
||||||
return new PhabricatorProject();
|
return id(new PhabricatorProjectQuery())
|
||||||
|
->needImages(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildCustomSearchFields() {
|
protected function buildCustomSearchFields() {
|
||||||
|
@ -41,8 +42,7 @@ final class PhabricatorProjectSearchEngine
|
||||||
|
|
||||||
|
|
||||||
public function buildQueryFromParameters(array $map) {
|
public function buildQueryFromParameters(array $map) {
|
||||||
$query = id(new PhabricatorProjectQuery())
|
$query = $this->newQuery();
|
||||||
->needImages(true);
|
|
||||||
|
|
||||||
if (strlen($map['name'])) {
|
if (strlen($map['name'])) {
|
||||||
$tokens = PhabricatorTypeaheadDatasource::tokenizeString($map['name']);
|
$tokens = PhabricatorTypeaheadDatasource::tokenizeString($map['name']);
|
||||||
|
|
|
@ -27,6 +27,19 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
const CONTEXT_PANEL = 'panel';
|
const CONTEXT_PANEL = 'panel';
|
||||||
|
|
||||||
public function newResultObject() {
|
public function newResultObject() {
|
||||||
|
// We may be able to get this automatically if newQuery() is implemented.
|
||||||
|
$query = $this->newQuery();
|
||||||
|
if ($query) {
|
||||||
|
$object = $query->newResultObject();
|
||||||
|
if ($object) {
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newQuery() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,15 +111,15 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
$fields = $this->buildSearchFields();
|
$fields = $this->buildSearchFields();
|
||||||
$viewer = $this->requireViewer();
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
$parameters = array();
|
$map = array();
|
||||||
foreach ($fields as $field) {
|
foreach ($fields as $field) {
|
||||||
$field->setViewer($viewer);
|
$field->setViewer($viewer);
|
||||||
$field->readValueFromSavedQuery($saved);
|
$field->readValueFromSavedQuery($saved);
|
||||||
$value = $field->getValueForQuery($field->getValue());
|
$value = $field->getValueForQuery($field->getValue());
|
||||||
$parameters[$field->getKey()] = $value;
|
$map[$field->getKey()] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = $this->buildQueryFromParameters($parameters);
|
$query = $this->buildQueryFromParameters($map);
|
||||||
|
|
||||||
$object = $this->newResultObject();
|
$object = $this->newResultObject();
|
||||||
if (!$object) {
|
if (!$object) {
|
||||||
|
@ -114,25 +127,25 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($object instanceof PhabricatorSubscribableInterface) {
|
if ($object instanceof PhabricatorSubscribableInterface) {
|
||||||
if (!empty($parameters['subscriberPHIDs'])) {
|
if (!empty($map['subscriberPHIDs'])) {
|
||||||
$query->withEdgeLogicPHIDs(
|
$query->withEdgeLogicPHIDs(
|
||||||
PhabricatorObjectHasSubscriberEdgeType::EDGECONST,
|
PhabricatorObjectHasSubscriberEdgeType::EDGECONST,
|
||||||
PhabricatorQueryConstraint::OPERATOR_OR,
|
PhabricatorQueryConstraint::OPERATOR_OR,
|
||||||
$parameters['subscriberPHIDs']);
|
$map['subscriberPHIDs']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($object instanceof PhabricatorProjectInterface) {
|
if ($object instanceof PhabricatorProjectInterface) {
|
||||||
if (!empty($parameters['projectPHIDs'])) {
|
if (!empty($map['projectPHIDs'])) {
|
||||||
$query->withEdgeLogicConstraints(
|
$query->withEdgeLogicConstraints(
|
||||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
|
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
|
||||||
$parameters['projectPHIDs']);
|
$map['projectPHIDs']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($object instanceof PhabricatorSpacesInterface) {
|
if ($object instanceof PhabricatorSpacesInterface) {
|
||||||
if (!empty($parameters['spacePHIDs'])) {
|
if (!empty($map['spacePHIDs'])) {
|
||||||
$query->withSpacePHIDs($parameters['spacePHIDs']);
|
$query->withSpacePHIDs($map['spacePHIDs']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,6 +153,8 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
$this->applyCustomFieldsToQuery($query, $saved);
|
$this->applyCustomFieldsToQuery($query, $saved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->setQueryOrder($query, $saved);
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,30 +200,28 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
$object = $this->newResultObject();
|
$object = $this->newResultObject();
|
||||||
if (!$object) {
|
if ($object) {
|
||||||
return $fields;
|
if ($object instanceof PhabricatorSubscribableInterface) {
|
||||||
}
|
$fields[] = id(new PhabricatorSearchSubscribersField())
|
||||||
|
->setLabel(pht('Subscribers'))
|
||||||
|
->setKey('subscriberPHIDs')
|
||||||
|
->setAliases(array('subscriber', 'subscribers'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($object instanceof PhabricatorSubscribableInterface) {
|
if ($object instanceof PhabricatorProjectInterface) {
|
||||||
$fields[] = id(new PhabricatorSearchSubscribersField())
|
$fields[] = id(new PhabricatorSearchProjectsField())
|
||||||
->setLabel(pht('Subscribers'))
|
->setKey('projectPHIDs')
|
||||||
->setKey('subscriberPHIDs')
|
->setAliases(array('project', 'projects'))
|
||||||
->setAliases(array('subscriber', 'subscribers'));
|
->setLabel(pht('Projects'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($object instanceof PhabricatorProjectInterface) {
|
if ($object instanceof PhabricatorSpacesInterface) {
|
||||||
$fields[] = id(new PhabricatorSearchProjectsField())
|
if (PhabricatorSpacesNamespaceQuery::getSpacesExist()) {
|
||||||
->setKey('projectPHIDs')
|
$fields[] = id(new PhabricatorSearchSpacesField())
|
||||||
->setAliases(array('project', 'projects'))
|
->setKey('spacePHIDs')
|
||||||
->setLabel(pht('Projects'));
|
->setAliases(array('space', 'spaces'))
|
||||||
}
|
->setLabel(pht('Spaces'));
|
||||||
|
}
|
||||||
if ($object instanceof PhabricatorSpacesInterface) {
|
|
||||||
if (PhabricatorSpacesNamespaceQuery::getSpacesExist()) {
|
|
||||||
$fields[] = id(new PhabricatorSearchSpacesField())
|
|
||||||
->setKey('spacePHIDs')
|
|
||||||
->setAliases(array('space', 'spaces'))
|
|
||||||
->setLabel(pht('Spaces'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +229,17 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
$fields[] = $custom_field;
|
$fields[] = $custom_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$query = $this->newQuery();
|
||||||
|
if ($query) {
|
||||||
|
$orders = $query->getBuiltinOrders();
|
||||||
|
$orders = ipull($orders, 'name');
|
||||||
|
|
||||||
|
$fields[] = id(new PhabricatorSearchOrderField())
|
||||||
|
->setLabel(pht('Order'))
|
||||||
|
->setKey('order')
|
||||||
|
->setOptions($orders);
|
||||||
|
}
|
||||||
|
|
||||||
$field_map = array();
|
$field_map = array();
|
||||||
foreach ($fields as $field) {
|
foreach ($fields as $field) {
|
||||||
$key = $field->getKey();
|
$key = $field->getKey();
|
||||||
|
@ -890,6 +914,7 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
|
|
||||||
$order = $saved->getParameter('order');
|
$order = $saved->getParameter('order');
|
||||||
$builtin = $query->getBuiltinOrders();
|
$builtin = $query->getBuiltinOrders();
|
||||||
|
|
||||||
if (strlen($order) && isset($builtin[$order])) {
|
if (strlen($order) && isset($builtin[$order])) {
|
||||||
$query->setOrder($order);
|
$query->setOrder($order);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorSearchOrderField
|
||||||
|
extends PhabricatorSearchField {
|
||||||
|
|
||||||
|
private $options;
|
||||||
|
|
||||||
|
public function setOptions(array $options) {
|
||||||
|
$this->options = $options;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOptions() {
|
||||||
|
return $this->options;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDefaultValue() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getValueFromRequest(AphrontRequest $request, $key) {
|
||||||
|
return $request->getStr($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newControl() {
|
||||||
|
return id(new AphrontFormSelectControl())
|
||||||
|
->setOptions($this->getOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -200,7 +200,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newResultObject() {
|
public function newResultObject() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,6 +844,9 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
|
||||||
'column' => 'indexValue',
|
'column' => 'indexValue',
|
||||||
'type' => $index->getIndexValueType(),
|
'type' => $index->getIndexValueType(),
|
||||||
'null' => 'tail',
|
'null' => 'tail',
|
||||||
|
'customfield' => true,
|
||||||
|
'customfield.index.table' => $index->getTableName(),
|
||||||
|
'customfield.index.key' => $digest,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1229,6 +1232,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Get rid of this.
|
||||||
foreach ($this->applicationSearchOrders as $key => $order) {
|
foreach ($this->applicationSearchOrders as $key => $order) {
|
||||||
$table = $order['table'];
|
$table = $order['table'];
|
||||||
$index = $order['index'];
|
$index = $order['index'];
|
||||||
|
@ -1247,6 +1251,32 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
|
||||||
$index);
|
$index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$phid_column = $this->getApplicationSearchObjectPHIDColumn();
|
||||||
|
$orderable = $this->getOrderableColumns();
|
||||||
|
|
||||||
|
$vector = $this->getOrderVector();
|
||||||
|
foreach ($vector as $order) {
|
||||||
|
$spec = $orderable[$order->getOrderKey()];
|
||||||
|
if (empty($spec['customfield'])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = $spec['customfield.index.table'];
|
||||||
|
$alias = $spec['table'];
|
||||||
|
$key = $spec['customfield.index.key'];
|
||||||
|
|
||||||
|
$joins[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'LEFT JOIN %T %T ON %T.objectPHID = %Q
|
||||||
|
AND %T.indexKey = %s',
|
||||||
|
$table,
|
||||||
|
$alias,
|
||||||
|
$alias,
|
||||||
|
$phid_column,
|
||||||
|
$alias,
|
||||||
|
$key);
|
||||||
|
}
|
||||||
|
|
||||||
return implode(' ', $joins);
|
return implode(' ', $joins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue