Path: blob/master/src/applications/notification/query/PhabricatorNotificationQuery.php
12256 views
<?php12/**3* @task config Configuring the Query4* @task exec Query Execution5*/6final class PhabricatorNotificationQuery7extends PhabricatorCursorPagedPolicyAwareQuery {89private $userPHIDs;10private $keys;11private $unread;121314/* -( Configuring the Query )---------------------------------------------- */151617public function withUserPHIDs(array $user_phids) {18$this->userPHIDs = $user_phids;19return $this;20}2122public function withKeys(array $keys) {23$this->keys = $keys;24return $this;25}262728/**29* Filter results by read/unread status. Note that `true` means to return30* only unread notifications, while `false` means to return only //read//31* notifications. The default is `null`, which returns both.32*33* @param mixed True or false to filter results by read status. Null to remove34* the filter.35* @return this36* @task config37*/38public function withUnread($unread) {39$this->unread = $unread;40return $this;41}424344/* -( Query Execution )---------------------------------------------------- */454647protected function loadPage() {48$story_table = new PhabricatorFeedStoryData();49$notification_table = new PhabricatorFeedStoryNotification();5051$conn = $story_table->establishConnection('r');5253$data = queryfx_all(54$conn,55'SELECT story.*, notification.hasViewed FROM %R notification56JOIN %R story ON notification.chronologicalKey = story.chronologicalKey57%Q58ORDER BY notification.chronologicalKey DESC59%Q',60$notification_table,61$story_table,62$this->buildWhereClause($conn),63$this->buildLimitClause($conn));6465return $data;66}6768protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {69$where = parent::buildWhereClauseParts($conn);7071if ($this->userPHIDs !== null) {72$where[] = qsprintf(73$conn,74'notification.userPHID IN (%Ls)',75$this->userPHIDs);76}7778if ($this->unread !== null) {79$where[] = qsprintf(80$conn,81'notification.hasViewed = %d',82(int)!$this->unread);83}8485if ($this->keys !== null) {86$where[] = qsprintf(87$conn,88'notification.chronologicalKey IN (%Ls)',89$this->keys);90}9192return $where;93}9495protected function willFilterPage(array $rows) {96// See T13623. The policy model here is outdated and awkward.9798// Users may have notifications about objects they can no longer see.99// Two ways this can arise: destroy an object; or change an object's100// view policy to exclude a user.101102// "PhabricatorFeedStory::loadAllFromRows()" does its own policy filtering.103// This doesn't align well with modern query sequencing, but we should be104// able to get away with it by loading here.105106// See T13623. Although most queries for notifications return unique107// stories, this isn't a guarantee.108$story_map = ipull($rows, null, 'chronologicalKey');109110$viewer = $this->getViewer();111$stories = PhabricatorFeedStory::loadAllFromRows($story_map, $viewer);112$stories = mpull($stories, null, 'getChronologicalKey');113114$results = array();115foreach ($rows as $row) {116$story_key = $row['chronologicalKey'];117$has_viewed = $row['hasViewed'];118119if (!isset($stories[$story_key])) {120// NOTE: We can't call "didRejectResult()" here because we don't have121// a policy object to pass.122continue;123}124125$story = id(clone $stories[$story_key])126->setHasViewed($has_viewed);127128if (!$story->isVisibleInNotifications()) {129continue;130}131132$results[] = $story;133}134135return $results;136}137138protected function getDefaultOrderVector() {139return array('key');140}141142public function getBuiltinOrders() {143return array(144'newest' => array(145'vector' => array('key'),146'name' => pht('Creation (Newest First)'),147'aliases' => array('created'),148),149'oldest' => array(150'vector' => array('-key'),151'name' => pht('Creation (Oldest First)'),152),153);154}155156public function getOrderableColumns() {157return array(158'key' => array(159'table' => 'notification',160'column' => 'chronologicalKey',161'type' => 'string',162'unique' => true,163),164);165}166167protected function applyExternalCursorConstraintsToQuery(168PhabricatorCursorPagedPolicyAwareQuery $subquery,169$cursor) {170171$subquery172->withKeys(array($cursor))173->setLimit(1);174175}176177protected function newExternalCursorStringForResult($object) {178return $object->getChronologicalKey();179}180181protected function newPagingMapFromPartialObject($object) {182return array(183'key' => $object['chronologicalKey'],184);185}186187protected function getPrimaryTableAlias() {188return 'notification';189}190191public function getQueryApplicationClass() {192return 'PhabricatorNotificationsApplication';193}194195}196197198