MediaWiki  master
TalkPageNotificationManager.php
Go to the documentation of this file.
1 <?php
2 
22 namespace MediaWiki\User;
23 
27 use MWTimestamp;
28 use ReadOnlyMode;
30 
36 
37  public const CONSTRUCTOR_OPTIONS = [
38  'DisableAnonTalk'
39  ];
40 
42  private $userMessagesCache = [];
43 
46 
48  private $loadBalancer;
49 
51  private $readOnlyMode;
52 
54  private $revisionLookup;
55 
62  public function __construct(
63  ServiceOptions $serviceOptions,
67  ) {
68  $serviceOptions->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
69  $this->disableAnonTalk = $serviceOptions->get( 'DisableAnonTalk' );
70  $this->loadBalancer = $loadBalancer;
71  $this->readOnlyMode = $readOnlyMode;
72  $this->revisionLookup = $revisionLookup;
73  }
74 
80  public function userHasNewMessages( UserIdentity $user ) : bool {
81  $userKey = $this->getCacheKey( $user );
82 
83  // Load the newtalk status if it is unloaded
84  if ( !isset( $this->userMessagesCache[$userKey] ) ) {
85  if ( $this->isTalkDisabled( $user ) ) {
86  // Anon disabled by configuration.
87  $this->userMessagesCache[$userKey] = false;
88  } else {
89  $this->userMessagesCache[$userKey] = $this->dbCheckNewUserMessages( $user );
90  }
91  }
92 
93  return (bool)$this->userMessagesCache[$userKey];
94  }
95 
104  public function setUserHasNewMessages(
105  UserIdentity $user,
106  RevisionRecord $curRev = null
107  ) : void {
108  if ( $this->isTalkDisabled( $user ) ) {
109  return;
110  }
111 
112  $userKey = $this->getCacheKey( $user );
113  $this->userMessagesCache[$userKey] = true;
114  $this->dbUpdateNewUserMessages( $user, $curRev );
115  }
116 
121  public function removeUserHasNewMessages( UserIdentity $user ) : void {
122  if ( $this->isTalkDisabled( $user ) ) {
123  return;
124  }
125 
126  $userKey = $this->getCacheKey( $user );
127  $this->userMessagesCache[$userKey] = false;
128 
129  $this->dbDeleteNewUserMessages( $user );
130  }
131 
140  public function getLatestSeenMessageTimestamp( UserIdentity $user ) : ?string {
141  $userKey = $this->getCacheKey( $user );
142  // Don't use self::userHasNewMessages here to avoid an extra DB query
143  // in case the value is not cached already
144  if ( $this->isTalkDisabled( $user ) ||
145  isset( $this->userMessagesCache[$userKey] ) && !$this->userMessagesCache[$userKey]
146  ) {
147  return null;
148  }
149 
150  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
151  list( $field, $id ) = $this->getQueryFieldAndId( $user );
152  // Get the "last viewed rev" timestamp from the oldest message notification
153  $timestamp = $dbr->selectField(
154  'user_newtalk',
155  'MIN(user_last_timestamp)',
156  [ $field => $id ],
157  __METHOD__
158  );
159  if ( $timestamp ) {
160  // TODO: Once passing 'null' as Revision setUserHasNewMessages is removed,
161  // null $timestamp would mean no new messages, so negatives can be cached too.
162  $this->userMessagesCache[$userKey] = true;
163  }
164  return $timestamp !== null ? MWTimestamp::convert( TS_MW, $timestamp ) : null;
165  }
166 
172  public function clearInstanceCache( UserIdentity $user ) : void {
173  $userKey = $this->getCacheKey( $user );
174  $this->userMessagesCache[$userKey] = null;
175  }
176 
182  private function isTalkDisabled( UserIdentity $user ) : bool {
183  return !$user->isRegistered() && $this->disableAnonTalk;
184  }
185 
191  private function dbCheckNewUserMessages( UserIdentity $user ) : bool {
192  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
193  list( $field, $id ) = $this->getQueryFieldAndId( $user );
194  $ok = $dbr->selectField(
195  'user_newtalk',
196  $field,
197  [ $field => $id ],
198  __METHOD__
199  );
200  return (bool)$ok;
201  }
202 
210  private function dbUpdateNewUserMessages(
211  UserIdentity $user,
212  RevisionRecord $curRev = null
213  ) : bool {
214  if ( $this->readOnlyMode->isReadOnly() ) {
215  return false;
216  }
217 
218  if ( $curRev ) {
219  $prevRev = $this->revisionLookup->getPreviousRevision( $curRev );
220  $ts = $prevRev ? $prevRev->getTimestamp() : null;
221  } else {
222  $ts = null;
223  }
224 
225  // Mark the user as having new messages since this revision
226  $dbw = $this->loadBalancer->getConnectionRef( DB_MASTER );
227  list( $field, $id ) = $this->getQueryFieldAndId( $user );
228  $dbw->insert(
229  'user_newtalk',
230  [
231  $field => $id,
232  'user_last_timestamp' => $dbw->timestampOrNull( $ts )
233  ],
234  __METHOD__,
235  [ 'IGNORE' ]
236  );
237  return (bool)$dbw->affectedRows();
238  }
239 
245  private function dbDeleteNewUserMessages( UserIdentity $user ) : bool {
246  if ( $this->readOnlyMode->isReadOnly() ) {
247  return false;
248  }
249  $dbw = $this->loadBalancer->getConnectionRef( DB_MASTER );
250  list( $field, $id ) = $this->getQueryFieldAndId( $user );
251  $dbw->delete(
252  'user_newtalk',
253  [ $field => $id ],
254  __METHOD__
255  );
256  return (bool)$dbw->affectedRows();
257  }
258 
264  private function getQueryFieldAndId( UserIdentity $user ) : array {
265  if ( $user->isRegistered() ) {
266  $field = 'user_id';
267  $id = $user->getId();
268  } else {
269  $field = 'user_ip';
270  $id = $user->getName();
271  }
272  return [ $field, $id ];
273  }
274 
280  private function getCacheKey( UserIdentity $user ) : string {
281  return $user->isRegistered() ? "u:{$user->getId()}" : "anon:{$user->getName()}";
282  }
283 }
MWTimestamp
Library for creating and parsing MW-style timestamps.
Definition: MWTimestamp.php:32
MediaWiki\User\TalkPageNotificationManager\CONSTRUCTOR_OPTIONS
const CONSTRUCTOR_OPTIONS
Definition: TalkPageNotificationManager.php:37
Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:46
MediaWiki\User\TalkPageNotificationManager\$loadBalancer
ILoadBalancer $loadBalancer
Definition: TalkPageNotificationManager.php:48
MediaWiki\User\TalkPageNotificationManager\isTalkDisabled
isTalkDisabled(UserIdentity $user)
Check whether the talk page is disabled for a user.
Definition: TalkPageNotificationManager.php:182
ReadOnlyMode
A service class for fetching the wiki's current read-only mode.
Definition: ReadOnlyMode.php:11
MediaWiki\User\TalkPageNotificationManager\removeUserHasNewMessages
removeUserHasNewMessages(UserIdentity $user)
Remove the new messages status.
Definition: TalkPageNotificationManager.php:121
MediaWiki\User\TalkPageNotificationManager\__construct
__construct(ServiceOptions $serviceOptions, ILoadBalancer $loadBalancer, ReadOnlyMode $readOnlyMode, RevisionLookup $revisionLookup)
Definition: TalkPageNotificationManager.php:62
MediaWiki\User\UserIdentity
Interface for objects representing user identity.
Definition: UserIdentity.php:32
Revision\RevisionLookup
Service for looking up page revisions.
Definition: RevisionLookup.php:38
MediaWiki\User\TalkPageNotificationManager
Manages user talk page notifications.
Definition: TalkPageNotificationManager.php:35
$dbr
$dbr
Definition: testCompression.php:54
MediaWiki\User\TalkPageNotificationManager\dbDeleteNewUserMessages
dbDeleteNewUserMessages(UserIdentity $user)
Clear the new messages flag for the given user.
Definition: TalkPageNotificationManager.php:245
MediaWiki\User\TalkPageNotificationManager\setUserHasNewMessages
setUserHasNewMessages(UserIdentity $user, RevisionRecord $curRev=null)
Update the talk page messages status.
Definition: TalkPageNotificationManager.php:104
MediaWiki\User\TalkPageNotificationManager\getCacheKey
getCacheKey(UserIdentity $user)
Gets a unique key for various caches.
Definition: TalkPageNotificationManager.php:280
MediaWiki\Config\ServiceOptions
A class for passing options to services.
Definition: ServiceOptions.php:25
MediaWiki\User\TalkPageNotificationManager\$userMessagesCache
array $userMessagesCache
Definition: TalkPageNotificationManager.php:42
MediaWiki\User\UserIdentity\isRegistered
isRegistered()
MediaWiki\User\TalkPageNotificationManager\$revisionLookup
RevisionLookup $revisionLookup
Definition: TalkPageNotificationManager.php:54
MediaWiki\User\TalkPageNotificationManager\getQueryFieldAndId
getQueryFieldAndId(UserIdentity $user)
Get the field name and id for the user_newtalk table query.
Definition: TalkPageNotificationManager.php:264
MediaWiki\User\TalkPageNotificationManager\dbUpdateNewUserMessages
dbUpdateNewUserMessages(UserIdentity $user, RevisionRecord $curRev=null)
Add or update the new messages flag.
Definition: TalkPageNotificationManager.php:210
MediaWiki\User\UserIdentity\getName
getName()
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
DB_MASTER
const DB_MASTER
Definition: defines.php:26
MediaWiki\User
Definition: DefaultOptionsLookup.php:21
MediaWiki\User\TalkPageNotificationManager\dbCheckNewUserMessages
dbCheckNewUserMessages(UserIdentity $user)
Internal uncached check for new messages.
Definition: TalkPageNotificationManager.php:191
MediaWiki\User\TalkPageNotificationManager\clearInstanceCache
clearInstanceCache(UserIdentity $user)
Remove the cached newtalk status for the given user.
Definition: TalkPageNotificationManager.php:172
MediaWiki\User\TalkPageNotificationManager\$disableAnonTalk
bool $disableAnonTalk
Definition: TalkPageNotificationManager.php:45
MediaWiki\User\TalkPageNotificationManager\userHasNewMessages
userHasNewMessages(UserIdentity $user)
Check if the user has new messages.
Definition: TalkPageNotificationManager.php:80
MediaWiki\User\UserIdentity\getId
getId()
MediaWiki\User\TalkPageNotificationManager\$readOnlyMode
ReadOnlyMode $readOnlyMode
Definition: TalkPageNotificationManager.php:51
MediaWiki\Config\ServiceOptions\get
get( $key)
Definition: ServiceOptions.php:84
MediaWiki\User\TalkPageNotificationManager\getLatestSeenMessageTimestamp
getLatestSeenMessageTimestamp(UserIdentity $user)
Returns the timestamp of the latest revision of the user talkpage that the user has already seen in T...
Definition: TalkPageNotificationManager.php:140
Wikimedia\Rdbms\ILoadBalancer
Database cluster connection, tracking, load balancing, and transaction manager interface.
Definition: ILoadBalancer.php:81
MediaWiki\Config\ServiceOptions\assertRequiredOptions
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
Definition: ServiceOptions.php:62