[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 final class PhabricatorProjectColumnPositionQuery 4 extends PhabricatorCursorPagedPolicyAwareQuery { 5 6 private $ids; 7 private $boardPHIDs; 8 private $objectPHIDs; 9 private $columns; 10 11 private $needColumns; 12 private $skipImplicitCreate; 13 14 public function withIDs(array $ids) { 15 $this->ids = $ids; 16 return $this; 17 } 18 19 public function withBoardPHIDs(array $board_phids) { 20 $this->boardPHIDs = $board_phids; 21 return $this; 22 } 23 24 public function withObjectPHIDs(array $object_phids) { 25 $this->objectPHIDs = $object_phids; 26 return $this; 27 } 28 29 /** 30 * Find objects in specific columns. 31 * 32 * NOTE: Using this method activates logic which constructs virtual 33 * column positions for objects not in any column, if you pass a default 34 * column. Normally these results are not returned. 35 * 36 * @param list<PhabricatorProjectColumn> Columns to look for objects in. 37 * @return this 38 */ 39 public function withColumns(array $columns) { 40 assert_instances_of($columns, 'PhabricatorProjectColumn'); 41 $this->columns = $columns; 42 return $this; 43 } 44 45 public function needColumns($need_columns) { 46 $this->needColumns = true; 47 return $this; 48 } 49 50 51 /** 52 * Skip implicit creation of column positions which are implied but do not 53 * yet exist. 54 * 55 * This is primarily useful internally. 56 * 57 * @param bool True to skip implicit creation of column positions. 58 * @return this 59 */ 60 public function setSkipImplicitCreate($skip) { 61 $this->skipImplicitCreate = $skip; 62 return $this; 63 } 64 65 // NOTE: For now, boards are always attached to projects. However, they might 66 // not be in the future. This generalization just anticipates a future where 67 // we let other types of objects (like users) have boards, or let boards 68 // contain other types of objects. 69 70 private function newPositionObject() { 71 return new PhabricatorProjectColumnPosition(); 72 } 73 74 private function newColumnQuery() { 75 return new PhabricatorProjectColumnQuery(); 76 } 77 78 private function getBoardMembershipEdgeTypes() { 79 return array( 80 PhabricatorProjectProjectHasObjectEdgeType::EDGECONST, 81 ); 82 } 83 84 private function getBoardMembershipPHIDTypes() { 85 return array( 86 ManiphestTaskPHIDType::TYPECONST, 87 ); 88 } 89 90 protected function loadPage() { 91 $table = $this->newPositionObject(); 92 $conn_r = $table->establishConnection('r'); 93 94 // We're going to find results by combining two queries: one query finds 95 // objects on a board column, while the other query finds objects not on 96 // any board column and virtually puts them on the default column. 97 98 $unions = array(); 99 100 // First, find all the stuff that's actually on a column. 101 102 $unions[] = qsprintf( 103 $conn_r, 104 'SELECT * FROM %T %Q', 105 $table->getTableName(), 106 $this->buildWhereClause($conn_r)); 107 108 // If we have a default column, find all the stuff that's not in any 109 // column and put it in the default column. 110 111 $must_type_filter = false; 112 if ($this->columns && !$this->skipImplicitCreate) { 113 $default_map = array(); 114 foreach ($this->columns as $column) { 115 if ($column->isDefaultColumn()) { 116 $default_map[$column->getProjectPHID()] = $column->getPHID(); 117 } 118 } 119 120 if ($default_map) { 121 $where = array(); 122 123 // Find the edges attached to the boards we have default columns for. 124 125 $where[] = qsprintf( 126 $conn_r, 127 'e.src IN (%Ls)', 128 array_keys($default_map)); 129 130 // Find only edges which describe a board relationship. 131 132 $where[] = qsprintf( 133 $conn_r, 134 'e.type IN (%Ld)', 135 $this->getBoardMembershipEdgeTypes()); 136 137 if ($this->boardPHIDs !== null) { 138 // This should normally be redundant, but construct it anyway if 139 // the caller has told us to. 140 $where[] = qsprintf( 141 $conn_r, 142 'e.src IN (%Ls)', 143 $this->boardPHIDs); 144 } 145 146 if ($this->objectPHIDs !== null) { 147 $where[] = qsprintf( 148 $conn_r, 149 'e.dst IN (%Ls)', 150 $this->objectPHIDs); 151 } 152 153 $where[] = qsprintf( 154 $conn_r, 155 'p.id IS NULL'); 156 157 $where = $this->formatWhereClause($where); 158 159 $unions[] = qsprintf( 160 $conn_r, 161 'SELECT NULL id, e.src boardPHID, NULL columnPHID, e.dst objectPHID, 162 0 sequence 163 FROM %T e LEFT JOIN %T p 164 ON e.src = p.boardPHID AND e.dst = p.objectPHID 165 %Q', 166 PhabricatorEdgeConfig::TABLE_NAME_EDGE, 167 $table->getTableName(), 168 $where); 169 170 $must_type_filter = true; 171 } 172 } 173 174 $data = queryfx_all( 175 $conn_r, 176 '%Q %Q %Q', 177 implode(' UNION ALL ', $unions), 178 $this->buildOrderClause($conn_r), 179 $this->buildLimitClause($conn_r)); 180 181 // If we've picked up objects not in any column, we need to filter out any 182 // matched objects which have the wrong edge type. 183 if ($must_type_filter) { 184 $allowed_types = array_fuse($this->getBoardMembershipPHIDTypes()); 185 foreach ($data as $id => $row) { 186 if ($row['columnPHID'] === null) { 187 $object_phid = $row['objectPHID']; 188 if (empty($allowed_types[phid_get_type($object_phid)])) { 189 unset($data[$id]); 190 } 191 } 192 } 193 } 194 195 $positions = $table->loadAllFromArray($data); 196 197 // Find the implied positions which don't exist yet. If there are any, 198 // we're going to create them. 199 $create = array(); 200 foreach ($positions as $position) { 201 if ($position->getColumnPHID() === null) { 202 $column_phid = idx($default_map, $position->getBoardPHID()); 203 $position->setColumnPHID($column_phid); 204 205 $create[] = $position; 206 } 207 } 208 209 if ($create) { 210 // If we're adding several objects to a column, insert the column 211 // position objects in object ID order. This means that newly added 212 // objects float to the top, and when a group of newly added objects 213 // float up at the same time, the most recently created ones end up 214 // highest in the list. 215 216 $objects = id(new PhabricatorObjectQuery()) 217 ->setViewer(PhabricatorUser::getOmnipotentUser()) 218 ->withPHIDs(mpull($create, 'getObjectPHID')) 219 ->execute(); 220 $objects = mpull($objects, null, 'getPHID'); 221 $objects = msort($objects, 'getID'); 222 223 $create = mgroup($create, 'getObjectPHID'); 224 $create = array_select_keys($create, array_keys($objects)) + $create; 225 226 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); 227 228 foreach ($create as $object_phid => $create_positions) { 229 foreach ($create_positions as $create_position) { 230 $create_position->save(); 231 } 232 } 233 234 unset($unguarded); 235 } 236 237 return $positions; 238 } 239 240 protected function willFilterPage(array $page) { 241 242 if ($this->needColumns) { 243 $column_phids = mpull($page, 'getColumnPHID'); 244 $columns = $this->newColumnQuery() 245 ->setParentQuery($this) 246 ->setViewer($this->getViewer()) 247 ->withPHIDs($column_phids) 248 ->execute(); 249 $columns = mpull($columns, null, 'getPHID'); 250 251 foreach ($page as $key => $position) { 252 $column = idx($columns, $position->getColumnPHID()); 253 if (!$column) { 254 unset($page[$key]); 255 continue; 256 } 257 258 $position->attachColumn($column); 259 } 260 } 261 262 return $page; 263 } 264 265 private function buildWhereClause($conn_r) { 266 $where = array(); 267 268 if ($this->ids !== null) { 269 $where[] = qsprintf( 270 $conn_r, 271 'id IN (%Ld)', 272 $this->ids); 273 } 274 275 if ($this->boardPHIDs !== null) { 276 $where[] = qsprintf( 277 $conn_r, 278 'boardPHID IN (%Ls)', 279 $this->boardPHIDs); 280 } 281 282 if ($this->objectPHIDs !== null) { 283 $where[] = qsprintf( 284 $conn_r, 285 'objectPHID IN (%Ls)', 286 $this->objectPHIDs); 287 } 288 289 if ($this->columns !== null) { 290 $where[] = qsprintf( 291 $conn_r, 292 'columnPHID IN (%Ls)', 293 mpull($this->columns, 'getPHID')); 294 } 295 296 // NOTE: Explicitly not building the paging clause here, since it won't 297 // work with the UNION. 298 299 return $this->formatWhereClause($where); 300 } 301 302 public function getQueryApplicationClass() { 303 return 'PhabricatorProjectApplication'; 304 } 305 306 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |