@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
3final class PhabricatorProfileMenuItemConfiguration
4 extends PhabricatorSearchDAO
5 implements
6 PhabricatorPolicyInterface,
7 PhabricatorExtendedPolicyInterface,
8 PhabricatorApplicationTransactionInterface,
9 PhabricatorIndexableInterface {
10
11 protected $profilePHID;
12 protected $menuItemKey;
13 protected $builtinKey;
14 protected $menuItemOrder;
15 protected $visibility;
16 protected $customPHID;
17 protected $menuItemProperties = array();
18
19 private $profileObject = self::ATTACHABLE;
20 private $menuItem = self::ATTACHABLE;
21 private $isHeadItem = false;
22 private $isTailItem = false;
23
24 const VISIBILITY_DEFAULT = 'default';
25 const VISIBILITY_VISIBLE = 'visible';
26 const VISIBILITY_DISABLED = 'disabled';
27
28 public function getTableName() {
29 // For now, this class uses an older table name.
30 return 'search_profilepanelconfiguration';
31 }
32
33 public static function initializeNewBuiltin() {
34 return id(new self())
35 ->setVisibility(self::VISIBILITY_VISIBLE);
36 }
37
38 public static function initializeNewItem(
39 $profile_object,
40 PhabricatorProfileMenuItem $item,
41 $custom_phid) {
42
43 return self::initializeNewBuiltin()
44 ->setProfilePHID($profile_object->getPHID())
45 ->setMenuItemKey($item->getMenuItemKey())
46 ->attachMenuItem($item)
47 ->attachProfileObject($profile_object)
48 ->setCustomPHID($custom_phid);
49 }
50
51 protected function getConfiguration() {
52 return array(
53 self::CONFIG_AUX_PHID => true,
54 self::CONFIG_SERIALIZATION => array(
55 'menuItemProperties' => self::SERIALIZATION_JSON,
56 ),
57 self::CONFIG_COLUMN_SCHEMA => array(
58 'menuItemKey' => 'text64',
59 'builtinKey' => 'text64?',
60 'menuItemOrder' => 'uint32?',
61 'customPHID' => 'phid?',
62 'visibility' => 'text32',
63 ),
64 self::CONFIG_KEY_SCHEMA => array(
65 'key_profile' => array(
66 'columns' => array('profilePHID', 'menuItemOrder'),
67 ),
68 ),
69 ) + parent::getConfiguration();
70 }
71
72 public function generatePHID() {
73 return PhabricatorPHID::generateNewPHID(
74 PhabricatorProfileMenuItemPHIDType::TYPECONST);
75 }
76
77 public function attachMenuItem(PhabricatorProfileMenuItem $item) {
78 $this->menuItem = $item;
79 return $this;
80 }
81
82 public function getMenuItem() {
83 return $this->assertAttached($this->menuItem);
84 }
85
86 public function attachProfileObject($profile_object) {
87 $this->profileObject = $profile_object;
88 return $this;
89 }
90
91 public function getProfileObject() {
92 return $this->assertAttached($this->profileObject);
93 }
94
95 public function setMenuItemProperty($key, $value) {
96 $this->menuItemProperties[$key] = $value;
97 return $this;
98 }
99
100 public function getMenuItemProperty($key, $default = null) {
101 return idx($this->menuItemProperties, $key, $default);
102 }
103
104 public function getMenuItemTypeName() {
105 return $this->getMenuItem()->getMenuItemTypeName();
106 }
107
108 public function getDisplayName() {
109 return $this->getMenuItem()->getDisplayName($this);
110 }
111
112 public function canMakeDefault() {
113 return $this->getMenuItem()->canMakeDefault($this);
114 }
115
116 public function canHideMenuItem() {
117 return $this->getMenuItem()->canHideMenuItem($this);
118 }
119
120 public function shouldEnableForObject($object) {
121 return $this->getMenuItem()->shouldEnableForObject($object);
122 }
123
124 public function willGetMenuItemViewList(array $items) {
125 return $this->getMenuItem()->willGetMenuItemViewList($items);
126 }
127
128 public function getMenuItemViewList() {
129 return $this->getMenuItem()->getMenuItemViewList($this);
130 }
131
132 public function validateTransactions(array $map) {
133 $item = $this->getMenuItem();
134
135 $fields = $item->buildEditEngineFields($this);
136 $errors = array();
137 foreach ($fields as $field) {
138 $field_key = $field->getKey();
139
140 $xactions = idx($map, $field_key, array());
141 $value = $this->getMenuItemProperty($field_key);
142
143 $field_errors = $item->validateTransactions(
144 $this,
145 $field_key,
146 $value,
147 $xactions);
148 foreach ($field_errors as $error) {
149 $errors[] = $error;
150 }
151 }
152
153 return $errors;
154 }
155
156 public function getSortVector() {
157 // Sort custom items above global items.
158 if ($this->getCustomPHID()) {
159 $is_global = 0;
160 } else {
161 $is_global = 1;
162 }
163
164 // Sort "head" items above other items and "tail" items after other items.
165 if ($this->getIsHeadItem()) {
166 $force_position = 0;
167 } else if ($this->getIsTailItem()) {
168 $force_position = 2;
169 } else {
170 $force_position = 1;
171 }
172
173 // Sort items with an explicit order above items without an explicit order,
174 // so any newly created builtins go to the bottom.
175 $order = $this->getMenuItemOrder();
176 if ($order !== null) {
177 $has_order = 0;
178 } else {
179 $has_order = 1;
180 }
181
182 return id(new PhutilSortVector())
183 ->addInt($is_global)
184 ->addInt($force_position)
185 ->addInt($has_order)
186 ->addInt((int)$order)
187 ->addInt((int)$this->getID());
188 }
189
190 public function isDisabled() {
191 if (!$this->canHideMenuItem()) {
192 return false;
193 }
194 return ($this->getVisibility() === self::VISIBILITY_DISABLED);
195 }
196
197 public function isDefault() {
198 return ($this->getVisibility() === self::VISIBILITY_DEFAULT);
199 }
200
201 /**
202 * @return int|string
203 */
204 public function getItemIdentifier() {
205 $id = $this->getID();
206
207 if ($id) {
208 return (int)$id;
209 }
210
211 return $this->getBuiltinKey();
212 }
213
214 /**
215 * @return string
216 */
217 public function getDefaultMenuItemKey() {
218 if ($this->getBuiltinKey()) {
219 return $this->getBuiltinKey();
220 }
221
222 return $this->getPHID();
223 }
224
225 public function newPageContent() {
226 return $this->getMenuItem()->newPageContent($this);
227 }
228
229 public function setIsHeadItem($is_head_item) {
230 $this->isHeadItem = $is_head_item;
231 return $this;
232 }
233
234 public function getIsHeadItem() {
235 return $this->isHeadItem;
236 }
237
238 public function setIsTailItem($is_tail_item) {
239 $this->isTailItem = $is_tail_item;
240 return $this;
241 }
242
243 public function getIsTailItem() {
244 return $this->isTailItem;
245 }
246
247 public function matchesIdentifier($identifier) {
248 if (!strlen($identifier)) {
249 return false;
250 }
251
252 if (ctype_digit($identifier)) {
253 if ((int)$this->getID() === (int)$identifier) {
254 return true;
255 }
256 }
257
258 if ((string)$this->getBuiltinKey() === (string)$identifier) {
259 return true;
260 }
261
262 return false;
263 }
264
265 public function getAffectedObjectPHIDs() {
266 return $this->getMenuItem()->getAffectedObjectPHIDs($this);
267 }
268
269 public function getProfileMenuTypeDescription() {
270 $profile_phid = $this->getProfilePHID();
271
272 $home_phid = id(new PhabricatorHomeApplication())->getPHID();
273 if ($profile_phid === $home_phid) {
274 return pht('Home Menu');
275 }
276
277 $favorites_phid = id(new PhabricatorFavoritesApplication())->getPHID();
278 if ($profile_phid === $favorites_phid) {
279 return pht('Favorites Menu');
280 }
281
282 switch (phid_get_type($profile_phid)) {
283 case PhabricatorProjectProjectPHIDType::TYPECONST:
284 return pht('Project Menu');
285 case PhabricatorDashboardPortalPHIDType::TYPECONST:
286 return pht('Portal Menu');
287 }
288
289 return pht('Profile Menu');
290 }
291
292 public function newUsageSortVector() {
293 // Used to sort items in contexts where we're showing the usage of an
294 // object in menus, like "Dashboard Used By" on Dashboard pages.
295
296 // Sort usage as a custom item after usage as a global item.
297 if ($this->getCustomPHID()) {
298 $is_personal = 1;
299 } else {
300 $is_personal = 0;
301 }
302
303 return id(new PhutilSortVector())
304 ->addInt($is_personal)
305 ->addInt($this->getID());
306 }
307
308
309/* -( PhabricatorPolicyInterface )----------------------------------------- */
310
311
312 public function getCapabilities() {
313 return array(
314 PhabricatorPolicyCapability::CAN_VIEW,
315 PhabricatorPolicyCapability::CAN_EDIT,
316 );
317 }
318
319
320 public function getPolicy($capability) {
321 return PhabricatorPolicies::getMostOpenPolicy();
322 }
323
324
325 public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
326 return $this->getProfileObject()->hasAutomaticCapability(
327 $capability,
328 $viewer);
329 }
330
331
332/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
333
334
335 public function getExtendedPolicy($capability, PhabricatorUser $viewer) {
336 // If this is an item with a custom PHID (like a personal menu item),
337 // we only require that the user can edit the corresponding custom
338 // object (usually their own user profile), not the object that the
339 // menu appears on (which may be an Application like Favorites or Home).
340 if ($capability == PhabricatorPolicyCapability::CAN_EDIT) {
341 if ($this->getCustomPHID()) {
342 return array(
343 array(
344 $this->getCustomPHID(),
345 $capability,
346 ),
347 );
348 }
349 }
350
351 return array(
352 array(
353 $this->getProfileObject(),
354 $capability,
355 ),
356 );
357 }
358
359
360/* -( PhabricatorApplicationTransactionInterface )------------------------- */
361
362
363 public function getApplicationTransactionEditor() {
364 return new PhabricatorProfileMenuEditor();
365 }
366
367 public function getApplicationTransactionTemplate() {
368 return new PhabricatorProfileMenuItemConfigurationTransaction();
369 }
370
371}