Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/project/controller/PhabricatorProjectListController.php b/src/applications/project/controller/PhabricatorProjectListController.php
index 139f3f7229..83f9cd3fa4 100644
--- a/src/applications/project/controller/PhabricatorProjectListController.php
+++ b/src/applications/project/controller/PhabricatorProjectListController.php
@@ -1,182 +1,172 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorProjectListController
extends PhabricatorProjectController {
private $filter;
public function willProcessRequest(array $data) {
$this->filter = idx($data, 'filter');
}
public function processRequest() {
$request = $this->getRequest();
$nav = new AphrontSideNavFilterView();
$nav
->setBaseURI(new PhutilURI('/project/filter/'))
->addLabel('User')
->addFilter('active', 'Active')
->addSpacer()
->addLabel('All')
->addFilter('all', 'All Projects')
->addFilter('allactive','Active Projects');
$this->filter = $nav->selectFilter($this->filter, 'active');
$pager = new AphrontPagerView();
$pager->setPageSize(250);
$pager->setURI($request->getRequestURI(), 'page');
$pager->setOffset($request->getInt('page'));
$query = new PhabricatorProjectQuery();
$query->setViewer($request->getUser());
- $query->setOffset($pager->getOffset());
- $query->setLimit($pager->getPageSize() + 1);
+ $query->needMembers(true);
$view_phid = $request->getUser()->getPHID();
$status_filter = PhabricatorProjectQuery::STATUS_ANY;
switch ($this->filter) {
case 'active':
$table_header = 'Your Projects';
$query->withMemberPHIDs(array($view_phid));
$query->withStatus(PhabricatorProjectQuery::STATUS_ACTIVE);
break;
case 'allactive':
$status_filter = PhabricatorProjectQuery::STATUS_ACTIVE;
$table_header = 'Active Projects';
// fallthrough
case 'all':
$table_header = 'All Projects';
$query->withStatus($status_filter);
break;
}
- $projects = $query->execute();
- $projects = $pager->sliceResults($projects);
+ $projects = $query->executeWithOffsetPager($pager);
$project_phids = mpull($projects, 'getPHID');
$profiles = array();
if ($projects) {
$profiles = id(new PhabricatorProjectProfile())->loadAllWhere(
'projectPHID in (%Ls)',
$project_phids);
$profiles = mpull($profiles, null, 'getProjectPHID');
}
- $edge_query = new PhabricatorEdgeQuery();
- if ($projects) {
- $edge_query
- ->withSourcePHIDs($project_phids)
- ->withEdgeTypes(array(PhabricatorEdgeConfig::TYPE_PROJ_MEMBER))
- ->execute();
- }
-
$tasks = array();
$groups = array();
if ($project_phids) {
$query = id(new ManiphestTaskQuery())
->withProjects($project_phids)
->withAnyProject(true)
->withStatus(ManiphestTaskQuery::STATUS_OPEN)
->setLimit(PHP_INT_MAX);
$tasks = $query->execute();
foreach ($tasks as $task) {
foreach ($task->getProjectPHIDs() as $phid) {
$groups[$phid][] = $task;
}
}
}
$rows = array();
foreach ($projects as $project) {
$phid = $project->getPHID();
$profile = idx($profiles, $phid);
- $members = $edge_query->getDestinationPHIDs(array($phid));
+ $members = $project->getMemberPHIDs();
$group = idx($groups, $phid, array());
$task_count = count($group);
$population = count($members);
if ($profile) {
$blurb = $profile->getBlurb();
$blurb = phutil_utf8_shorten($blurb, 64);
} else {
$blurb = null;
}
$rows[] = array(
phutil_render_tag(
'a',
array(
'href' => '/project/view/'.$project->getID().'/',
),
phutil_escape_html($project->getName())),
phutil_escape_html(
PhabricatorProjectStatus::getNameForStatus($project->getStatus())),
phutil_escape_html($blurb),
phutil_escape_html($population),
phutil_render_tag(
'a',
array(
'href' => '/maniphest/view/all/?projects='.$phid,
),
phutil_escape_html($task_count)),
);
}
$table = new AphrontTableView($rows);
$table->setHeaders(
array(
'Project',
'Status',
'Description',
'Population',
'Open Tasks',
));
$table->setColumnClasses(
array(
'pri',
'',
'wide',
'',
''
));
$panel = new AphrontPanelView();
$panel->setHeader($table_header);
$panel->setCreateButton('Create New Project', '/project/create/');
$panel->appendChild($table);
$panel->appendChild($pager);
$nav->appendChild($panel);
return $this->buildStandardPageResponse(
$nav,
array(
'title' => 'Projects',
));
}
}
diff --git a/src/applications/project/query/PhabricatorProjectQuery.php b/src/applications/project/query/PhabricatorProjectQuery.php
index f0187227b7..74fd7e5adc 100644
--- a/src/applications/project/query/PhabricatorProjectQuery.php
+++ b/src/applications/project/query/PhabricatorProjectQuery.php
@@ -1,205 +1,209 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorProjectQuery extends PhabricatorCursorPagedPolicyQuery {
private $ids;
private $phids;
private $memberPHIDs;
private $status = 'status-any';
const STATUS_ANY = 'status-any';
const STATUS_OPEN = 'status-open';
const STATUS_CLOSED = 'status-closed';
const STATUS_ACTIVE = 'status-active';
const STATUS_ARCHIVED = 'status-archived';
private $needMembers;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withStatus($status) {
$this->status = $status;
return $this;
}
public function withMemberPHIDs(array $member_phids) {
$this->memberPHIDs = $member_phids;
return $this;
}
public function needMembers($need_members) {
$this->needMembers = $need_members;
return $this;
}
protected function getPagingColumn() {
return 'name';
}
protected function getPagingValue($result) {
return $result->getName();
}
+ protected function getReversePaging() {
+ return true;
+ }
+
public function loadPage() {
$table = new PhabricatorProject();
$conn_r = $table->establishConnection('r');
// NOTE: Because visibility checks for projects depend on whether or not
// the user is a project member, we always load their membership. If we're
// loading all members anyway we can piggyback on that; otherwise we
// do an explicit join.
$select_clause = '';
if (!$this->needMembers) {
$select_clause = ', vm.dst viewerIsMember';
}
$data = queryfx_all(
$conn_r,
'SELECT p.* %Q FROM %T p %Q %Q %Q %Q %Q',
$select_clause,
$table->getTableName(),
$this->buildJoinClause($conn_r),
$this->buildWhereClause($conn_r),
$this->buildGroupClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
$projects = $table->loadAllFromArray($data);
if ($projects) {
$viewer_phid = $this->getViewer()->getPHID();
if ($this->needMembers) {
$etype = PhabricatorEdgeConfig::TYPE_PROJ_MEMBER;
$members = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(mpull($projects, 'getPHID'))
->withEdgeTypes(array($etype))
->execute();
foreach ($projects as $project) {
$phid = $project->getPHID();
$project->attachMemberPHIDs(array_keys($members[$phid][$etype]));
$project->setIsUserMember(
$viewer_phid,
isset($members[$phid][$etype][$viewer_phid]));
}
} else {
foreach ($data as $row) {
$projects[$row['id']]->setIsUserMember(
$viewer_phid,
($row['viewerIsMember'] !== null));
}
}
}
return $projects;
}
private function buildWhereClause($conn_r) {
$where = array();
if ($this->status != self::STATUS_ANY) {
switch ($this->status) {
case self::STATUS_OPEN:
case self::STATUS_ACTIVE:
$filter = array(
PhabricatorProjectStatus::STATUS_ACTIVE,
);
break;
case self::STATUS_CLOSED:
case self::STATUS_ARCHIVED:
$filter = array(
PhabricatorProjectStatus::STATUS_ARCHIVED,
);
break;
default:
throw new Exception(
"Unknown project status '{$this->status}'!");
}
$where[] = qsprintf(
$conn_r,
'status IN (%Ld)',
$filter);
}
if ($this->ids) {
$where[] = qsprintf(
$conn_r,
'id IN (%Ld)',
$this->ids);
}
if ($this->phids) {
$where[] = qsprintf(
$conn_r,
'phid IN (%Ls)',
$this->phids);
}
if ($this->memberPHIDs) {
$where[] = qsprintf(
$conn_r,
'e.dst IN (%Ls)',
$this->memberPHIDs);
}
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
}
private function buildGroupClause($conn_r) {
if ($this->memberPHIDs) {
return 'GROUP BY p.id';
} else {
return '';
}
}
private function buildJoinClause($conn_r) {
$joins = array();
if (!$this->needMembers) {
$joins[] = qsprintf(
$conn_r,
'LEFT JOIN %T vm ON vm.src = p.phid AND vm.type = %d AND vm.dst = %s',
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
PhabricatorEdgeConfig::TYPE_PROJ_MEMBER,
$this->getViewer()->getPHID());
}
if ($this->memberPHIDs) {
$joins[] = qsprintf(
$conn_r,
'JOIN %T e ON e.src = p.phid AND e.type = %d',
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
PhabricatorEdgeConfig::TYPE_PROJ_MEMBER);
}
return implode(' ', $joins);
}
}
diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyQuery.php
index 8dda36f17d..a3059437ae 100644
--- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyQuery.php
+++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyQuery.php
@@ -1,130 +1,138 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* A query class which uses cursor-based paging. This paging is much more
* performant than offset-based paging in the presence of policy filtering.
*/
abstract class PhabricatorCursorPagedPolicyQuery
extends PhabricatorPolicyQuery {
private $afterID;
private $beforeID;
protected function getPagingColumn() {
return 'id';
}
protected function getPagingValue($result) {
return $result->getID();
}
+ protected function getReversePaging() {
+ return false;
+ }
+
protected function nextPage(array $page) {
if ($this->beforeID) {
$this->beforeID = $this->getPagingValue(head($page));
} else {
$this->afterID = $this->getPagingValue(last($page));
}
}
final public function setAfterID($object_id) {
$this->afterID = $object_id;
return $this;
}
final public function setBeforeID($object_id) {
$this->beforeID = $object_id;
return $this;
}
final protected function buildLimitClause(AphrontDatabaseConnection $conn_r) {
if ($this->getRawResultLimit()) {
return qsprintf($conn_r, 'LIMIT %d', $this->getRawResultLimit());
} else {
return '';
}
}
final protected function buildPagingClause(
AphrontDatabaseConnection $conn_r) {
if ($this->beforeID) {
return qsprintf(
$conn_r,
- '%Q > %s',
+ '%Q %Q %s',
$this->getPagingColumn(),
+ $this->getReversePaging() ? '<' : '>',
$this->beforeID);
} else if ($this->afterID) {
return qsprintf(
$conn_r,
- '%Q < %s',
+ '%Q %Q %s',
$this->getPagingColumn(),
+ $this->getReversePaging() ? '>' : '<',
$this->afterID);
}
return null;
}
final protected function buildOrderClause(AphrontDatabaseConnection $conn_r) {
if ($this->beforeID) {
return qsprintf(
$conn_r,
- 'ORDER BY %Q ASC',
- $this->getPagingColumn());
+ 'ORDER BY %Q %Q',
+ $this->getPagingColumn(),
+ $this->getReversePaging() ? 'DESC' : 'ASC');
} else {
return qsprintf(
$conn_r,
- 'ORDER BY %Q DESC',
- $this->getPagingColumn());
+ 'ORDER BY %Q %Q',
+ $this->getPagingColumn(),
+ $this->getReversePaging() ? 'ASC' : 'DESC');
}
}
final protected function processResults(array $results) {
if ($this->beforeID) {
$results = array_reverse($results, $preserve_keys = true);
}
return $results;
}
final public function executeWithCursorPager(AphrontCursorPagerView $pager) {
$this->setLimit($pager->getPageSize() + 1);
if ($pager->getAfterID()) {
$this->setAfterID($pager->getAfterID());
} else if ($pager->getBeforeID()) {
$this->setBeforeID($pager->getBeforeID());
}
$results = $this->execute();
$sliced_results = $pager->sliceResults($results);
if ($this->beforeID || (count($results) > $pager->getPageSize())) {
$pager->setNextPageID($this->getPagingValue(last($sliced_results)));
}
if ($this->afterID ||
($this->beforeID && (count($results) > $pager->getPageSize()))) {
$pager->setPrevPageID($this->getPagingValue(head($sliced_results)));
}
return $sliced_results;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 3, 4:13 PM (16 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
166015
Default Alt Text
(15 KB)

Event Timeline