[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 final class PhabricatorProjectQuery 4 extends PhabricatorCursorPagedPolicyAwareQuery { 5 6 private $ids; 7 private $phids; 8 private $memberPHIDs; 9 private $slugs; 10 private $phrictionSlugs; 11 private $names; 12 private $datasourceQuery; 13 private $icons; 14 private $colors; 15 16 private $status = 'status-any'; 17 const STATUS_ANY = 'status-any'; 18 const STATUS_OPEN = 'status-open'; 19 const STATUS_CLOSED = 'status-closed'; 20 const STATUS_ACTIVE = 'status-active'; 21 const STATUS_ARCHIVED = 'status-archived'; 22 23 private $needSlugs; 24 private $needMembers; 25 private $needWatchers; 26 private $needImages; 27 28 public function withIDs(array $ids) { 29 $this->ids = $ids; 30 return $this; 31 } 32 33 public function withPHIDs(array $phids) { 34 $this->phids = $phids; 35 return $this; 36 } 37 38 public function withStatus($status) { 39 $this->status = $status; 40 return $this; 41 } 42 43 public function withMemberPHIDs(array $member_phids) { 44 $this->memberPHIDs = $member_phids; 45 return $this; 46 } 47 48 public function withSlugs(array $slugs) { 49 $this->slugs = $slugs; 50 return $this; 51 } 52 53 public function withPhrictionSlugs(array $slugs) { 54 $this->phrictionSlugs = $slugs; 55 return $this; 56 } 57 58 public function withNames(array $names) { 59 $this->names = $names; 60 return $this; 61 } 62 63 public function withDatasourceQuery($string) { 64 $this->datasourceQuery = $string; 65 return $this; 66 } 67 68 public function withIcons(array $icons) { 69 $this->icons = $icons; 70 return $this; 71 } 72 73 public function withColors(array $colors) { 74 $this->colors = $colors; 75 return $this; 76 } 77 78 public function needMembers($need_members) { 79 $this->needMembers = $need_members; 80 return $this; 81 } 82 83 public function needWatchers($need_watchers) { 84 $this->needWatchers = $need_watchers; 85 return $this; 86 } 87 88 public function needImages($need_images) { 89 $this->needImages = $need_images; 90 return $this; 91 } 92 93 public function needSlugs($need_slugs) { 94 $this->needSlugs = $need_slugs; 95 return $this; 96 } 97 98 protected function getPagingColumn() { 99 return 'name'; 100 } 101 102 protected function getPagingValue($result) { 103 return $result->getName(); 104 } 105 106 protected function getReversePaging() { 107 return true; 108 } 109 110 protected function loadPage() { 111 $table = new PhabricatorProject(); 112 $conn_r = $table->establishConnection('r'); 113 114 // NOTE: Because visibility checks for projects depend on whether or not 115 // the user is a project member, we always load their membership. If we're 116 // loading all members anyway we can piggyback on that; otherwise we 117 // do an explicit join. 118 119 $select_clause = ''; 120 if (!$this->needMembers) { 121 $select_clause = ', vm.dst viewerIsMember'; 122 } 123 124 $data = queryfx_all( 125 $conn_r, 126 'SELECT p.* %Q FROM %T p %Q %Q %Q %Q %Q', 127 $select_clause, 128 $table->getTableName(), 129 $this->buildJoinClause($conn_r), 130 $this->buildWhereClause($conn_r), 131 $this->buildGroupClause($conn_r), 132 $this->buildOrderClause($conn_r), 133 $this->buildLimitClause($conn_r)); 134 135 $projects = $table->loadAllFromArray($data); 136 137 if ($projects) { 138 $viewer_phid = $this->getViewer()->getPHID(); 139 $project_phids = mpull($projects, 'getPHID'); 140 141 $member_type = PhabricatorEdgeConfig::TYPE_PROJ_MEMBER; 142 $watcher_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_WATCHER; 143 144 $need_edge_types = array(); 145 if ($this->needMembers) { 146 $need_edge_types[] = $member_type; 147 } else { 148 foreach ($data as $row) { 149 $projects[$row['id']]->setIsUserMember( 150 $viewer_phid, 151 ($row['viewerIsMember'] !== null)); 152 } 153 } 154 155 if ($this->needWatchers) { 156 $need_edge_types[] = $watcher_type; 157 } 158 159 if ($need_edge_types) { 160 $edges = id(new PhabricatorEdgeQuery()) 161 ->withSourcePHIDs($project_phids) 162 ->withEdgeTypes($need_edge_types) 163 ->execute(); 164 165 if ($this->needMembers) { 166 foreach ($projects as $project) { 167 $phid = $project->getPHID(); 168 $project->attachMemberPHIDs( 169 array_keys($edges[$phid][$member_type])); 170 $project->setIsUserMember( 171 $viewer_phid, 172 isset($edges[$phid][$member_type][$viewer_phid])); 173 } 174 } 175 176 if ($this->needWatchers) { 177 foreach ($projects as $project) { 178 $phid = $project->getPHID(); 179 $project->attachWatcherPHIDs( 180 array_keys($edges[$phid][$watcher_type])); 181 $project->setIsUserWatcher( 182 $viewer_phid, 183 isset($edges[$phid][$watcher_type][$viewer_phid])); 184 } 185 } 186 } 187 } 188 189 return $projects; 190 } 191 192 protected function didFilterPage(array $projects) { 193 if ($this->needImages) { 194 $default = null; 195 196 $file_phids = mpull($projects, 'getProfileImagePHID'); 197 $files = id(new PhabricatorFileQuery()) 198 ->setParentQuery($this) 199 ->setViewer($this->getViewer()) 200 ->withPHIDs($file_phids) 201 ->execute(); 202 $files = mpull($files, null, 'getPHID'); 203 foreach ($projects as $project) { 204 $file = idx($files, $project->getProfileImagePHID()); 205 if (!$file) { 206 if (!$default) { 207 $default = PhabricatorFile::loadBuiltin( 208 $this->getViewer(), 209 'project.png'); 210 } 211 $file = $default; 212 } 213 $project->attachProfileImageFile($file); 214 } 215 } 216 217 if ($this->needSlugs) { 218 $slugs = id(new PhabricatorProjectSlug()) 219 ->loadAllWhere( 220 'projectPHID IN (%Ls)', 221 mpull($projects, 'getPHID')); 222 $slugs = mgroup($slugs, 'getProjectPHID'); 223 foreach ($projects as $project) { 224 $project_slugs = idx($slugs, $project->getPHID(), array()); 225 $project->attachSlugs($project_slugs); 226 } 227 } 228 229 return $projects; 230 } 231 232 private function buildWhereClause($conn_r) { 233 $where = array(); 234 235 if ($this->status != self::STATUS_ANY) { 236 switch ($this->status) { 237 case self::STATUS_OPEN: 238 case self::STATUS_ACTIVE: 239 $filter = array( 240 PhabricatorProjectStatus::STATUS_ACTIVE, 241 ); 242 break; 243 case self::STATUS_CLOSED: 244 case self::STATUS_ARCHIVED: 245 $filter = array( 246 PhabricatorProjectStatus::STATUS_ARCHIVED, 247 ); 248 break; 249 default: 250 throw new Exception( 251 "Unknown project status '{$this->status}'!"); 252 } 253 $where[] = qsprintf( 254 $conn_r, 255 'status IN (%Ld)', 256 $filter); 257 } 258 259 if ($this->ids !== null) { 260 $where[] = qsprintf( 261 $conn_r, 262 'id IN (%Ld)', 263 $this->ids); 264 } 265 266 if ($this->phids !== null) { 267 $where[] = qsprintf( 268 $conn_r, 269 'phid IN (%Ls)', 270 $this->phids); 271 } 272 273 if ($this->memberPHIDs !== null) { 274 $where[] = qsprintf( 275 $conn_r, 276 'e.dst IN (%Ls)', 277 $this->memberPHIDs); 278 } 279 280 if ($this->slugs !== null) { 281 $slugs = array(); 282 foreach ($this->slugs as $slug) { 283 $slugs[] = rtrim(PhabricatorSlug::normalize($slug), '/'); 284 } 285 286 $where[] = qsprintf( 287 $conn_r, 288 'slug.slug IN (%Ls)', 289 $slugs); 290 } 291 292 if ($this->phrictionSlugs !== null) { 293 $where[] = qsprintf( 294 $conn_r, 295 'phrictionSlug IN (%Ls)', 296 $this->phrictionSlugs); 297 } 298 299 if ($this->names !== null) { 300 $where[] = qsprintf( 301 $conn_r, 302 'name IN (%Ls)', 303 $this->names); 304 } 305 306 if ($this->icons !== null) { 307 $where[] = qsprintf( 308 $conn_r, 309 'icon IN (%Ls)', 310 $this->icons); 311 } 312 313 if ($this->colors !== null) { 314 $where[] = qsprintf( 315 $conn_r, 316 'color IN (%Ls)', 317 $this->colors); 318 } 319 320 $where[] = $this->buildPagingClause($conn_r); 321 322 return $this->formatWhereClause($where); 323 } 324 325 private function buildGroupClause($conn_r) { 326 if ($this->memberPHIDs || $this->datasourceQuery) { 327 return 'GROUP BY p.id'; 328 } else { 329 return $this->buildApplicationSearchGroupClause($conn_r); 330 } 331 } 332 333 private function buildJoinClause($conn_r) { 334 $joins = array(); 335 336 if (!$this->needMembers !== null) { 337 $joins[] = qsprintf( 338 $conn_r, 339 'LEFT JOIN %T vm ON vm.src = p.phid AND vm.type = %d AND vm.dst = %s', 340 PhabricatorEdgeConfig::TABLE_NAME_EDGE, 341 PhabricatorEdgeConfig::TYPE_PROJ_MEMBER, 342 $this->getViewer()->getPHID()); 343 } 344 345 if ($this->memberPHIDs !== null) { 346 $joins[] = qsprintf( 347 $conn_r, 348 'JOIN %T e ON e.src = p.phid AND e.type = %d', 349 PhabricatorEdgeConfig::TABLE_NAME_EDGE, 350 PhabricatorEdgeConfig::TYPE_PROJ_MEMBER); 351 } 352 353 if ($this->slugs !== null) { 354 $joins[] = qsprintf( 355 $conn_r, 356 'JOIN %T slug on slug.projectPHID = p.phid', 357 id(new PhabricatorProjectSlug())->getTableName()); 358 } 359 360 if ($this->datasourceQuery !== null) { 361 $tokens = PhabricatorTypeaheadDatasource::tokenizeString( 362 $this->datasourceQuery); 363 if (!$tokens) { 364 throw new PhabricatorEmptyQueryException(); 365 } 366 367 $likes = array(); 368 foreach ($tokens as $token) { 369 $likes[] = qsprintf($conn_r, 'token.token LIKE %>', $token); 370 } 371 372 $joins[] = qsprintf( 373 $conn_r, 374 'JOIN %T token ON token.projectID = p.id AND (%Q)', 375 PhabricatorProject::TABLE_DATASOURCE_TOKEN, 376 '('.implode(') OR (', $likes).')'); 377 } 378 379 $joins[] = $this->buildApplicationSearchJoinClause($conn_r); 380 381 return implode(' ', $joins); 382 } 383 384 public function getQueryApplicationClass() { 385 return 'PhabricatorProjectApplication'; 386 } 387 388 protected function getApplicationSearchObjectPHIDColumn() { 389 return 'p.phid'; 390 } 391 392 }
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 |