Differential D12526 Diff 30086 src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php
Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php
| Show All 16 Lines | abstract class PhabricatorCursorPagedPolicyAwareQuery | ||||
| private $afterID; | private $afterID; | ||||
| private $beforeID; | private $beforeID; | ||||
| private $applicationSearchConstraints = array(); | private $applicationSearchConstraints = array(); | ||||
| protected $applicationSearchOrders = array(); | protected $applicationSearchOrders = array(); | ||||
| private $internalPaging; | private $internalPaging; | ||||
| private $orderVector; | private $orderVector; | ||||
| private $builtinOrder; | private $builtinOrder; | ||||
| private $edgeLogicConstraints = array(); | private $edgeLogicConstraints = array(); | ||||
| private $edgeLogicConstraintsAreValid = false; | |||||
| protected function getPageCursors(array $page) { | protected function getPageCursors(array $page) { | ||||
| return array( | return array( | ||||
| $this->getResultCursor(head($page)), | $this->getResultCursor(head($page)), | ||||
| $this->getResultCursor(last($page)), | $this->getResultCursor(last($page)), | ||||
| ); | ); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 1,223 Lines • ▼ Show 20 Lines | protected function isCustomFieldOrderKey($key) { | ||||
| return !strncmp($key, $prefix, strlen($prefix)); | return !strncmp($key, $prefix, strlen($prefix)); | ||||
| } | } | ||||
| /* -( Edge Logic )--------------------------------------------------------- */ | /* -( Edge Logic )--------------------------------------------------------- */ | ||||
| /** | /** | ||||
| * Convenience method for specifying edge logic constraints with a list of | |||||
| * PHIDs. | |||||
| * | |||||
| * @param const Edge constant. | |||||
| * @param const Constraint operator. | |||||
| * @param list<phid> List of PHIDs. | |||||
| * @return this | |||||
| * @task edgelogic | |||||
| */ | |||||
| public function withEdgeLogicPHIDs($edge_type, $operator, array $phids) { | |||||
| $constraints = array(); | |||||
| foreach ($phids as $phid) { | |||||
| $constraints[] = new PhabricatorQueryConstraint($operator, $phid); | |||||
| } | |||||
| return $this->withEdgeLogicConstraints($edge_type, $constraints); | |||||
| } | |||||
| /** | |||||
| * @task edgelogic | * @task edgelogic | ||||
| */ | */ | ||||
| public function withEdgeLogicConstraints($edge_type, array $constraints) { | public function withEdgeLogicConstraints($edge_type, array $constraints) { | ||||
| assert_instances_of($constraints, 'PhabricatorQueryConstraint'); | assert_instances_of($constraints, 'PhabricatorQueryConstraint'); | ||||
| $constraints = mgroup($constraints, 'getOperator'); | $constraints = mgroup($constraints, 'getOperator'); | ||||
| foreach ($constraints as $operator => $list) { | foreach ($constraints as $operator => $list) { | ||||
| foreach ($list as $item) { | foreach ($list as $item) { | ||||
| $value = $item->getValue(); | $value = $item->getValue(); | ||||
| $this->edgeLogicConstraints[$edge_type][$operator][$value] = $item; | $this->edgeLogicConstraints[$edge_type][$operator][$value] = $item; | ||||
| } | } | ||||
| } | } | ||||
| $this->edgeLogicConstraintsAreValid = false; | |||||
| return $this; | return $this; | ||||
| } | } | ||||
| /** | /** | ||||
| * @task edgelogic | * @task edgelogic | ||||
| */ | */ | ||||
| public function buildEdgeLogicSelectClause(AphrontDatabaseConnection $conn) { | public function buildEdgeLogicSelectClause(AphrontDatabaseConnection $conn) { | ||||
| $select = array(); | $select = array(); | ||||
| $this->validateEdgeLogicConstraints(); | |||||
| foreach ($this->edgeLogicConstraints as $type => $constraints) { | foreach ($this->edgeLogicConstraints as $type => $constraints) { | ||||
| foreach ($constraints as $operator => $list) { | foreach ($constraints as $operator => $list) { | ||||
| $alias = $this->getEdgeLogicTableAlias($operator, $type); | $alias = $this->getEdgeLogicTableAlias($operator, $type); | ||||
| switch ($operator) { | switch ($operator) { | ||||
| case PhabricatorQueryConstraint::OPERATOR_AND: | case PhabricatorQueryConstraint::OPERATOR_AND: | ||||
| if (count($list) > 1) { | if (count($list) > 1) { | ||||
| $select[] = qsprintf( | $select[] = qsprintf( | ||||
| $conn, | $conn, | ||||
| ▲ Show 20 Lines • Show All 208 Lines • ▼ Show 20 Lines | /* -( Edge Logic )--------------------------------------------------------- */ | ||||
| /** | /** | ||||
| * @task edgelogic | * @task edgelogic | ||||
| */ | */ | ||||
| private function buildEdgeLogicTableAliasCount($alias) { | private function buildEdgeLogicTableAliasCount($alias) { | ||||
| return $alias.'_count'; | return $alias.'_count'; | ||||
| } | } | ||||
| /** | |||||
| * Select certain edge logic constraint values. | |||||
| * | |||||
| * @task edgelogic | |||||
| */ | |||||
| protected function getEdgeLogicValues( | |||||
| array $edge_types, | |||||
| array $operators) { | |||||
| $values = array(); | |||||
| $constraint_lists = $this->edgeLogicConstraints; | |||||
| if ($edge_types) { | |||||
| $constraint_lists = array_select_keys($constraint_lists, $edge_types); | |||||
| } | |||||
| foreach ($constraint_lists as $type => $constraints) { | |||||
| if ($operators) { | |||||
| $constraints = array_select_keys($constraints, $operators); | |||||
| } | |||||
| foreach ($constraints as $operator => $list) { | |||||
| foreach ($list as $constraint) { | |||||
| $values[] = $constraint->getValue(); | |||||
| } | |||||
| } | |||||
| } | |||||
| return $values; | |||||
| } | |||||
| /** | |||||
| * Validate edge logic constraints for the query. | |||||
| * | |||||
| * @return this | |||||
| * @task edgelogic | |||||
| */ | |||||
| private function validateEdgeLogicConstraints() { | |||||
| if ($this->edgeLogicConstraintsAreValid) { | |||||
| return $this; | |||||
| } | |||||
| // This should probably be more modular, eventually, but we only do | |||||
| // project-based edge logic today. | |||||
| $project_phids = $this->getEdgeLogicValues( | |||||
| array( | |||||
| PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, | |||||
| ), | |||||
| array( | |||||
| PhabricatorQueryConstraint::OPERATOR_AND, | |||||
| PhabricatorQueryConstraint::OPERATOR_OR, | |||||
| PhabricatorQueryConstraint::OPERATOR_NOT, | |||||
| )); | |||||
| if ($project_phids) { | |||||
| $projects = id(new PhabricatorProjectQuery()) | |||||
| ->setViewer($this->getViewer()) | |||||
| ->setParentQuery($this) | |||||
| ->withPHIDs($project_phids) | |||||
| ->execute(); | |||||
| $projects = mpull($projects, null, 'getPHID'); | |||||
| foreach ($project_phids as $phid) { | |||||
| if (empty($projects[$phid])) { | |||||
| throw new PhabricatorEmptyQueryException( | |||||
| pht( | |||||
| 'This query is constrained by a project you do not have '. | |||||
| 'permission to see.')); | |||||
| } | |||||
| } | |||||
| } | |||||
| $this->edgeLogicConstraintsAreValid = true; | |||||
| return $this; | |||||
| } | |||||
| } | } | ||||