diff --git a/src/applications/feed/query/PhabricatorFeedQuery.php b/src/applications/feed/query/PhabricatorFeedQuery.php index 5adf65917..fc545373c 100644 --- a/src/applications/feed/query/PhabricatorFeedQuery.php +++ b/src/applications/feed/query/PhabricatorFeedQuery.php @@ -1,188 +1,184 @@ <?php final class PhabricatorFeedQuery extends PhabricatorCursorPagedPolicyAwareQuery { private $filterPHIDs; private $filterOutPHIDs; // c4science custo private $chronologicalKeys; private $rangeMin; private $rangeMax; public function withFilterPHIDs(array $phids) { $this->filterPHIDs = $phids; return $this; } public function withChronologicalKeys(array $keys) { $this->chronologicalKeys = $keys; return $this; } public function withEpochInRange($range_min, $range_max) { $this->rangeMin = $range_min; $this->rangeMax = $range_max; return $this; } public function newResultObject() { return new PhabricatorFeedStoryData(); } protected function loadPage() { // NOTE: We return raw rows from this method, which is a little unusual. return $this->loadStandardPageRows($this->newResultObject()); } protected function willFilterPage(array $data) { $stories = PhabricatorFeedStory::loadAllFromRows($data, $this->getViewer()); foreach ($stories as $key => $story) { if (!$story->isVisibleInFeed()) { unset($stories[$key]); } } return $stories; } protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { $joins = parent::buildJoinClauseParts($conn); // NOTE: We perform this join unconditionally (even if we have no filter // PHIDs) to omit rows which have no story references. These story data // rows are notifications or realtime alerts. $ref_table = new PhabricatorFeedStoryReference(); $joins[] = qsprintf( $conn, 'JOIN %T ref ON ref.chronologicalKey = story.chronologicalKey', $ref_table->getTableName()); return $joins; } protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); if ($this->filterPHIDs) { // c4science custo $where[] = qsprintf( $conn, 'ref.objectPHID IN (%Ls)', $this->filterPHIDs); } // C4science customization if ($this->filterOutPHIDs !== null) { $where[] = qsprintf( $conn, 'ref.objectPHID NOT IN (%Ls)', $this->filterOutPHIDs); } if ($this->chronologicalKeys !== null) { // NOTE: We can't use "%d" to format these large integers on 32-bit // systems. Historically, we formatted these into integers in an // awkward way because MySQL could sometimes (?) fail to use the proper // keys if the values were formatted as strings instead of integers. // After the "qsprintf()" update to use PhutilQueryString, we can no // longer do this in a sneaky way. However, the MySQL key issue also // no longer appears to reproduce across several systems. So: just use // strings until problems turn up? $where[] = qsprintf( $conn, 'ref.chronologicalKey IN (%Ls)', $this->chronologicalKeys); } // NOTE: We may not have 64-bit PHP, so do the shifts in MySQL instead. // From EXPLAIN, it appears like MySQL is smart enough to compute the // result and make use of keys to execute the query. if ($this->rangeMin !== null) { $where[] = qsprintf( $conn, 'ref.chronologicalKey >= (%d << 32)', $this->rangeMin); } if ($this->rangeMax !== null) { $where[] = qsprintf( $conn, 'ref.chronologicalKey < (%d << 32)', $this->rangeMax); } return $where; } protected function buildGroupClause(AphrontDatabaseConnection $conn) { if ($this->filterPHIDs !== null) { return qsprintf($conn, 'GROUP BY ref.chronologicalKey'); } else { return qsprintf($conn, 'GROUP BY story.chronologicalKey'); } } protected function getDefaultOrderVector() { return array('key'); } public function getBuiltinOrders() { return array( 'newest' => array( 'vector' => array('key'), 'name' => pht('Creation (Newest First)'), 'aliases' => array('created'), ), 'oldest' => array( 'vector' => array('-key'), 'name' => pht('Creation (Oldest First)'), ), ); } public function getOrderableColumns() { $table = ($this->filterPHIDs ? 'ref' : 'story'); return array( 'key' => array( 'table' => $table, 'column' => 'chronologicalKey', 'type' => 'string', 'unique' => true, ), ); } protected function applyExternalCursorConstraintsToQuery( PhabricatorCursorPagedPolicyAwareQuery $subquery, $cursor) { $subquery->withChronologicalKeys(array($cursor)); } protected function newExternalCursorStringForResult($object) { return $object->getChronologicalKey(); } protected function newPagingMapFromPartialObject($object) { // This query is unusual, and the "object" is a raw result row. return array( 'key' => $object['chronologicalKey'], ); } protected function getPrimaryTableAlias() { return 'story'; } - protected function getPrimaryTableAlias() { - return 'story'; - } - public function getQueryApplicationClass() { return 'PhabricatorFeedApplication'; } } diff --git a/src/applications/fund/storage/FundBackerTransaction.php b/src/applications/fund/storage/FundBackerTransaction.php index abaf585ae..c08958a29 100644 --- a/src/applications/fund/storage/FundBackerTransaction.php +++ b/src/applications/fund/storage/FundBackerTransaction.php @@ -1,22 +1,18 @@ <?php final class FundBackerTransaction extends PhabricatorModularTransaction { public function getApplicationName() { return 'fund'; } public function getApplicationTransactionType() { return FundBackerPHIDType::TYPECONST; } public function getBaseTransactionClass() { return 'FundBackerTransactionType'; } - public function getBaseTransactionClass() { - return 'FundBackerTransactionType'; - } - } diff --git a/src/applications/people/storage/PhabricatorUserTransaction.php b/src/applications/people/storage/PhabricatorUserTransaction.php index 01d94b9fa..81ca52a13 100644 --- a/src/applications/people/storage/PhabricatorUserTransaction.php +++ b/src/applications/people/storage/PhabricatorUserTransaction.php @@ -1,22 +1,18 @@ <?php final class PhabricatorUserTransaction extends PhabricatorModularTransaction { public function getApplicationName() { return 'user'; } public function getApplicationTransactionType() { return PhabricatorPeopleUserPHIDType::TYPECONST; } public function getBaseTransactionClass() { return 'PhabricatorUserTransactionType'; } - public function getBaseTransactionClass() { - return 'PhabricatorUserTransactionType'; - } - } diff --git a/src/applications/project/controller/PhabricatorProjectController.php b/src/applications/project/controller/PhabricatorProjectController.php index 97e0ec9aa..63494bf44 100644 --- a/src/applications/project/controller/PhabricatorProjectController.php +++ b/src/applications/project/controller/PhabricatorProjectController.php @@ -1,218 +1,210 @@ <?php abstract class PhabricatorProjectController extends PhabricatorController { private $project; private $profileMenu; private $profileMenuEngine; protected function setProject(PhabricatorProject $project) { $this->project = $project; return $this; } protected function getProject() { return $this->project; } protected function loadProject() { $viewer = $this->getViewer(); $request = $this->getRequest(); $id = nonempty( $request->getURIData('projectID'), $request->getURIData('id')); $slug = $request->getURIData('slug'); if ($slug) { $normal_slug = PhabricatorSlug::normalizeProjectSlug($slug); $is_abnormal = ($slug !== $normal_slug); $normal_uri = "/tag/{$normal_slug}/"; } else { $is_abnormal = false; } $query = id(new PhabricatorProjectQuery()) ->setViewer($viewer) ->needMembers(true) ->needWatchers(true) ->needImages(true) ->needSlugs(true); if ($slug) { $query->withSlugs(array($slug)); } else { $query->withIDs(array($id)); } $policy_exception = null; try { $project = $query->executeOne(); } catch (PhabricatorPolicyException $ex) { $policy_exception = $ex; $project = null; } if (!$project) { // This project legitimately does not exist, so just 404 the user. if (!$policy_exception) { return new Aphront404Response(); } // Here, the project exists but the user can't see it. If they are // using a non-canonical slug to view the project, redirect to the // canonical slug. If they're already using the canonical slug, rethrow // the exception to give them the policy error. if ($is_abnormal) { return id(new AphrontRedirectResponse())->setURI($normal_uri); } else { throw $policy_exception; } } // The user can view the project, but is using a noncanonical slug. // Redirect to the canonical slug. $primary_slug = $project->getPrimarySlug(); if ($slug && ($slug !== $primary_slug)) { $primary_uri = "/tag/{$primary_slug}/"; return id(new AphrontRedirectResponse())->setURI($primary_uri); } $this->setProject($project); return null; } public function buildApplicationMenu() { $menu = $this->newApplicationMenu(); $profile_menu = $this->getProfileMenu(); if ($profile_menu) { $menu->setProfileMenu($profile_menu); } $menu->setSearchEngine(new PhabricatorProjectSearchEngine()); return $menu; } protected function getProfileMenu() { if (!$this->profileMenu) { $engine = $this->getProfileMenuEngine(); if ($engine) { $this->profileMenu = $engine->buildNavigation(); } } return $this->profileMenu; } protected function buildApplicationCrumbs() { return $this->newApplicationCrumbs('profile'); } protected function newWorkboardCrumbs() { return $this->newApplicationCrumbs('workboard'); } private function newApplicationCrumbs($mode) { $crumbs = parent::buildApplicationCrumbs(); $project = $this->getProject(); if ($project) { $ancestors = $project->getAncestorProjects(); $ancestors = array_reverse($ancestors); $ancestors[] = $project; foreach ($ancestors as $ancestor) { if ($ancestor->getPHID() === $project->getPHID()) { // Link the current project's crumb to its profile no matter what, // since we're already on the right context page for it and linking // to the current page isn't helpful. $crumb_uri = $ancestor->getProfileURI(); } else { switch ($mode) { case 'workboard': $crumb_uri = $ancestor->getWorkboardURI(); break; case 'profile': default: $crumb_uri = $ancestor->getProfileURI(); break; } } $crumbs->addTextCrumb($ancestor->getName(), $crumb_uri); } } return $crumbs; } protected function getProfileMenuEngine() { if (!$this->profileMenuEngine) { $viewer = $this->getViewer(); $project = $this->getProject(); if ($project) { $engine = id(new PhabricatorProjectProfileMenuEngine()) ->setViewer($viewer) ->setController($this) ->setProfileObject($project); $this->profileMenuEngine = $engine; } } return $this->profileMenuEngine; } protected function setProfileMenuEngine( PhabricatorProjectProfileMenuEngine $engine) { $this->profileMenuEngine = $engine; return $this; } protected function newCardResponse( $board_phid, $object_phid, PhabricatorProjectColumnOrder $ordering = null, $sounds = array()) { $viewer = $this->getViewer(); $request = $this->getRequest(); $visible_phids = $request->getStrList('visiblePHIDs'); if (!$visible_phids) { $visible_phids = array(); } $engine = id(new PhabricatorBoardResponseEngine()) ->setViewer($viewer) ->setBoardPHID($board_phid) ->setObjectPHID($object_phid) ->setVisiblePHIDs($visible_phids) ->setSounds($sounds); if ($ordering) { $engine->setOrdering($ordering); } return $engine->buildResponse(); } public function renderHashtags(array $tags) { $result = array(); foreach ($tags as $key => $tag) { $result[] = '#'.$tag; } return implode(', ', $result); } - public function renderHashtags(array $tags) { - $result = array(); - foreach ($tags as $key => $tag) { - $result[] = '#'.$tag; - } - return implode(', ', $result); - } - }