@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
3abstract class PhabricatorConduitController extends PhabricatorController {
4
5 protected function buildSideNavView() {
6 $viewer = $this->getRequest()->getUser();
7
8 $nav = new AphrontSideNavFilterView();
9 $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
10
11 id(new PhabricatorConduitSearchEngine())
12 ->setViewer($viewer)
13 ->addNavigationItems($nav->getMenu());
14
15 $nav->addLabel('Logs');
16 $nav->addFilter('log', pht('Call Logs'));
17
18 $nav->selectFilter(null);
19
20 return $nav;
21 }
22
23 public function buildApplicationMenu() {
24 return $this->buildSideNavView()->getMenu();
25 }
26
27 protected function renderExampleBox(ConduitAPIMethod $method, $params) {
28 $viewer = $this->getViewer();
29
30 $arc_example = id(new PHUIPropertyListView())
31 ->addRawContent($this->renderExample($method, 'arc', $params));
32
33 $curl_example = id(new PHUIPropertyListView())
34 ->addRawContent($this->renderExample($method, 'curl', $params));
35
36 $php_example = id(new PHUIPropertyListView())
37 ->addRawContent($this->renderExample($method, 'php', $params));
38
39 $panel_uri = id(new PhabricatorConduitTokensSettingsPanel())
40 ->setViewer($viewer)
41 ->setUser($viewer)
42 ->getPanelURI();
43
44 $panel_link = phutil_tag(
45 'a',
46 array(
47 'href' => $panel_uri,
48 ),
49 pht('Conduit API Tokens'));
50
51 $panel_link = phutil_tag('strong', array(), $panel_link);
52
53 $messages = array(
54 pht(
55 'Use the %s panel in Settings to generate or manage API tokens.',
56 $panel_link),
57 );
58
59 if ($params === null) {
60 $messages[] = pht(
61 'If you submit parameters, these examples will update to show '.
62 'exactly how to encode the parameters you submit.');
63 }
64
65 $info_view = id(new PHUIInfoView())
66 ->setErrors($messages)
67 ->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
68
69 $tab_group = id(new PHUITabGroupView())
70 ->addTab(
71 id(new PHUITabView())
72 ->setName(pht('arc call-conduit'))
73 ->setKey('arc')
74 ->appendChild($arc_example))
75 ->addTab(
76 id(new PHUITabView())
77 ->setName(pht('cURL'))
78 ->setKey('curl')
79 ->appendChild($curl_example))
80 ->addTab(
81 id(new PHUITabView())
82 ->setName(pht('PHP'))
83 ->setKey('php')
84 ->appendChild($php_example));
85
86 return id(new PHUIObjectBoxView())
87 ->setHeaderText(pht('Examples'))
88 ->setInfoView($info_view)
89 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
90 ->addTabGroup($tab_group);
91 }
92
93 private function renderExample(
94 ConduitAPIMethod $method,
95 $kind,
96 $params) {
97
98 switch ($kind) {
99 case 'arc':
100 $example = $this->buildArcanistExample($method, $params);
101 break;
102 case 'php':
103 $example = $this->buildPHPExample($method, $params);
104 break;
105 case 'curl':
106 $example = $this->buildCURLExample($method, $params);
107 break;
108 default:
109 throw new Exception(pht('Conduit client "%s" is not known.', $kind));
110 }
111
112 return $example;
113 }
114
115 private function buildArcanistExample(
116 ConduitAPIMethod $method,
117 $params) {
118
119 $parts = array();
120
121 $parts[] = '$ echo ';
122 if ($params === null) {
123 $parts[] = phutil_tag('strong', array(), '<json-parameters>');
124 } else {
125 $params = $this->simplifyParams($params);
126 $params = id(new PhutilJSON())->encodeFormatted($params);
127 $params = trim($params);
128 $params = csprintf('%s', $params);
129 $parts[] = phutil_tag('strong', array('class' => 'real'), $params);
130 }
131
132 $parts[] = ' | ';
133 $parts[] = 'arc call-conduit ';
134
135 $parts[] = '--conduit-uri ';
136 $parts[] = phutil_tag(
137 'strong',
138 array('class' => 'real'),
139 PhabricatorEnv::getURI('/'));
140 $parts[] = ' ';
141
142 $parts[] = '--conduit-token ';
143 $parts[] = phutil_tag('strong', array(), '<conduit-token>');
144 $parts[] = ' ';
145 $parts[] = '--';
146 $parts[] = ' ';
147
148 $parts[] = $method->getAPIMethodName();
149
150 return $this->renderExampleCode($parts);
151 }
152
153 private function buildPHPExample(
154 ConduitAPIMethod $method,
155 $params) {
156
157 $parts = array();
158
159 $libphutil_path = 'path/to/arcanist/support/init/init-script.php';
160
161 $parts[] = '<?php';
162 $parts[] = "\n\n";
163
164 $parts[] = 'require_once ';
165 $parts[] = phutil_var_export($libphutil_path);
166 $parts[] = ";\n\n";
167
168 $parts[] = '$api_token = "';
169 $parts[] = phutil_tag('strong', array(), pht('<api-token>'));
170 $parts[] = "\";\n";
171
172 $parts[] = '$api_parameters = ';
173 if ($params === null) {
174 $parts[] = 'array(';
175 $parts[] = phutil_tag('strong', array(), pht('<parameters>'));
176 $parts[] = ');';
177 } else {
178 $params = $this->simplifyParams($params);
179 $params = phutil_var_export($params);
180 $parts[] = phutil_tag('strong', array('class' => 'real'), $params);
181 $parts[] = ';';
182 }
183 $parts[] = "\n\n";
184
185 $parts[] = '$client = new ConduitClient(';
186 $parts[] = phutil_tag(
187 'strong',
188 array('class' => 'real'),
189 phutil_var_export(PhabricatorEnv::getURI('/')));
190 $parts[] = ");\n";
191
192 $parts[] = '$client->setConduitToken($api_token);';
193 $parts[] = "\n\n";
194
195 $parts[] = '$result = $client->callMethodSynchronous(';
196 $parts[] = phutil_tag(
197 'strong',
198 array('class' => 'real'),
199 phutil_var_export($method->getAPIMethodName()));
200 $parts[] = ', ';
201 $parts[] = '$api_parameters';
202 $parts[] = ");\n";
203
204 $parts[] = 'print_r($result);';
205
206 return $this->renderExampleCode($parts);
207 }
208
209 private function buildCURLExample(
210 ConduitAPIMethod $method,
211 $params) {
212
213 $call_uri = '/api/'.$method->getAPIMethodName();
214
215 $parts = array();
216
217 $linebreak = array('\\', phutil_tag('br'), ' ');
218
219 $parts[] = '$ curl ';
220 $parts[] = phutil_tag(
221 'strong',
222 array('class' => 'real'),
223 csprintf('%R', PhabricatorEnv::getURI($call_uri)));
224 $parts[] = ' ';
225 $parts[] = $linebreak;
226
227 $parts[] = '-d api.token=';
228 $parts[] = phutil_tag('strong', array(), 'api-token');
229 $parts[] = ' ';
230 $parts[] = $linebreak;
231
232 if ($params === null) {
233 $parts[] = '-d ';
234 $parts[] = phutil_tag('strong', array(), 'param');
235 $parts[] = '=';
236 $parts[] = phutil_tag('strong', array(), 'value');
237 $parts[] = ' ';
238 $parts[] = $linebreak;
239 $parts[] = phutil_tag('strong', array(), '...');
240 } else {
241 $lines = array();
242 $params = $this->simplifyParams($params);
243
244 foreach ($params as $key => $value) {
245 $pieces = $this->getQueryStringParts(null, $key, $value);
246 foreach ($pieces as $piece) {
247 $lines[] = array(
248 '-d ',
249 phutil_tag('strong', array('class' => 'real'), $piece),
250 );
251 }
252 }
253
254 $parts[] = phutil_implode_html(array(' ', $linebreak), $lines);
255 }
256
257 return $this->renderExampleCode($parts);
258 }
259
260 private function renderExampleCode($example) {
261 require_celerity_resource('conduit-api-css');
262
263 return phutil_tag(
264 'div',
265 array(
266 'class' => 'PhabricatorMonospaced conduit-api-example-code',
267 ),
268 $example);
269 }
270
271 private function simplifyParams(array $params) {
272 foreach ($params as $key => $value) {
273 if ($value === null) {
274 unset($params[$key]);
275 }
276 }
277 return $params;
278 }
279
280 private function getQueryStringParts($prefix, $key, $value) {
281 if ($prefix === null) {
282 $head = phutil_escape_uri($key);
283 } else {
284 $head = $prefix.'['.phutil_escape_uri($key).']';
285 }
286
287 if (!is_array($value)) {
288 return array(
289 $head.'='.phutil_escape_uri($value),
290 );
291 }
292
293 $results = array();
294 foreach ($value as $subkey => $subvalue) {
295 $subparts = $this->getQueryStringParts($head, $subkey, $subvalue);
296 foreach ($subparts as $subpart) {
297 $results[] = $subpart;
298 }
299 }
300
301 return $results;
302 }
303
304}