Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/notification/query/PhabricatorNotificationQuery.php
12256 views
1
<?php
2
3
/**
4
* @task config Configuring the Query
5
* @task exec Query Execution
6
*/
7
final class PhabricatorNotificationQuery
8
extends PhabricatorCursorPagedPolicyAwareQuery {
9
10
private $userPHIDs;
11
private $keys;
12
private $unread;
13
14
15
/* -( Configuring the Query )---------------------------------------------- */
16
17
18
public function withUserPHIDs(array $user_phids) {
19
$this->userPHIDs = $user_phids;
20
return $this;
21
}
22
23
public function withKeys(array $keys) {
24
$this->keys = $keys;
25
return $this;
26
}
27
28
29
/**
30
* Filter results by read/unread status. Note that `true` means to return
31
* only unread notifications, while `false` means to return only //read//
32
* notifications. The default is `null`, which returns both.
33
*
34
* @param mixed True or false to filter results by read status. Null to remove
35
* the filter.
36
* @return this
37
* @task config
38
*/
39
public function withUnread($unread) {
40
$this->unread = $unread;
41
return $this;
42
}
43
44
45
/* -( Query Execution )---------------------------------------------------- */
46
47
48
protected function loadPage() {
49
$story_table = new PhabricatorFeedStoryData();
50
$notification_table = new PhabricatorFeedStoryNotification();
51
52
$conn = $story_table->establishConnection('r');
53
54
$data = queryfx_all(
55
$conn,
56
'SELECT story.*, notification.hasViewed FROM %R notification
57
JOIN %R story ON notification.chronologicalKey = story.chronologicalKey
58
%Q
59
ORDER BY notification.chronologicalKey DESC
60
%Q',
61
$notification_table,
62
$story_table,
63
$this->buildWhereClause($conn),
64
$this->buildLimitClause($conn));
65
66
return $data;
67
}
68
69
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
70
$where = parent::buildWhereClauseParts($conn);
71
72
if ($this->userPHIDs !== null) {
73
$where[] = qsprintf(
74
$conn,
75
'notification.userPHID IN (%Ls)',
76
$this->userPHIDs);
77
}
78
79
if ($this->unread !== null) {
80
$where[] = qsprintf(
81
$conn,
82
'notification.hasViewed = %d',
83
(int)!$this->unread);
84
}
85
86
if ($this->keys !== null) {
87
$where[] = qsprintf(
88
$conn,
89
'notification.chronologicalKey IN (%Ls)',
90
$this->keys);
91
}
92
93
return $where;
94
}
95
96
protected function willFilterPage(array $rows) {
97
// See T13623. The policy model here is outdated and awkward.
98
99
// Users may have notifications about objects they can no longer see.
100
// Two ways this can arise: destroy an object; or change an object's
101
// view policy to exclude a user.
102
103
// "PhabricatorFeedStory::loadAllFromRows()" does its own policy filtering.
104
// This doesn't align well with modern query sequencing, but we should be
105
// able to get away with it by loading here.
106
107
// See T13623. Although most queries for notifications return unique
108
// stories, this isn't a guarantee.
109
$story_map = ipull($rows, null, 'chronologicalKey');
110
111
$viewer = $this->getViewer();
112
$stories = PhabricatorFeedStory::loadAllFromRows($story_map, $viewer);
113
$stories = mpull($stories, null, 'getChronologicalKey');
114
115
$results = array();
116
foreach ($rows as $row) {
117
$story_key = $row['chronologicalKey'];
118
$has_viewed = $row['hasViewed'];
119
120
if (!isset($stories[$story_key])) {
121
// NOTE: We can't call "didRejectResult()" here because we don't have
122
// a policy object to pass.
123
continue;
124
}
125
126
$story = id(clone $stories[$story_key])
127
->setHasViewed($has_viewed);
128
129
if (!$story->isVisibleInNotifications()) {
130
continue;
131
}
132
133
$results[] = $story;
134
}
135
136
return $results;
137
}
138
139
protected function getDefaultOrderVector() {
140
return array('key');
141
}
142
143
public function getBuiltinOrders() {
144
return array(
145
'newest' => array(
146
'vector' => array('key'),
147
'name' => pht('Creation (Newest First)'),
148
'aliases' => array('created'),
149
),
150
'oldest' => array(
151
'vector' => array('-key'),
152
'name' => pht('Creation (Oldest First)'),
153
),
154
);
155
}
156
157
public function getOrderableColumns() {
158
return array(
159
'key' => array(
160
'table' => 'notification',
161
'column' => 'chronologicalKey',
162
'type' => 'string',
163
'unique' => true,
164
),
165
);
166
}
167
168
protected function applyExternalCursorConstraintsToQuery(
169
PhabricatorCursorPagedPolicyAwareQuery $subquery,
170
$cursor) {
171
172
$subquery
173
->withKeys(array($cursor))
174
->setLimit(1);
175
176
}
177
178
protected function newExternalCursorStringForResult($object) {
179
return $object->getChronologicalKey();
180
}
181
182
protected function newPagingMapFromPartialObject($object) {
183
return array(
184
'key' => $object['chronologicalKey'],
185
);
186
}
187
188
protected function getPrimaryTableAlias() {
189
return 'notification';
190
}
191
192
public function getQueryApplicationClass() {
193
return 'PhabricatorNotificationsApplication';
194
}
195
196
}
197
198