[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/applications/project/query/ -> PhabricatorProjectQuery.php (source)

   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  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1