@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 PhabricatorObjectRelationshipList extends Phobject {
4
5 private $viewer;
6 private $object;
7 private $relationships;
8
9 public function setViewer(PhabricatorUser $viewer) {
10 $this->viewer = $viewer;
11 return $this;
12 }
13
14 public function getViewer() {
15 if ($this->viewer === null) {
16 throw new PhutilInvalidStateException('setViewer');
17 }
18
19 return $this->viewer;
20 }
21
22 public function setObject($object) {
23 $this->object = $object;
24 return $this;
25 }
26
27 public function getObject() {
28 if ($this->object === null) {
29 throw new PhutilInvalidStateException('setObject');
30 }
31
32 return $this->object;
33 }
34
35 /**
36 * @param array<PhabricatorObjectRelationship> $relationships
37 */
38 public function setRelationships(array $relationships) {
39 assert_instances_of($relationships, PhabricatorObjectRelationship::class);
40 $this->relationships = $relationships;
41 return $this;
42 }
43
44 public function getRelationships() {
45 if ($this->relationships === null) {
46 throw new PhutilInvalidStateException('setRelationships');
47 }
48
49 return $this->relationships;
50 }
51
52 public function newActionSubmenu(array $keys) {
53 $object = $this->getObject();
54
55 $actions = array();
56
57 foreach ($keys as $key) {
58 // If we're passed a menu item, just include it verbatim.
59 if ($key instanceof PhabricatorActionView) {
60 $actions[] = $key;
61 continue;
62 }
63
64 $relationship = $this->getRelationship($key);
65 if (!$relationship) {
66 throw new Exception(
67 pht(
68 'No object relationship of type "%s" exists.',
69 $key));
70 }
71
72 $actions[$key] = $relationship->newAction($object);
73 }
74
75 return $this->newMenuWithActions($actions);
76 }
77
78 public function newActionMenu() {
79 $relationships = $this->getRelationships();
80 $object = $this->getObject();
81
82 $actions = array();
83 foreach ($relationships as $key => $relationship) {
84 if (!$relationship->shouldAppearInActionMenu()) {
85 continue;
86 }
87
88 $actions[$key] = $relationship->newAction($object);
89 }
90
91 if (!$actions) {
92 return null;
93 }
94
95 $actions = msort($actions, 'getName');
96
97 return $this->newMenuWithActions($actions)
98 ->setName(pht('Edit Related Objects...'))
99 ->setIcon('fa-link');
100 }
101
102 private function newMenuWithActions(array $actions) {
103 $any_enabled = false;
104 foreach ($actions as $action) {
105 if (!$action->getDisabled()) {
106 $any_enabled = true;
107 break;
108 }
109 }
110
111 return id(new PhabricatorActionView())
112 ->setDisabled(!$any_enabled)
113 ->setSubmenu($actions);
114 }
115
116 public function getRelationship($key) {
117 return idx($this->relationships, $key);
118 }
119
120 public static function newForObject(PhabricatorUser $viewer, $object) {
121 $relationships = PhabricatorObjectRelationship::getAllRelationships();
122
123 $results = array();
124 foreach ($relationships as $key => $relationship) {
125 $relationship = clone $relationship;
126
127 $relationship->setViewer($viewer);
128 if (!$relationship->isEnabledForObject($object)) {
129 continue;
130 }
131
132 $source = $relationship->newSource();
133 if (!$source->isEnabledForObject($object)) {
134 continue;
135 }
136
137 $results[$key] = $relationship;
138 }
139
140 return id(new self())
141 ->setViewer($viewer)
142 ->setObject($object)
143 ->setRelationships($results);
144 }
145
146}