@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 PhabricatorInlineComment
4 extends Phobject
5 implements
6 PhabricatorMarkupInterface {
7
8 const MARKUP_FIELD_BODY = 'markup:body';
9
10 const STATE_UNDONE = 'undone';
11 const STATE_DRAFT = 'draft';
12 const STATE_UNDRAFT = 'undraft';
13 const STATE_DONE = 'done';
14
15 private $storageObject;
16 private $syntheticAuthor;
17 private $isGhost;
18 private $versionedDrafts = array();
19
20 public function __clone() {
21 $this->storageObject = clone $this->storageObject;
22 }
23
24 final public static function loadAndAttachVersionedDrafts(
25 PhabricatorUser $viewer,
26 array $inlines) {
27
28 $viewer_phid = $viewer->getPHID();
29 if (!$viewer_phid) {
30 return;
31 }
32
33 $inlines = mpull($inlines, null, 'getPHID');
34
35 $load = array();
36 foreach ($inlines as $key => $inline) {
37 if (!$inline->getIsEditing()) {
38 continue;
39 }
40
41 if ($inline->getAuthorPHID() !== $viewer_phid) {
42 continue;
43 }
44
45 $load[$key] = $inline;
46 }
47
48 if (!$load) {
49 return;
50 }
51
52 $drafts = PhabricatorVersionedDraft::loadDrafts(
53 array_keys($load),
54 $viewer_phid);
55
56 $drafts = mpull($drafts, null, 'getObjectPHID');
57 foreach ($inlines as $inline) {
58 $draft = idx($drafts, $inline->getPHID());
59 $inline->attachVersionedDraftForViewer($viewer, $draft);
60 }
61 }
62
63 public function setSyntheticAuthor($synthetic_author) {
64 $this->syntheticAuthor = $synthetic_author;
65 return $this;
66 }
67
68 public function getSyntheticAuthor() {
69 return $this->syntheticAuthor;
70 }
71
72 public function setStorageObject($storage_object) {
73 $this->storageObject = $storage_object;
74 return $this;
75 }
76
77 public function getStorageObject() {
78 if (!$this->storageObject) {
79 $this->storageObject = $this->newStorageObject();
80 }
81
82 return $this->storageObject;
83 }
84
85 public function getInlineCommentCacheFragment() {
86 $phid = $this->getPHID();
87
88 if ($phid === null) {
89 return null;
90 }
91
92 return sprintf('inline(%s)', $phid);
93 }
94
95 abstract protected function newStorageObject();
96 abstract public function getControllerURI();
97
98 abstract public function setChangesetID($id);
99 abstract public function getChangesetID();
100
101 abstract public function supportsHiding();
102 abstract public function isHidden();
103
104 /**
105 * @return Phobject
106 */
107 abstract public function getTransactionCommentForSave();
108
109 public function isDraft() {
110 return !$this->getTransactionPHID();
111 }
112
113 public function getTransactionPHID() {
114 return $this->getStorageObject()->getTransactionPHID();
115 }
116
117 public function isCompatible(PhabricatorInlineComment $comment) {
118 return
119 ($this->getAuthorPHID() === $comment->getAuthorPHID()) &&
120 ($this->getSyntheticAuthor() === $comment->getSyntheticAuthor()) &&
121 ($this->getContent() === $comment->getContent());
122 }
123
124 public function setIsGhost($is_ghost) {
125 $this->isGhost = $is_ghost;
126 return $this;
127 }
128
129 public function getIsGhost() {
130 return $this->isGhost;
131 }
132
133 public function setContent($content) {
134 $this->getStorageObject()->setContent($content);
135 return $this;
136 }
137
138 public function getContent() {
139 return $this->getStorageObject()->getContent();
140 }
141
142 public function getID() {
143 return $this->getStorageObject()->getID();
144 }
145
146 public function getPHID() {
147 return $this->getStorageObject()->getPHID();
148 }
149
150 public function setIsNewFile($is_new) {
151 $this->getStorageObject()->setIsNewFile($is_new);
152 return $this;
153 }
154
155 public function getIsNewFile() {
156 return $this->getStorageObject()->getIsNewFile();
157 }
158
159 public function setFixedState($state) {
160 $this->getStorageObject()->setFixedState($state);
161 return $this;
162 }
163
164 public function setHasReplies($has_replies) {
165 $this->getStorageObject()->setHasReplies($has_replies);
166 return $this;
167 }
168
169 public function getHasReplies() {
170 return $this->getStorageObject()->getHasReplies();
171 }
172
173 public function getFixedState() {
174 return $this->getStorageObject()->getFixedState();
175 }
176
177 public function setLineNumber($number) {
178 $this->getStorageObject()->setLineNumber($number);
179 return $this;
180 }
181
182 public function getLineNumber() {
183 return $this->getStorageObject()->getLineNumber();
184 }
185
186 public function setLineLength($length) {
187 $this->getStorageObject()->setLineLength($length);
188 return $this;
189 }
190
191 public function getLineLength() {
192 return $this->getStorageObject()->getLineLength();
193 }
194
195 public function setAuthorPHID($phid) {
196 $this->getStorageObject()->setAuthorPHID($phid);
197 return $this;
198 }
199
200 public function getAuthorPHID() {
201 return $this->getStorageObject()->getAuthorPHID();
202 }
203
204 public function setReplyToCommentPHID($phid) {
205 $this->getStorageObject()->setReplyToCommentPHID($phid);
206 return $this;
207 }
208
209 public function getReplyToCommentPHID() {
210 return $this->getStorageObject()->getReplyToCommentPHID();
211 }
212
213 public function setIsDeleted($is_deleted) {
214 $this->getStorageObject()->setIsDeleted($is_deleted);
215 return $this;
216 }
217
218 public function getIsDeleted() {
219 return $this->getStorageObject()->getIsDeleted();
220 }
221
222 public function setIsEditing($is_editing) {
223 $this->getStorageObject()->setAttribute('editing', (bool)$is_editing);
224 return $this;
225 }
226
227 public function getIsEditing() {
228 return (bool)$this->getStorageObject()->getAttribute('editing', false);
229 }
230
231 public function setDocumentEngineKey($engine_key) {
232 $this->getStorageObject()->setAttribute('documentEngineKey', $engine_key);
233 return $this;
234 }
235
236 public function getDocumentEngineKey() {
237 return $this->getStorageObject()->getAttribute('documentEngineKey');
238 }
239
240 public function setStartOffset($offset) {
241 $this->getStorageObject()->setAttribute('startOffset', $offset);
242 return $this;
243 }
244
245 public function getStartOffset() {
246 return $this->getStorageObject()->getAttribute('startOffset');
247 }
248
249 public function setEndOffset($offset) {
250 $this->getStorageObject()->setAttribute('endOffset', $offset);
251 return $this;
252 }
253
254 public function getEndOffset() {
255 return $this->getStorageObject()->getAttribute('endOffset');
256 }
257
258 public function getDateModified() {
259 return $this->getStorageObject()->getDateModified();
260 }
261
262 public function getDateCreated() {
263 return $this->getStorageObject()->getDateCreated();
264 }
265
266 public function openTransaction() {
267 $this->getStorageObject()->openTransaction();
268 }
269
270 public function saveTransaction() {
271 $this->getStorageObject()->saveTransaction();
272 }
273
274 public function save() {
275 $this->getTransactionCommentForSave()->save();
276 return $this;
277 }
278
279 public function delete() {
280 $this->getStorageObject()->delete();
281 return $this;
282 }
283
284 public function makeEphemeral() {
285 $this->getStorageObject()->makeEphemeral();
286 return $this;
287 }
288
289 public function attachVersionedDraftForViewer(
290 PhabricatorUser $viewer,
291 ?PhabricatorVersionedDraft $draft = null) {
292
293 $key = $viewer->getCacheFragment();
294 $this->versionedDrafts[$key] = $draft;
295
296 return $this;
297 }
298
299 public function hasVersionedDraftForViewer(PhabricatorUser $viewer) {
300 $key = $viewer->getCacheFragment();
301 return array_key_exists($key, $this->versionedDrafts);
302 }
303
304 public function getVersionedDraftForViewer(PhabricatorUser $viewer) {
305 $key = $viewer->getCacheFragment();
306 if (!array_key_exists($key, $this->versionedDrafts)) {
307 throw new Exception(
308 pht(
309 'Versioned draft is not attached for user with fragment "%s".',
310 $key));
311 }
312
313 return $this->versionedDrafts[$key];
314 }
315
316 public function isVoidComment(PhabricatorUser $viewer) {
317 return $this->getContentStateForEdit($viewer)->isEmptyContentState();
318 }
319
320 public function getContentStateForEdit(PhabricatorUser $viewer) {
321 $state = $this->getContentState();
322
323 if ($this->hasVersionedDraftForViewer($viewer)) {
324 $versioned_draft = $this->getVersionedDraftForViewer($viewer);
325 if ($versioned_draft) {
326 $storage_map = $versioned_draft->getProperty('inline.state');
327 if (is_array($storage_map)) {
328 $state->readStorageMap($storage_map);
329 }
330 }
331 }
332
333 return $state;
334 }
335
336 protected function newContentState() {
337 return new PhabricatorDiffInlineCommentContentState();
338 }
339
340 public function newContentStateFromRequest(AphrontRequest $request) {
341 return $this->newContentState()->readFromRequest($request);
342 }
343
344 public function getInitialContentState() {
345 return $this->getNamedContentState('inline.state.initial');
346 }
347
348 public function setInitialContentState(
349 PhabricatorInlineCommentContentState $state) {
350 return $this->setNamedContentState('inline.state.initial', $state);
351 }
352
353 public function getCommittedContentState() {
354 return $this->getNamedContentState('inline.state.committed');
355 }
356
357 public function setCommittedContentState(
358 PhabricatorInlineCommentContentState $state) {
359 return $this->setNamedContentState('inline.state.committed', $state);
360 }
361
362 public function getContentState() {
363 $state = $this->getNamedContentState('inline.state');
364
365 if (!$state) {
366 $state = $this->newContentState();
367 }
368
369 $state->setContentText($this->getContent());
370
371 return $state;
372 }
373
374 public function setContentState(PhabricatorInlineCommentContentState $state) {
375 $this->setContent($state->getContentText());
376
377 return $this->setNamedContentState('inline.state', $state);
378 }
379
380 private function getNamedContentState($key) {
381 $storage = $this->getStorageObject();
382
383 $storage_map = $storage->getAttribute($key);
384 if (!is_array($storage_map)) {
385 return null;
386 }
387
388 $state = $this->newContentState();
389 $state->readStorageMap($storage_map);
390 return $state;
391 }
392
393 private function setNamedContentState(
394 $key,
395 PhabricatorInlineCommentContentState $state) {
396
397 $storage = $this->getStorageObject();
398 $storage_map = $state->newStorageMap();
399 $storage->setAttribute($key, $storage_map);
400
401 return $this;
402 }
403
404 public function getInlineContext() {
405 return $this->getStorageObject()->getInlineContext();
406 }
407
408 public function getContentStateMapForEdit(PhabricatorUser $viewer) {
409 return $this->getWireContentStateMap(true, $viewer);
410 }
411
412 public function getContentStateMap() {
413 return $this->getWireContentStateMap(false, null);
414 }
415
416 private function getWireContentStateMap(
417 $is_edit,
418 ?PhabricatorUser $viewer = null) {
419
420 $initial_state = $this->getInitialContentState();
421 $committed_state = $this->getCommittedContentState();
422
423 if ($is_edit) {
424 $active_state = $this->getContentStateForEdit($viewer);
425 } else {
426 $active_state = $this->getContentState();
427 }
428
429 return array(
430 'initial' => $this->getWireContentState($initial_state),
431 'committed' => $this->getWireContentState($committed_state),
432 'active' => $this->getWireContentState($active_state),
433 );
434 }
435
436 private function getWireContentState($content_state) {
437 if ($content_state === null) {
438 return null;
439 }
440
441 return $content_state->newStorageMap();
442 }
443
444 public function getDefaultSuggestionText() {
445 $context = $this->getInlineContext();
446
447 if (!$context) {
448 return null;
449 }
450
451 $default = $context->getBodyLines();
452 $default = implode('', $default);
453
454 return $default;
455 }
456
457
458/* -( PhabricatorMarkupInterface Implementation )-------------------------- */
459
460
461 public function getMarkupFieldKey($field) {
462 $content = $this->getMarkupText($field);
463 return PhabricatorMarkupEngine::digestRemarkupContent($this, $content);
464 }
465
466 public function newMarkupEngine($field) {
467 return PhabricatorMarkupEngine::newDifferentialMarkupEngine();
468 }
469
470 public function getMarkupText($field) {
471 return $this->getContent();
472 }
473
474 public function didMarkupText($field, $output, PhutilMarkupEngine $engine) {
475 return $output;
476 }
477
478 public function shouldUseMarkupCache($field) {
479 return !$this->isDraft();
480 }
481
482}