@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 * @extends AlmanacQuery<AlmanacService>
5 */
6final class AlmanacServiceQuery
7 extends AlmanacQuery {
8
9 private $ids;
10 private $phids;
11 private $names;
12 private $serviceTypes;
13 private $devicePHIDs;
14 private $namePrefix;
15 private $nameSuffix;
16
17 private $needBindings;
18 private $needActiveBindings;
19
20 public function withIDs(array $ids) {
21 $this->ids = $ids;
22 return $this;
23 }
24
25 public function withPHIDs(array $phids) {
26 $this->phids = $phids;
27 return $this;
28 }
29
30 public function withNames(array $names) {
31 $this->names = $names;
32 return $this;
33 }
34
35 public function withServiceTypes(array $types) {
36 $this->serviceTypes = $types;
37 return $this;
38 }
39
40 public function withDevicePHIDs(array $phids) {
41 $this->devicePHIDs = $phids;
42 return $this;
43 }
44
45 public function withNamePrefix($prefix) {
46 $this->namePrefix = $prefix;
47 return $this;
48 }
49
50 public function withNameSuffix($suffix) {
51 $this->nameSuffix = $suffix;
52 return $this;
53 }
54
55 public function withNameNgrams($ngrams) {
56 return $this->withNgramsConstraint(
57 new AlmanacServiceNameNgrams(),
58 $ngrams);
59 }
60
61 public function needBindings($need_bindings) {
62 $this->needBindings = $need_bindings;
63 return $this;
64 }
65
66 public function needActiveBindings($need_active) {
67 $this->needActiveBindings = $need_active;
68 return $this;
69 }
70
71 public function newResultObject() {
72 return new AlmanacService();
73 }
74
75 protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
76 $joins = parent::buildJoinClauseParts($conn);
77
78 if ($this->shouldJoinBindingTable()) {
79 $joins[] = qsprintf(
80 $conn,
81 'JOIN %T binding ON service.phid = binding.servicePHID',
82 id(new AlmanacBinding())->getTableName());
83 }
84
85 return $joins;
86 }
87
88 protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
89 $where = parent::buildWhereClauseParts($conn);
90
91 if ($this->ids !== null) {
92 $where[] = qsprintf(
93 $conn,
94 'service.id IN (%Ld)',
95 $this->ids);
96 }
97
98 if ($this->phids !== null) {
99 $where[] = qsprintf(
100 $conn,
101 'service.phid IN (%Ls)',
102 $this->phids);
103 }
104
105 if ($this->names !== null) {
106 $hashes = array();
107 foreach ($this->names as $name) {
108 $hashes[] = PhabricatorHash::digestForIndex($name);
109 }
110
111 $where[] = qsprintf(
112 $conn,
113 'service.nameIndex IN (%Ls)',
114 $hashes);
115 }
116
117 if ($this->serviceTypes !== null) {
118 $where[] = qsprintf(
119 $conn,
120 'service.serviceType IN (%Ls)',
121 $this->serviceTypes);
122 }
123
124 if ($this->devicePHIDs !== null) {
125 $where[] = qsprintf(
126 $conn,
127 'binding.devicePHID IN (%Ls)',
128 $this->devicePHIDs);
129 }
130
131 if ($this->namePrefix !== null) {
132 $where[] = qsprintf(
133 $conn,
134 'service.name LIKE %>',
135 $this->namePrefix);
136 }
137
138 if ($this->nameSuffix !== null) {
139 $where[] = qsprintf(
140 $conn,
141 'service.name LIKE %<',
142 $this->nameSuffix);
143 }
144
145 return $where;
146 }
147
148 protected function willFilterPage(array $services) {
149 $service_map = AlmanacServiceType::getAllServiceTypes();
150
151 foreach ($services as $key => $service) {
152 $implementation = idx($service_map, $service->getServiceType());
153
154 if (!$implementation) {
155 $this->didRejectResult($service);
156 unset($services[$key]);
157 continue;
158 }
159
160 $implementation = clone $implementation;
161 $service->attachServiceImplementation($implementation);
162 }
163
164 return $services;
165 }
166
167 protected function didFilterPage(array $services) {
168 $need_all = $this->needBindings;
169 $need_active = $this->needActiveBindings;
170
171 $need_any = ($need_all || $need_active);
172 $only_active = ($need_active && !$need_all);
173
174 if ($need_any) {
175 $service_phids = mpull($services, 'getPHID');
176
177 $bindings_query = id(new AlmanacBindingQuery())
178 ->setViewer($this->getViewer())
179 ->withServicePHIDs($service_phids)
180 ->needProperties($this->getNeedProperties());
181
182 if ($only_active) {
183 $bindings_query->withIsActive(true);
184 }
185
186 $bindings = $bindings_query->execute();
187 $bindings = mgroup($bindings, 'getServicePHID');
188
189 foreach ($services as $service) {
190 $service_bindings = idx($bindings, $service->getPHID(), array());
191
192 if ($only_active) {
193 $service->attachActiveBindings($service_bindings);
194 } else {
195 $service->attachBindings($service_bindings);
196 }
197 }
198 }
199
200 return parent::didFilterPage($services);
201 }
202
203 private function shouldJoinBindingTable() {
204 return ($this->devicePHIDs !== null);
205 }
206
207 protected function shouldGroupQueryResultRows() {
208 if ($this->shouldJoinBindingTable()) {
209 return true;
210 }
211
212 return parent::shouldGroupQueryResultRows();
213 }
214
215 protected function getPrimaryTableAlias() {
216 return 'service';
217 }
218
219 public function getOrderableColumns() {
220 return parent::getOrderableColumns() + array(
221 'name' => array(
222 'table' => $this->getPrimaryTableAlias(),
223 'column' => 'name',
224 'type' => 'string',
225 'unique' => true,
226 'reverse' => true,
227 ),
228 );
229 }
230
231 protected function newPagingMapFromPartialObject($object) {
232 return array(
233 'id' => (int)$object->getID(),
234 'name' => $object->getName(),
235 );
236 }
237
238 public function getBuiltinOrders() {
239 return array(
240 'name' => array(
241 'vector' => array('name'),
242 'name' => pht('Service Name'),
243 ),
244 ) + parent::getBuiltinOrders();
245 }
246
247}