PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/src/applications/phid/query/PhabricatorObjectQuery.php

http://github.com/facebook/phabricator
PHP | 227 lines | 161 code | 40 blank | 26 comment | 21 complexity | 76bd0d07021fce59b62c28729899fe71 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. final class PhabricatorObjectQuery
  3. extends PhabricatorCursorPagedPolicyAwareQuery {
  4. private $phids = array();
  5. private $names = array();
  6. private $types;
  7. private $namedResults;
  8. public function withPHIDs(array $phids) {
  9. $this->phids = $phids;
  10. return $this;
  11. }
  12. public function withNames(array $names) {
  13. $this->names = $names;
  14. return $this;
  15. }
  16. public function withTypes(array $types) {
  17. $this->types = $types;
  18. return $this;
  19. }
  20. protected function loadPage() {
  21. if ($this->namedResults === null) {
  22. $this->namedResults = array();
  23. }
  24. $names = array_unique($this->names);
  25. $phids = $this->phids;
  26. // We allow objects to be named by their PHID in addition to their normal
  27. // name so that, e.g., CLI tools which accept object names can also accept
  28. // PHIDs and work as users expect.
  29. $actually_phids = array();
  30. if ($names) {
  31. foreach ($names as $key => $name) {
  32. if (!strncmp($name, 'PHID-', 5)) {
  33. $actually_phids[] = $name;
  34. $phids[] = $name;
  35. unset($names[$key]);
  36. }
  37. }
  38. }
  39. if ($names) {
  40. $types = PhabricatorPHIDType::getAllTypes();
  41. if ($this->types) {
  42. $types = array_select_keys($types, $this->types);
  43. }
  44. $name_results = $this->loadObjectsByName($types, $names);
  45. } else {
  46. $name_results = array();
  47. }
  48. if ($phids) {
  49. $phids = array_unique($phids);
  50. $phid_types = array();
  51. foreach ($phids as $phid) {
  52. $phid_type = phid_get_type($phid);
  53. $phid_types[$phid_type] = $phid_type;
  54. }
  55. $types = PhabricatorPHIDType::getTypes($phid_types);
  56. if ($this->types) {
  57. $types = array_select_keys($types, $this->types);
  58. }
  59. $phid_results = $this->loadObjectsByPHID($types, $phids);
  60. } else {
  61. $phid_results = array();
  62. }
  63. foreach ($actually_phids as $phid) {
  64. if (isset($phid_results[$phid])) {
  65. $name_results[$phid] = $phid_results[$phid];
  66. }
  67. }
  68. $this->namedResults += $name_results;
  69. return $phid_results + mpull($name_results, null, 'getPHID');
  70. }
  71. public function getNamedResults() {
  72. if ($this->namedResults === null) {
  73. throw new PhutilInvalidStateException('execute');
  74. }
  75. return $this->namedResults;
  76. }
  77. private function loadObjectsByName(array $types, array $names) {
  78. $groups = array();
  79. foreach ($names as $name) {
  80. foreach ($types as $type => $type_impl) {
  81. if (!$type_impl->canLoadNamedObject($name)) {
  82. continue;
  83. }
  84. $groups[$type][] = $name;
  85. break;
  86. }
  87. }
  88. $results = array();
  89. foreach ($groups as $type => $group) {
  90. $results += $types[$type]->loadNamedObjects($this, $group);
  91. }
  92. return $results;
  93. }
  94. private function loadObjectsByPHID(array $types, array $phids) {
  95. $results = array();
  96. $groups = array();
  97. foreach ($phids as $phid) {
  98. $type = phid_get_type($phid);
  99. $groups[$type][] = $phid;
  100. }
  101. $in_flight = $this->getPHIDsInFlight();
  102. foreach ($groups as $type => $group) {
  103. // We check the workspace for each group, because some groups may trigger
  104. // other groups to load (for example, transactions load their objects).
  105. $workspace = $this->getObjectsFromWorkspace($group);
  106. foreach ($group as $key => $phid) {
  107. if (isset($workspace[$phid])) {
  108. $results[$phid] = $workspace[$phid];
  109. unset($group[$key]);
  110. }
  111. }
  112. if (!$group) {
  113. continue;
  114. }
  115. // Don't try to load PHIDs which are already "in flight"; this prevents
  116. // us from recursing indefinitely if policy checks or edges form a loop.
  117. // We will decline to load the corresponding objects.
  118. foreach ($group as $key => $phid) {
  119. if (isset($in_flight[$phid])) {
  120. unset($group[$key]);
  121. }
  122. }
  123. if ($group && isset($types[$type])) {
  124. $this->putPHIDsInFlight($group);
  125. $objects = $types[$type]->loadObjects($this, $group);
  126. $map = mpull($objects, null, 'getPHID');
  127. $this->putObjectsInWorkspace($map);
  128. $results += $map;
  129. }
  130. }
  131. return $results;
  132. }
  133. protected function didFilterResults(array $filtered) {
  134. foreach ($this->namedResults as $name => $result) {
  135. if (isset($filtered[$result->getPHID()])) {
  136. unset($this->namedResults[$name]);
  137. }
  138. }
  139. }
  140. /**
  141. * This query disables policy filtering if the only required capability is
  142. * the view capability.
  143. *
  144. * The view capability is always checked in the subqueries, so we do not need
  145. * to re-filter results. For any other set of required capabilities, we do.
  146. */
  147. protected function shouldDisablePolicyFiltering() {
  148. $view_capability = PhabricatorPolicyCapability::CAN_VIEW;
  149. if ($this->getRequiredCapabilities() === array($view_capability)) {
  150. return true;
  151. }
  152. return false;
  153. }
  154. public function getQueryApplicationClass() {
  155. return null;
  156. }
  157. /**
  158. * Select invalid or restricted PHIDs from a list.
  159. *
  160. * PHIDs are invalid if their objects do not exist or can not be seen by the
  161. * viewer. This method is generally used to validate that PHIDs affected by
  162. * a transaction are valid.
  163. *
  164. * @param PhabricatorUser Viewer.
  165. * @param list<phid> List of ostensibly valid PHIDs.
  166. * @return list<phid> List of invalid or restricted PHIDs.
  167. */
  168. public static function loadInvalidPHIDsForViewer(
  169. PhabricatorUser $viewer,
  170. array $phids) {
  171. if (!$phids) {
  172. return array();
  173. }
  174. $objects = id(new PhabricatorObjectQuery())
  175. ->setViewer($viewer)
  176. ->withPHIDs($phids)
  177. ->execute();
  178. $objects = mpull($objects, null, 'getPHID');
  179. $invalid = array();
  180. foreach ($phids as $phid) {
  181. if (empty($objects[$phid])) {
  182. $invalid[] = $phid;
  183. }
  184. }
  185. return $invalid;
  186. }
  187. }