Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / applications / phid / PhabricatorObjectHandle.php
blob577fd056922f5e1e3584a31d2916c043c5a288fd
1 <?php
3 final class PhabricatorObjectHandle
4 extends Phobject
5 implements PhabricatorPolicyInterface {
7 const AVAILABILITY_FULL = 'full';
8 const AVAILABILITY_NONE = 'none';
9 const AVAILABILITY_NOEMAIL = 'no-email';
10 const AVAILABILITY_PARTIAL = 'partial';
11 const AVAILABILITY_DISABLED = 'disabled';
13 const STATUS_OPEN = 'open';
14 const STATUS_CLOSED = 'closed';
16 private $uri;
17 private $phid;
18 private $type;
19 private $name;
20 private $fullName;
21 private $title;
22 private $imageURI;
23 private $icon;
24 private $tagColor;
25 private $timestamp;
26 private $status = self::STATUS_OPEN;
27 private $availability = self::AVAILABILITY_FULL;
28 private $complete;
29 private $objectName;
30 private $policyFiltered;
31 private $subtitle;
32 private $tokenIcon;
33 private $commandLineObjectName;
34 private $mailStampName;
35 private $capabilities = array();
37 public function setIcon($icon) {
38 $this->icon = $icon;
39 return $this;
42 public function getIcon() {
43 if ($this->getPolicyFiltered()) {
44 return 'fa-lock';
47 if ($this->icon) {
48 return $this->icon;
50 return $this->getTypeIcon();
53 public function setSubtitle($subtitle) {
54 $this->subtitle = $subtitle;
55 return $this;
58 public function getSubtitle() {
59 return $this->subtitle;
62 public function setTagColor($color) {
63 static $colors;
64 if (!$colors) {
65 $colors = array_fuse(array_keys(PHUITagView::getShadeMap()));
68 if (isset($colors[$color])) {
69 $this->tagColor = $color;
72 return $this;
75 public function getTagColor() {
76 if ($this->getPolicyFiltered()) {
77 return 'disabled';
80 if ($this->tagColor) {
81 return $this->tagColor;
84 return 'blue';
87 public function getIconColor() {
88 if ($this->tagColor) {
89 return $this->tagColor;
91 return null;
94 public function setTokenIcon($icon) {
95 $this->tokenIcon = $icon;
96 return $this;
99 public function getTokenIcon() {
100 if ($this->tokenIcon !== null) {
101 return $this->tokenIcon;
104 return $this->getIcon();
107 public function getTypeIcon() {
108 if ($this->getPHIDType()) {
109 return $this->getPHIDType()->getTypeIcon();
111 return null;
114 public function setPolicyFiltered($policy_filered) {
115 $this->policyFiltered = $policy_filered;
116 return $this;
119 public function getPolicyFiltered() {
120 return $this->policyFiltered;
123 public function setObjectName($object_name) {
124 $this->objectName = $object_name;
125 return $this;
128 public function getObjectName() {
129 if (!$this->objectName) {
130 return $this->getName();
132 return $this->objectName;
135 public function setMailStampName($mail_stamp_name) {
136 $this->mailStampName = $mail_stamp_name;
137 return $this;
140 public function getMailStampName() {
141 return $this->mailStampName;
144 public function setURI($uri) {
145 $this->uri = $uri;
146 return $this;
149 public function getURI() {
150 return $this->uri;
153 public function setPHID($phid) {
154 $this->phid = $phid;
155 return $this;
158 public function getPHID() {
159 return $this->phid;
162 public function setName($name) {
163 $this->name = $name;
164 return $this;
167 public function getName() {
168 if ($this->name === null) {
169 if ($this->getPolicyFiltered()) {
170 return pht('Restricted %s', $this->getTypeName());
171 } else {
172 return pht('Unknown Object (%s)', $this->getTypeName());
175 return $this->name;
178 public function setAvailability($availability) {
179 $this->availability = $availability;
180 return $this;
183 public function getAvailability() {
184 return $this->availability;
187 public function isDisabled() {
188 return ($this->getAvailability() == self::AVAILABILITY_DISABLED);
191 public function setStatus($status) {
192 $this->status = $status;
193 return $this;
196 public function getStatus() {
197 return $this->status;
200 public function isClosed() {
201 return ($this->status === self::STATUS_CLOSED);
204 public function setFullName($full_name) {
205 $this->fullName = $full_name;
206 return $this;
209 public function getFullName() {
210 if ($this->fullName !== null) {
211 return $this->fullName;
213 return $this->getName();
216 public function setCommandLineObjectName($command_line_object_name) {
217 $this->commandLineObjectName = $command_line_object_name;
218 return $this;
221 public function getCommandLineObjectName() {
222 if ($this->commandLineObjectName !== null) {
223 return $this->commandLineObjectName;
226 return $this->getObjectName();
229 public function setTitle($title) {
230 $this->title = $title;
231 return $this;
234 public function getTitle() {
235 return $this->title;
238 public function setType($type) {
239 $this->type = $type;
240 return $this;
243 public function getType() {
244 return $this->type;
247 public function setImageURI($uri) {
248 $this->imageURI = $uri;
249 return $this;
252 public function getImageURI() {
253 return $this->imageURI;
256 public function setTimestamp($timestamp) {
257 $this->timestamp = $timestamp;
258 return $this;
261 public function getTimestamp() {
262 return $this->timestamp;
265 public function getTypeName() {
266 if ($this->getPHIDType()) {
267 return $this->getPHIDType()->getTypeName();
270 return $this->getType();
275 * Set whether or not the underlying object is complete. See
276 * @{method:isComplete} for an explanation of what it means to be complete.
278 * @param bool True if the handle represents a complete object.
279 * @return this
281 public function setComplete($complete) {
282 $this->complete = $complete;
283 return $this;
288 * Determine if the handle represents an object which was completely loaded
289 * (i.e., the underlying object exists) vs an object which could not be
290 * completely loaded (e.g., the type or data for the PHID could not be
291 * identified or located).
293 * Basically, @{class:PhabricatorHandleQuery} gives you back a handle for
294 * any PHID you give it, but it gives you a complete handle only for valid
295 * PHIDs.
297 * @return bool True if the handle represents a complete object.
299 public function isComplete() {
300 return $this->complete;
303 public function renderLink($name = null) {
304 return $this->renderLinkWithAttributes($name, array());
307 public function renderHovercardLink($name = null, $context_phid = null) {
308 Javelin::initBehavior('phui-hovercards');
310 $hovercard_spec = array(
311 'objectPHID' => $this->getPHID(),
314 if ($context_phid) {
315 $hovercard_spec['contextPHID'] = $context_phid;
318 $attributes = array(
319 'sigil' => 'hovercard',
320 'meta' => array(
321 'hovercardSpec' => $hovercard_spec,
325 return $this->renderLinkWithAttributes($name, $attributes);
328 private function renderLinkWithAttributes($name, array $attributes) {
329 if ($name === null) {
330 $name = $this->getLinkName();
332 $classes = array();
333 $classes[] = 'phui-handle';
334 $title = $this->title;
336 if ($this->status != self::STATUS_OPEN) {
337 $classes[] = 'handle-status-'.$this->status;
340 $circle = null;
341 if ($this->availability != self::AVAILABILITY_FULL) {
342 $classes[] = 'handle-availability-'.$this->availability;
343 $circle = array(
344 phutil_tag(
345 'span',
346 array(
347 'class' => 'perfect-circle',
349 "\xE2\x80\xA2"),
350 ' ',
354 if ($this->getType() == PhabricatorPeopleUserPHIDType::TYPECONST) {
355 $classes[] = 'phui-link-person';
358 $uri = $this->getURI();
360 $icon = null;
361 if ($this->getPolicyFiltered()) {
362 $icon = id(new PHUIIconView())
363 ->setIcon('fa-lock lightgreytext');
366 $attributes = $attributes + array(
367 'href' => $uri,
368 'class' => implode(' ', $classes),
369 'title' => $title,
372 return javelin_tag(
373 $uri ? 'a' : 'span',
374 $attributes,
375 array($circle, $icon, $name));
378 public function renderTag() {
379 return id(new PHUITagView())
380 ->setType(PHUITagView::TYPE_SHADE)
381 ->setColor($this->getTagColor())
382 ->setIcon($this->getIcon())
383 ->setHref($this->getURI())
384 ->setName($this->getLinkName());
387 public function getLinkName() {
388 switch ($this->getType()) {
389 case PhabricatorPeopleUserPHIDType::TYPECONST:
390 $name = $this->getName();
391 break;
392 default:
393 $name = $this->getFullName();
394 break;
396 return $name;
399 protected function getPHIDType() {
400 $types = PhabricatorPHIDType::getAllTypes();
401 return idx($types, $this->getType());
404 public function hasCapabilities() {
405 if (!$this->isComplete()) {
406 return false;
409 return ($this->getType() === PhabricatorPeopleUserPHIDType::TYPECONST);
412 public function attachCapability(
413 PhabricatorPolicyInterface $object,
414 $capability,
415 $has_capability) {
417 if (!$this->hasCapabilities()) {
418 throw new Exception(
419 pht(
420 'Attempting to attach capability ("%s") for object ("%s") to '.
421 'handle, but this handle (of type "%s") can not have '.
422 'capabilities.',
423 $capability,
424 get_class($object),
425 $this->getType()));
428 $object_key = $this->getObjectCapabilityKey($object);
429 $this->capabilities[$object_key][$capability] = $has_capability;
431 return $this;
434 public function hasViewCapability(PhabricatorPolicyInterface $object) {
435 return $this->hasCapability($object, PhabricatorPolicyCapability::CAN_VIEW);
438 private function hasCapability(
439 PhabricatorPolicyInterface $object,
440 $capability) {
442 $object_key = $this->getObjectCapabilityKey($object);
444 if (!isset($this->capabilities[$object_key][$capability])) {
445 throw new Exception(
446 pht(
447 'Attempting to test capability "%s" for handle of type "%s", but '.
448 'this capability has not been attached.',
449 $capability,
450 $this->getType()));
453 return $this->capabilities[$object_key][$capability];
456 private function getObjectCapabilityKey(PhabricatorPolicyInterface $object) {
457 $object_phid = $object->getPHID();
459 if (!$object_phid) {
460 throw new Exception(
461 pht(
462 'Object (of class "%s") has no PHID, so handles can not interact '.
463 'with capabilities for it.',
464 get_class($object)));
467 return $object_phid;
471 /* -( PhabricatorPolicyInterface )----------------------------------------- */
474 public function getCapabilities() {
475 return array(
476 PhabricatorPolicyCapability::CAN_VIEW,
480 public function getPolicy($capability) {
481 return PhabricatorPolicies::POLICY_PUBLIC;
484 public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
485 // NOTE: Handles are always visible, they just don't get populated with
486 // data if the user can't see the underlying object.
487 return true;
490 public function describeAutomaticCapability($capability) {
491 return null;