/src/applications/phid/query/PhabricatorObjectQuery.php
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
- <?php
- final class PhabricatorObjectQuery
- extends PhabricatorCursorPagedPolicyAwareQuery {
- private $phids = array();
- private $names = array();
- private $types;
- private $namedResults;
- public function withPHIDs(array $phids) {
- $this->phids = $phids;
- return $this;
- }
- public function withNames(array $names) {
- $this->names = $names;
- return $this;
- }
- public function withTypes(array $types) {
- $this->types = $types;
- return $this;
- }
- protected function loadPage() {
- if ($this->namedResults === null) {
- $this->namedResults = array();
- }
- $names = array_unique($this->names);
- $phids = $this->phids;
- // We allow objects to be named by their PHID in addition to their normal
- // name so that, e.g., CLI tools which accept object names can also accept
- // PHIDs and work as users expect.
- $actually_phids = array();
- if ($names) {
- foreach ($names as $key => $name) {
- if (!strncmp($name, 'PHID-', 5)) {
- $actually_phids[] = $name;
- $phids[] = $name;
- unset($names[$key]);
- }
- }
- }
- if ($names) {
- $types = PhabricatorPHIDType::getAllTypes();
- if ($this->types) {
- $types = array_select_keys($types, $this->types);
- }
- $name_results = $this->loadObjectsByName($types, $names);
- } else {
- $name_results = array();
- }
- if ($phids) {
- $phids = array_unique($phids);
- $phid_types = array();
- foreach ($phids as $phid) {
- $phid_type = phid_get_type($phid);
- $phid_types[$phid_type] = $phid_type;
- }
- $types = PhabricatorPHIDType::getTypes($phid_types);
- if ($this->types) {
- $types = array_select_keys($types, $this->types);
- }
- $phid_results = $this->loadObjectsByPHID($types, $phids);
- } else {
- $phid_results = array();
- }
- foreach ($actually_phids as $phid) {
- if (isset($phid_results[$phid])) {
- $name_results[$phid] = $phid_results[$phid];
- }
- }
- $this->namedResults += $name_results;
- return $phid_results + mpull($name_results, null, 'getPHID');
- }
- public function getNamedResults() {
- if ($this->namedResults === null) {
- throw new PhutilInvalidStateException('execute');
- }
- return $this->namedResults;
- }
- private function loadObjectsByName(array $types, array $names) {
- $groups = array();
- foreach ($names as $name) {
- foreach ($types as $type => $type_impl) {
- if (!$type_impl->canLoadNamedObject($name)) {
- continue;
- }
- $groups[$type][] = $name;
- break;
- }
- }
- $results = array();
- foreach ($groups as $type => $group) {
- $results += $types[$type]->loadNamedObjects($this, $group);
- }
- return $results;
- }
- private function loadObjectsByPHID(array $types, array $phids) {
- $results = array();
- $groups = array();
- foreach ($phids as $phid) {
- $type = phid_get_type($phid);
- $groups[$type][] = $phid;
- }
- $in_flight = $this->getPHIDsInFlight();
- foreach ($groups as $type => $group) {
- // We check the workspace for each group, because some groups may trigger
- // other groups to load (for example, transactions load their objects).
- $workspace = $this->getObjectsFromWorkspace($group);
- foreach ($group as $key => $phid) {
- if (isset($workspace[$phid])) {
- $results[$phid] = $workspace[$phid];
- unset($group[$key]);
- }
- }
- if (!$group) {
- continue;
- }
- // Don't try to load PHIDs which are already "in flight"; this prevents
- // us from recursing indefinitely if policy checks or edges form a loop.
- // We will decline to load the corresponding objects.
- foreach ($group as $key => $phid) {
- if (isset($in_flight[$phid])) {
- unset($group[$key]);
- }
- }
- if ($group && isset($types[$type])) {
- $this->putPHIDsInFlight($group);
- $objects = $types[$type]->loadObjects($this, $group);
- $map = mpull($objects, null, 'getPHID');
- $this->putObjectsInWorkspace($map);
- $results += $map;
- }
- }
- return $results;
- }
- protected function didFilterResults(array $filtered) {
- foreach ($this->namedResults as $name => $result) {
- if (isset($filtered[$result->getPHID()])) {
- unset($this->namedResults[$name]);
- }
- }
- }
- /**
- * This query disables policy filtering if the only required capability is
- * the view capability.
- *
- * The view capability is always checked in the subqueries, so we do not need
- * to re-filter results. For any other set of required capabilities, we do.
- */
- protected function shouldDisablePolicyFiltering() {
- $view_capability = PhabricatorPolicyCapability::CAN_VIEW;
- if ($this->getRequiredCapabilities() === array($view_capability)) {
- return true;
- }
- return false;
- }
- public function getQueryApplicationClass() {
- return null;
- }
- /**
- * Select invalid or restricted PHIDs from a list.
- *
- * PHIDs are invalid if their objects do not exist or can not be seen by the
- * viewer. This method is generally used to validate that PHIDs affected by
- * a transaction are valid.
- *
- * @param PhabricatorUser Viewer.
- * @param list<phid> List of ostensibly valid PHIDs.
- * @return list<phid> List of invalid or restricted PHIDs.
- */
- public static function loadInvalidPHIDsForViewer(
- PhabricatorUser $viewer,
- array $phids) {
- if (!$phids) {
- return array();
- }
- $objects = id(new PhabricatorObjectQuery())
- ->setViewer($viewer)
- ->withPHIDs($phids)
- ->execute();
- $objects = mpull($objects, null, 'getPHID');
- $invalid = array();
- foreach ($phids as $phid) {
- if (empty($objects[$phid])) {
- $invalid[] = $phid;
- }
- }
- return $invalid;
- }
- }