PageRenderTime 22ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/applications/diffusion/query/symbol/DiffusionSymbolQuery.php

http://github.com/facebook/phabricator
PHP | 280 lines | 152 code | 57 blank | 71 comment | 23 complexity | fe5bde81d3d1fb14b7c67f2c289b7b94 MD5 | raw file
Possible License(s): JSON, MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause, LGPL-2.0, MIT, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /*
  3. * Copyright 2011 Facebook, Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /**
  18. * Query symbol information (class and function names and location), returning
  19. * a list of matching @{class:PhabricatorRepositorySymbol} objects and possibly
  20. * attached data.
  21. *
  22. * @task config Configuring the Query
  23. * @task exec Executing the Query
  24. * @task internal Internals
  25. *
  26. * @group diffusion
  27. */
  28. final class DiffusionSymbolQuery {
  29. private $namePrefix;
  30. private $name;
  31. private $projectIDs;
  32. private $language;
  33. private $type;
  34. private $limit = 20;
  35. private $needPaths;
  36. private $needArcanistProject;
  37. private $needRepositories;
  38. /* -( Configuring the Query )---------------------------------------------- */
  39. /**
  40. * @task config
  41. */
  42. public function setName($name) {
  43. $this->name = $name;
  44. return $this;
  45. }
  46. /**
  47. * @task config
  48. */
  49. public function setNamePrefix($name_prefix) {
  50. $this->namePrefix = $name_prefix;
  51. return $this;
  52. }
  53. /**
  54. * @task config
  55. */
  56. public function setProjectIDs(array $project_ids) {
  57. $this->projectIDs = $project_ids;
  58. return $this;
  59. }
  60. /**
  61. * @task config
  62. */
  63. public function setLanguage($language) {
  64. $this->language = $language;
  65. return $this;
  66. }
  67. /**
  68. * @task config
  69. */
  70. public function setType($type) {
  71. $this->type = $type;
  72. return $this;
  73. }
  74. /**
  75. * @task config
  76. */
  77. public function setLimit($limit) {
  78. $this->limit = $limit;
  79. return $this;
  80. }
  81. /**
  82. * @task config
  83. */
  84. public function needPaths($need_paths) {
  85. $this->needPaths = $need_paths;
  86. return $this;
  87. }
  88. /**
  89. * @task config
  90. */
  91. public function needArcanistProjects($need_arcanist_projects) {
  92. $this->needArcanistProjects = $need_arcanist_projects;
  93. return $this;
  94. }
  95. /**
  96. * @task config
  97. */
  98. public function needRepositories($need_repositories) {
  99. $this->needRepositories = $need_repositories;
  100. return $this;
  101. }
  102. /* -( Executing the Query )------------------------------------------------ */
  103. /**
  104. * @task exec
  105. */
  106. public function execute() {
  107. if ($this->name && $this->namePrefix) {
  108. throw new Exception(
  109. "You can not set both a name and a name prefix!");
  110. } else if (!$this->name && !$this->namePrefix) {
  111. throw new Exception(
  112. "You must set a name or a name prefix!");
  113. }
  114. $symbol = new PhabricatorRepositorySymbol();
  115. $conn_r = $symbol->establishConnection('r');
  116. $where = array();
  117. if ($this->name) {
  118. $where[] = qsprintf(
  119. $conn_r,
  120. 'symbolName = %s',
  121. $this->name);
  122. }
  123. if ($this->namePrefix) {
  124. $where[] = qsprintf(
  125. $conn_r,
  126. 'symbolName LIKE %>',
  127. $this->namePrefix);
  128. }
  129. if ($this->projectIDs) {
  130. $where[] = qsprintf(
  131. $conn_r,
  132. 'arcanistProjectID IN (%Ld)',
  133. $this->projectIDs);
  134. }
  135. $where = 'WHERE ('.implode(') AND (', $where).')';
  136. $data = queryfx_all(
  137. $conn_r,
  138. 'SELECT * FROM %T %Q',
  139. $symbol->getTableName(),
  140. $where);
  141. // Our ability to match up symbol types and languages probably isn't all
  142. // that great, so use them as hints for ranking rather than hard
  143. // requirements. TODO: Is this really the right choice?
  144. foreach ($data as $key => $row) {
  145. $score = 0;
  146. if ($this->language && $row['symbolLanguage'] == $this->language) {
  147. $score += 2;
  148. }
  149. if ($this->type && $row['symbolType'] == $this->type) {
  150. $score += 1;
  151. }
  152. $data[$key]['score'] = $score;
  153. $data[$key]['id'] = $key;
  154. }
  155. $data = isort($data, 'score');
  156. $data = array_reverse($data);
  157. $data = array_slice($data, 0, $this->limit);
  158. $symbols = $symbol->loadAllFromArray($data);
  159. if ($symbols) {
  160. if ($this->needPaths) {
  161. $this->loadPaths($symbols);
  162. }
  163. if ($this->needArcanistProjects || $this->needRepositories) {
  164. $this->loadArcanistProjects($symbols);
  165. }
  166. if ($this->needRepositories) {
  167. $this->loadRepositories($symbols);
  168. }
  169. }
  170. return $symbols;
  171. }
  172. /* -( Internals )---------------------------------------------------------- */
  173. /**
  174. * @task internal
  175. */
  176. private function loadPaths(array $symbols) {
  177. $path_map = queryfx_all(
  178. id(new PhabricatorRepository())->establishConnection('r'),
  179. 'SELECT * FROM %T WHERE id IN (%Ld)',
  180. PhabricatorRepository::TABLE_PATH,
  181. mpull($symbols, 'getPathID'));
  182. $path_map = ipull($path_map, 'path', 'id');
  183. foreach ($symbols as $symbol) {
  184. $symbol->attachPath(idx($path_map, $symbol->getPathID()));
  185. }
  186. }
  187. /**
  188. * @task internal
  189. */
  190. private function loadArcanistProjects(array $symbols) {
  191. $projects = id(new PhabricatorRepositoryArcanistProject())->loadAllWhere(
  192. 'id IN (%Ld)',
  193. mpull($symbols, 'getArcanistProjectID'));
  194. foreach ($symbols as $symbol) {
  195. $project = idx($projects, $symbol->getArcanistProjectID());
  196. $symbol->attachArcanistProject($project);
  197. }
  198. }
  199. /**
  200. * @task internal
  201. */
  202. private function loadRepositories(array $symbols) {
  203. $projects = mpull($symbols, 'getArcanistProject');
  204. $projects = array_filter($projects);
  205. $repo_ids = mpull($projects, 'getRepositoryID');
  206. $repo_ids = array_filter($repo_ids);
  207. if ($repo_ids) {
  208. $repos = id(new PhabricatorRepository())->loadAllWhere(
  209. 'id IN (%Ld)',
  210. $repo_ids);
  211. } else {
  212. $repos = array();
  213. }
  214. foreach ($symbols as $symbol) {
  215. $proj = $symbol->getArcanistProject();
  216. if ($proj) {
  217. $symbol->attachRepository(idx($repos, $proj->getRepositoryID()));
  218. } else {
  219. $symbol->attachRepository(null);
  220. }
  221. }
  222. }
  223. }