2011-09-05 19:43:24 +02:00
|
|
|
<?php
|
|
|
|
|
2011-12-21 18:39:33 +01:00
|
|
|
/**
|
|
|
|
* Query symbol information (class and function names and location), returning
|
|
|
|
* a list of matching @{class:PhabricatorRepositorySymbol} objects and possibly
|
|
|
|
* attached data.
|
|
|
|
*
|
|
|
|
* @task config Configuring the Query
|
|
|
|
* @task exec Executing the Query
|
|
|
|
* @task internal Internals
|
|
|
|
*/
|
2012-08-01 21:36:47 +02:00
|
|
|
final class DiffusionSymbolQuery extends PhabricatorOffsetPagedQuery {
|
2011-09-05 19:43:24 +02:00
|
|
|
|
2015-02-01 03:36:36 +01:00
|
|
|
private $viewer;
|
2012-08-07 18:28:49 +02:00
|
|
|
private $context;
|
2011-09-05 19:43:24 +02:00
|
|
|
private $namePrefix;
|
|
|
|
private $name;
|
|
|
|
|
|
|
|
private $projectIDs;
|
|
|
|
private $language;
|
|
|
|
private $type;
|
|
|
|
|
2011-12-21 18:39:33 +01:00
|
|
|
private $needPaths;
|
|
|
|
private $needArcanistProject;
|
|
|
|
private $needRepositories;
|
|
|
|
|
|
|
|
|
|
|
|
/* -( Configuring the Query )---------------------------------------------- */
|
|
|
|
|
2015-02-01 03:36:36 +01:00
|
|
|
/**
|
|
|
|
* @task config
|
|
|
|
*/
|
|
|
|
public function setViewer(PhabricatorUser $viewer) {
|
|
|
|
$this->viewer = $viewer;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task config
|
|
|
|
*/
|
|
|
|
public function getViewer() {
|
|
|
|
return $this->viewer;
|
|
|
|
}
|
2011-12-21 18:39:33 +01:00
|
|
|
|
2012-08-07 18:28:49 +02:00
|
|
|
/**
|
|
|
|
* @task config
|
|
|
|
*/
|
|
|
|
public function setContext($context) {
|
|
|
|
$this->context = $context;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-21 18:39:33 +01:00
|
|
|
/**
|
|
|
|
* @task config
|
|
|
|
*/
|
2011-09-05 19:43:24 +02:00
|
|
|
public function setName($name) {
|
|
|
|
$this->name = $name;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-12-21 18:39:33 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @task config
|
|
|
|
*/
|
2011-09-05 19:43:24 +02:00
|
|
|
public function setNamePrefix($name_prefix) {
|
|
|
|
$this->namePrefix = $name_prefix;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-12-21 18:39:33 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @task config
|
|
|
|
*/
|
2011-09-05 19:43:24 +02:00
|
|
|
public function setProjectIDs(array $project_ids) {
|
|
|
|
$this->projectIDs = $project_ids;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-12-21 18:39:33 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @task config
|
|
|
|
*/
|
2011-09-05 19:43:24 +02:00
|
|
|
public function setLanguage($language) {
|
|
|
|
$this->language = $language;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-12-21 18:39:33 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @task config
|
|
|
|
*/
|
2011-09-05 19:43:24 +02:00
|
|
|
public function setType($type) {
|
|
|
|
$this->type = $type;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-12-21 18:39:33 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @task config
|
|
|
|
*/
|
|
|
|
public function needPaths($need_paths) {
|
|
|
|
$this->needPaths = $need_paths;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task config
|
|
|
|
*/
|
|
|
|
public function needArcanistProjects($need_arcanist_projects) {
|
|
|
|
$this->needArcanistProjects = $need_arcanist_projects;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task config
|
|
|
|
*/
|
|
|
|
public function needRepositories($need_repositories) {
|
|
|
|
$this->needRepositories = $need_repositories;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -( Executing the Query )------------------------------------------------ */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task exec
|
|
|
|
*/
|
2011-09-05 19:43:24 +02:00
|
|
|
public function execute() {
|
|
|
|
if ($this->name && $this->namePrefix) {
|
|
|
|
throw new Exception(
|
2014-06-09 20:36:49 +02:00
|
|
|
'You can not set both a name and a name prefix!');
|
2011-09-05 19:43:24 +02:00
|
|
|
} else if (!$this->name && !$this->namePrefix) {
|
|
|
|
throw new Exception(
|
2014-06-09 20:36:49 +02:00
|
|
|
'You must set a name or a name prefix!');
|
2011-09-05 19:43:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$symbol = new PhabricatorRepositorySymbol();
|
|
|
|
$conn_r = $symbol->establishConnection('r');
|
|
|
|
|
2012-08-01 21:36:47 +02:00
|
|
|
$data = queryfx_all(
|
|
|
|
$conn_r,
|
|
|
|
'SELECT * FROM %T %Q %Q %Q',
|
|
|
|
$symbol->getTableName(),
|
|
|
|
$this->buildWhereClause($conn_r),
|
|
|
|
$this->buildOrderClause($conn_r),
|
|
|
|
$this->buildLimitClause($conn_r));
|
|
|
|
|
|
|
|
$symbols = $symbol->loadAllFromArray($data);
|
|
|
|
|
|
|
|
if ($symbols) {
|
|
|
|
if ($this->needPaths) {
|
|
|
|
$this->loadPaths($symbols);
|
|
|
|
}
|
|
|
|
if ($this->needArcanistProjects || $this->needRepositories) {
|
|
|
|
$this->loadArcanistProjects($symbols);
|
|
|
|
}
|
|
|
|
if ($this->needRepositories) {
|
|
|
|
$this->loadRepositories($symbols);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return $symbols;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -( Internals )---------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task internal
|
|
|
|
*/
|
|
|
|
private function buildOrderClause($conn_r) {
|
|
|
|
return qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'ORDER BY symbolName ASC');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task internal
|
|
|
|
*/
|
Make buildWhereClause() a method of AphrontCursorPagedPolicyAwareQuery
Summary:
Ref T4100. Ref T5595.
To support a unified "Projects:" query across all applications, a future diff is going to add a set of "Edge Logic" capabilities to `PolicyAwareQuery` which write the required SELECT, JOIN, WHERE, HAVING and GROUP clauses for you.
With the addition of "Edge Logic", we'll have three systems which may need to build components of query claues: ordering/paging, customfields/applicationsearch, and edge logic.
For most clauses, queries don't currently call into the parent explicitly to get default components. I want to move more query construction logic up the class tree so it can be shared.
For most methods, this isn't a problem, but many subclasses define a `buildWhereClause()`. Make all such definitions protected and consistent.
This causes no behavioral changes.
Test Plan: Ran `arc unit --everything`, which does a pretty through job of verifying this statically.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: yelirekim, hach-que, epriestley
Maniphest Tasks: T4100, T5595
Differential Revision: https://secure.phabricator.com/D12453
2015-04-18 16:08:30 +02:00
|
|
|
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
2011-09-05 19:43:24 +02:00
|
|
|
$where = array();
|
2012-08-01 21:36:47 +02:00
|
|
|
|
2012-08-07 18:28:49 +02:00
|
|
|
if (isset($this->context)) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'symbolContext = %s',
|
|
|
|
$this->context);
|
|
|
|
}
|
|
|
|
|
2011-09-05 19:43:24 +02:00
|
|
|
if ($this->name) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'symbolName = %s',
|
|
|
|
$this->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->namePrefix) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'symbolName LIKE %>',
|
|
|
|
$this->namePrefix);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->projectIDs) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'arcanistProjectID IN (%Ld)',
|
|
|
|
$this->projectIDs);
|
|
|
|
}
|
|
|
|
|
2012-08-01 21:36:47 +02:00
|
|
|
if ($this->language) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'symbolLanguage = %s',
|
|
|
|
$this->language);
|
2011-12-21 18:39:33 +01:00
|
|
|
}
|
|
|
|
|
2012-08-10 07:16:32 +02:00
|
|
|
if ($this->type) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'symbolType = %s',
|
|
|
|
$this->type);
|
|
|
|
}
|
|
|
|
|
2012-08-01 21:36:47 +02:00
|
|
|
return $this->formatWhereClause($where);
|
2011-12-21 18:39:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task internal
|
|
|
|
*/
|
|
|
|
private function loadPaths(array $symbols) {
|
2012-04-04 01:22:31 +02:00
|
|
|
assert_instances_of($symbols, 'PhabricatorRepositorySymbol');
|
2011-12-21 18:39:33 +01:00
|
|
|
$path_map = queryfx_all(
|
|
|
|
id(new PhabricatorRepository())->establishConnection('r'),
|
|
|
|
'SELECT * FROM %T WHERE id IN (%Ld)',
|
|
|
|
PhabricatorRepository::TABLE_PATH,
|
|
|
|
mpull($symbols, 'getPathID'));
|
|
|
|
$path_map = ipull($path_map, 'path', 'id');
|
|
|
|
foreach ($symbols as $symbol) {
|
|
|
|
$symbol->attachPath(idx($path_map, $symbol->getPathID()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task internal
|
|
|
|
*/
|
|
|
|
private function loadArcanistProjects(array $symbols) {
|
2012-04-04 01:22:31 +02:00
|
|
|
assert_instances_of($symbols, 'PhabricatorRepositorySymbol');
|
2011-12-21 18:39:33 +01:00
|
|
|
$projects = id(new PhabricatorRepositoryArcanistProject())->loadAllWhere(
|
|
|
|
'id IN (%Ld)',
|
|
|
|
mpull($symbols, 'getArcanistProjectID'));
|
|
|
|
foreach ($symbols as $symbol) {
|
|
|
|
$project = idx($projects, $symbol->getArcanistProjectID());
|
|
|
|
$symbol->attachArcanistProject($project);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task internal
|
|
|
|
*/
|
|
|
|
private function loadRepositories(array $symbols) {
|
2012-04-04 01:22:31 +02:00
|
|
|
assert_instances_of($symbols, 'PhabricatorRepositorySymbol');
|
|
|
|
|
2011-12-21 18:39:33 +01:00
|
|
|
$projects = mpull($symbols, 'getArcanistProject');
|
|
|
|
$projects = array_filter($projects);
|
|
|
|
|
|
|
|
$repo_ids = mpull($projects, 'getRepositoryID');
|
|
|
|
$repo_ids = array_filter($repo_ids);
|
|
|
|
|
|
|
|
if ($repo_ids) {
|
2015-02-01 03:36:36 +01:00
|
|
|
$repos = id(new PhabricatorRepositoryQuery())
|
|
|
|
->setViewer($this->getViewer())
|
|
|
|
->withIDs($repo_ids)
|
|
|
|
->execute();
|
2011-12-21 18:39:33 +01:00
|
|
|
} else {
|
|
|
|
$repos = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($symbols as $symbol) {
|
|
|
|
$proj = $symbol->getArcanistProject();
|
|
|
|
if ($proj) {
|
|
|
|
$symbol->attachRepository(idx($repos, $proj->getRepositoryID()));
|
|
|
|
} else {
|
|
|
|
$symbol->attachRepository(null);
|
|
|
|
}
|
|
|
|
}
|
2011-09-05 19:43:24 +02:00
|
|
|
}
|
2011-12-21 18:39:33 +01:00
|
|
|
|
2011-09-05 19:43:24 +02:00
|
|
|
}
|