@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 PhabricatorCursorPagedPolicyAwareQuery<PhabricatorSpacesNamespace>
5 */
6final class PhabricatorSpacesNamespaceQuery
7 extends PhabricatorCursorPagedPolicyAwareQuery {
8
9 const KEY_ALL = 'spaces.all';
10 const KEY_DEFAULT = 'spaces.default';
11 const KEY_VIEWER = 'spaces.viewer';
12
13 private $ids;
14 private $phids;
15 private $isDefaultNamespace;
16 private $isArchived;
17
18 public function withIDs(array $ids) {
19 $this->ids = $ids;
20 return $this;
21 }
22
23 public function withPHIDs(array $phids) {
24 $this->phids = $phids;
25 return $this;
26 }
27
28 public function withIsDefaultNamespace($default) {
29 $this->isDefaultNamespace = $default;
30 return $this;
31 }
32
33 public function withIsArchived($archived) {
34 $this->isArchived = $archived;
35 return $this;
36 }
37
38 public function getQueryApplicationClass() {
39 return PhabricatorSpacesApplication::class;
40 }
41
42 public function newResultObject() {
43 return new PhabricatorSpacesNamespace();
44 }
45
46 protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
47 $where = parent::buildWhereClauseParts($conn);
48
49 if ($this->ids !== null) {
50 $where[] = qsprintf(
51 $conn,
52 'id IN (%Ld)',
53 $this->ids);
54 }
55
56 if ($this->phids !== null) {
57 $where[] = qsprintf(
58 $conn,
59 'phid IN (%Ls)',
60 $this->phids);
61 }
62
63 if ($this->isDefaultNamespace !== null) {
64 if ($this->isDefaultNamespace) {
65 $where[] = qsprintf(
66 $conn,
67 'isDefaultNamespace = 1');
68 } else {
69 $where[] = qsprintf(
70 $conn,
71 'isDefaultNamespace IS NULL');
72 }
73 }
74
75 if ($this->isArchived !== null) {
76 $where[] = qsprintf(
77 $conn,
78 'isArchived = %d',
79 (int)$this->isArchived);
80 }
81
82 return $where;
83 }
84
85 public static function destroySpacesCache() {
86 $cache = PhabricatorCaches::getRequestCache();
87 $cache->deleteKeys(
88 array(
89 self::KEY_ALL,
90 self::KEY_DEFAULT,
91 ));
92 }
93
94 public static function getSpacesExist() {
95 return (bool)self::getAllSpaces();
96 }
97
98 public static function getViewerSpacesExist(PhabricatorUser $viewer) {
99 if (!self::getSpacesExist()) {
100 return false;
101 }
102
103 // If the viewer has access to only one space, pretend spaces simply don't
104 // exist.
105 $spaces = self::getViewerSpaces($viewer);
106 return (count($spaces) > 1);
107 }
108
109 public static function getAllSpaces() {
110 $cache = PhabricatorCaches::getRequestCache();
111 $cache_key = self::KEY_ALL;
112
113 $spaces = $cache->getKey($cache_key);
114 if ($spaces === null) {
115 $spaces = id(new PhabricatorSpacesNamespaceQuery())
116 ->setViewer(PhabricatorUser::getOmnipotentUser())
117 ->execute();
118 $spaces = mpull($spaces, null, 'getPHID');
119 $cache->setKey($cache_key, $spaces);
120 }
121
122 return $spaces;
123 }
124
125 public static function getDefaultSpace() {
126 $cache = PhabricatorCaches::getRequestCache();
127 $cache_key = self::KEY_DEFAULT;
128
129 $default_space = $cache->getKey($cache_key, false);
130 if ($default_space === false) {
131 $default_space = null;
132
133 $spaces = self::getAllSpaces();
134 foreach ($spaces as $space) {
135 if ($space->getIsDefaultNamespace()) {
136 $default_space = $space;
137 break;
138 }
139 }
140
141 $cache->setKey($cache_key, $default_space);
142 }
143
144 return $default_space;
145 }
146
147 public static function getViewerSpaces(PhabricatorUser $viewer) {
148 $cache = PhabricatorCaches::getRequestCache();
149 $cache_key = self::KEY_VIEWER.'('.$viewer->getCacheFragment().')';
150
151 $result = $cache->getKey($cache_key);
152 if ($result === null) {
153 $spaces = self::getAllSpaces();
154
155 $result = array();
156 foreach ($spaces as $key => $space) {
157 $can_see = PhabricatorPolicyFilter::hasCapability(
158 $viewer,
159 $space,
160 PhabricatorPolicyCapability::CAN_VIEW);
161 if ($can_see) {
162 $result[$key] = $space;
163 }
164 }
165
166 $cache->setKey($cache_key, $result);
167 }
168
169 return $result;
170 }
171
172
173 public static function getViewerActiveSpaces(PhabricatorUser $viewer) {
174 $spaces = self::getViewerSpaces($viewer);
175
176 foreach ($spaces as $key => $space) {
177 if ($space->getIsArchived()) {
178 unset($spaces[$key]);
179 }
180 }
181
182 return $spaces;
183 }
184
185 public static function getSpaceOptionsForViewer(
186 PhabricatorUser $viewer,
187 $space_phid) {
188
189 $viewer_spaces = self::getViewerSpaces($viewer);
190 $viewer_spaces = msort($viewer_spaces, 'getNamespaceName');
191
192 $map = array();
193 foreach ($viewer_spaces as $space) {
194
195 // Skip archived spaces, unless the object is already in that space.
196 if ($space->getIsArchived()) {
197 if ($space->getPHID() != $space_phid) {
198 continue;
199 }
200 }
201
202 $map[$space->getPHID()] = pht(
203 'Space %s: %s',
204 $space->getMonogram(),
205 $space->getNamespaceName());
206 }
207
208 return $map;
209 }
210
211
212 /**
213 * Get the Space PHID for an object, if one exists.
214 *
215 * This is intended to simplify performing a bunch of redundant checks; you
216 * can intentionally pass any value in (including `null`).
217 *
218 * @param object $object
219 * @return string|null Space PHID of the object, or null.
220 */
221 public static function getObjectSpacePHID($object) {
222 if (!$object) {
223 return null;
224 }
225
226 if (!($object instanceof PhabricatorSpacesInterface)) {
227 return null;
228 }
229
230 $space_phid = $object->getSpacePHID();
231 if ($space_phid === null) {
232 $default_space = self::getDefaultSpace();
233 if ($default_space) {
234 $space_phid = $default_space->getPHID();
235 }
236 }
237
238 return $space_phid;
239 }
240
241}