@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
fork

Configure Feed

Select the types of activity you want to include in your feed.

at upstream/main 279 lines 7.3 kB view raw
1<?php 2 3final class PhabricatorBoardResponseEngine extends Phobject { 4 5 private $viewer; 6 private $objects; 7 private $boardPHID; 8 private $visiblePHIDs = array(); 9 private $updatePHIDs = array(); 10 private $ordering; 11 private $sounds; 12 13 public function setViewer(PhabricatorUser $viewer) { 14 $this->viewer = $viewer; 15 return $this; 16 } 17 18 public function getViewer() { 19 return $this->viewer; 20 } 21 22 public function setBoardPHID($board_phid) { 23 $this->boardPHID = $board_phid; 24 return $this; 25 } 26 27 public function getBoardPHID() { 28 return $this->boardPHID; 29 } 30 31 public function setObjects(array $objects) { 32 $this->objects = $objects; 33 return $this; 34 } 35 36 public function getObjects() { 37 return $this->objects; 38 } 39 40 public function setVisiblePHIDs(array $visible_phids) { 41 $this->visiblePHIDs = $visible_phids; 42 return $this; 43 } 44 45 public function getVisiblePHIDs() { 46 return $this->visiblePHIDs; 47 } 48 49 public function setUpdatePHIDs(array $update_phids) { 50 $this->updatePHIDs = $update_phids; 51 return $this; 52 } 53 54 public function getUpdatePHIDs() { 55 return $this->updatePHIDs; 56 } 57 58 public function setOrdering(PhabricatorProjectColumnOrder $ordering) { 59 $this->ordering = $ordering; 60 return $this; 61 } 62 63 public function getOrdering() { 64 return $this->ordering; 65 } 66 67 public function setSounds(array $sounds) { 68 $this->sounds = $sounds; 69 return $this; 70 } 71 72 public function getSounds() { 73 return $this->sounds; 74 } 75 76 public function buildResponse() { 77 $viewer = $this->getViewer(); 78 $board_phid = $this->getBoardPHID(); 79 $ordering = $this->getOrdering(); 80 81 $update_phids = $this->getUpdatePHIDs(); 82 $update_phids = array_fuse($update_phids); 83 84 $visible_phids = $this->getVisiblePHIDs(); 85 $visible_phids = array_fuse($visible_phids); 86 87 $all_phids = $update_phids + $visible_phids; 88 89 // Load all the other tasks that are visible in the affected columns and 90 // perform layout for them. 91 92 if ($this->objects !== null) { 93 $all_objects = $this->getObjects(); 94 $all_objects = mpull($all_objects, null, 'getPHID'); 95 } else { 96 $all_objects = id(new ManiphestTaskQuery()) 97 ->setViewer($viewer) 98 ->withPHIDs($all_phids) 99 ->execute(); 100 $all_objects = mpull($all_objects, null, 'getPHID'); 101 } 102 103 // NOTE: The board layout engine is sensitive to PHID input order, and uses 104 // the input order as a component of the "natural" column ordering if no 105 // explicit ordering is specified. Rearrange the PHIDs in ID order. 106 107 $all_objects = msort($all_objects, 'getID'); 108 $ordered_phids = mpull($all_objects, 'getPHID'); 109 110 $layout_engine = id(new PhabricatorBoardLayoutEngine()) 111 ->setViewer($viewer) 112 ->setBoardPHIDs(array($board_phid)) 113 ->setObjectPHIDs($ordered_phids) 114 ->executeLayout(); 115 116 $natural = array(); 117 118 $update_columns = array(); 119 foreach ($update_phids as $update_phid) { 120 $update_columns += $layout_engine->getObjectColumns( 121 $board_phid, 122 $update_phid); 123 } 124 125 foreach ($update_columns as $column_phid => $column) { 126 $column_object_phids = $layout_engine->getColumnObjectPHIDs( 127 $board_phid, 128 $column_phid); 129 $natural[$column_phid] = array_values($column_object_phids); 130 } 131 132 if ($ordering) { 133 $vectors = $ordering->getSortVectorsForObjects($all_objects); 134 $header_keys = $ordering->getHeaderKeysForObjects($all_objects); 135 $headers = $ordering->getHeadersForObjects($all_objects); 136 $headers = mpull($headers, 'toDictionary'); 137 } else { 138 $vectors = array(); 139 $header_keys = array(); 140 $headers = array(); 141 } 142 143 $templates = $this->newCardTemplates(); 144 145 $cards = array(); 146 foreach ($all_objects as $card_phid => $object) { 147 $card = array( 148 'vectors' => array(), 149 'headers' => array(), 150 'properties' => array(), 151 'nodeHTMLTemplate' => null, 152 ); 153 154 if ($ordering) { 155 $order_key = $ordering->getColumnOrderKey(); 156 157 $vector = idx($vectors, $card_phid); 158 if ($vector !== null) { 159 $card['vectors'][$order_key] = $vector; 160 } 161 162 $header = idx($header_keys, $card_phid); 163 if ($header !== null) { 164 $card['headers'][$order_key] = $header; 165 } 166 167 $card['properties'] = self::newTaskProperties($object); 168 } 169 170 if (isset($templates[$card_phid])) { 171 $card['nodeHTMLTemplate'] = hsprintf('%s', $templates[$card_phid]); 172 $card['update'] = true; 173 } else { 174 $card['update'] = false; 175 } 176 177 $card['vectors'] = (object)$card['vectors']; 178 $card['headers'] = (object)$card['headers']; 179 $card['properties'] = (object)$card['properties']; 180 181 $cards[$card_phid] = $card; 182 } 183 184 // Mark cards which are currently visible on the client but not visible 185 // on the board on the server for removal from the client view of the 186 // board state. 187 foreach ($visible_phids as $card_phid) { 188 if (!isset($cards[$card_phid])) { 189 $cards[$card_phid] = array( 190 'remove' => true, 191 ); 192 } 193 } 194 195 $payload = array( 196 'columnMaps' => $natural, 197 'cards' => $cards, 198 'headers' => $headers, 199 'sounds' => $this->getSounds(), 200 ); 201 202 return id(new AphrontAjaxResponse()) 203 ->setContent($payload); 204 } 205 206 public static function newTaskProperties($task) { 207 return array( 208 'points' => (float)$task->getPoints(), 209 'status' => $task->getStatus(), 210 'priority' => (int)$task->getPriority(), 211 'owner' => $task->getOwnerPHID(), 212 ); 213 } 214 215 private function loadExcludedProjectPHIDs() { 216 $viewer = $this->getViewer(); 217 $board_phid = $this->getBoardPHID(); 218 219 $exclude_phids = array($board_phid); 220 221 $descendants = id(new PhabricatorProjectQuery()) 222 ->setViewer($viewer) 223 ->withAncestorProjectPHIDs($exclude_phids) 224 ->execute(); 225 226 foreach ($descendants as $descendant) { 227 $exclude_phids[] = $descendant->getPHID(); 228 } 229 230 return array_fuse($exclude_phids); 231 } 232 233 private function newCardTemplates() { 234 $viewer = $this->getViewer(); 235 236 $update_phids = $this->getUpdatePHIDs(); 237 if (!$update_phids) { 238 return array(); 239 } 240 $update_phids = array_fuse($update_phids); 241 242 if ($this->objects === null) { 243 $objects = id(new ManiphestTaskQuery()) 244 ->setViewer($viewer) 245 ->withPHIDs($update_phids) 246 ->needProjectPHIDs(true) 247 ->execute(); 248 } else { 249 $objects = $this->getObjects(); 250 $objects = mpull($objects, null, 'getPHID'); 251 $objects = array_select_keys($objects, $update_phids); 252 } 253 254 if (!$objects) { 255 return array(); 256 } 257 258 $excluded_phids = $this->loadExcludedProjectPHIDs(); 259 260 $rendering_engine = id(new PhabricatorBoardRenderingEngine()) 261 ->setViewer($viewer) 262 ->setObjects($objects) 263 ->setExcludedProjectPHIDs($excluded_phids); 264 265 $templates = array(); 266 foreach ($objects as $object) { 267 $object_phid = $object->getPHID(); 268 269 $card = $rendering_engine->renderCard($object_phid); 270 $item = $card->getItem(); 271 $template = hsprintf('%s', $item); 272 273 $templates[$object_phid] = $template; 274 } 275 276 return $templates; 277 } 278 279}