@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3/**
4 * Structural class representing a column ordering for a query.
5 *
6 * Queries often order results on multiple columns. For example, projects might
7 * be ordered by "name, id". This class wraps a list of column orderings and
8 * makes them easier to manage.
9 *
10 * To construct an order vector, use @{method:newFromVector}:
11 *
12 * $vector = PhabricatorQueryOrderVector::newFromVector(array('name', 'id'));
13 *
14 * You can iterate over an order vector normally:
15 *
16 * foreach ($vector as $item) {
17 * // ...
18 * }
19 *
20 * The items are objects of class @{class:PhabricatorQueryOrderItem}.
21 *
22 * This class is primarily internal to the query infrastructure, and most
23 * application code should not need to interact with it directly.
24 */
25final class PhabricatorQueryOrderVector
26 extends Phobject
27 implements Iterator {
28
29 private $items;
30 private $keys;
31 private $cursor;
32
33 private function __construct() {
34 // <private>
35 }
36
37 public static function newFromVector($vector) {
38 if ($vector instanceof PhabricatorQueryOrderVector) {
39 return (clone $vector);
40 }
41
42 if (!is_array($vector)) {
43 throw new Exception(
44 pht(
45 'An order vector can only be constructed from a list of strings or '.
46 'another order vector.'));
47 }
48
49 if (!$vector) {
50 throw new Exception(
51 pht(
52 'An order vector must not be empty.'));
53 }
54
55 $items = array();
56 foreach ($vector as $key => $scalar) {
57 if (!is_string($scalar)) {
58 throw new Exception(
59 pht(
60 'Value with key "%s" in order vector is not a string (it has '.
61 'type "%s"). An order vector must contain only strings.',
62 $key,
63 gettype($scalar)));
64 }
65
66 $item = PhabricatorQueryOrderItem::newFromScalar($scalar);
67
68 // Orderings like "id, id, id" or "id, -id" are meaningless and invalid.
69 if (isset($items[$item->getOrderKey()])) {
70 throw new Exception(
71 pht(
72 'Order vector "%s" specifies order "%s" twice. Each component '.
73 'of an ordering must be unique.',
74 implode(', ', $vector),
75 $item->getOrderKey()));
76 }
77
78 $items[$item->getOrderKey()] = $item;
79 }
80
81 $obj = new PhabricatorQueryOrderVector();
82 $obj->items = $items;
83 $obj->keys = array_keys($items);
84 return $obj;
85 }
86
87 public function appendVector($vector) {
88 $vector = self::newFromVector($vector);
89
90 // When combining vectors (like "group by" and "order by" vectors), there
91 // may be redundant columns. We only want to append unique columns which
92 // aren't already present in the vector.
93 foreach ($vector->items as $key => $item) {
94 if (empty($this->items[$key])) {
95 $this->items[$key] = $item;
96 $this->keys[] = $key;
97 }
98 }
99
100 return $this;
101 }
102
103 public function getAsString() {
104 $scalars = array();
105 foreach ($this->items as $item) {
106 $scalars[] = $item->getAsScalar();
107 }
108 return implode(', ', $scalars);
109 }
110
111 public function containsKey($key) {
112 return isset($this->items[$key]);
113 }
114
115
116/* -( Iterator Interface )------------------------------------------------- */
117
118
119 public function rewind() {
120 $this->cursor = 0;
121 }
122
123
124 public function current() {
125 return $this->items[$this->key()];
126 }
127
128
129 public function key() {
130 return $this->keys[$this->cursor];
131 }
132
133
134 public function next() {
135 ++$this->cursor;
136 }
137
138
139 public function valid() {
140 return isset($this->keys[$this->cursor]);
141 }
142
143}