@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
at recaptime-dev/main 482 lines 12 kB view raw
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}