MediaWiki  1.23.1
WatchedItem.php
Go to the documentation of this file.
1 <?php
29 class WatchedItem {
35  const IGNORE_USER_RIGHTS = 0;
36 
42  const CHECK_USER_RIGHTS = 1;
43 
45  private $loaded = false, $watched, $timestamp;
46 
56  public static function fromUserTitle( $user, $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
57  $wl = new WatchedItem;
58  $wl->mUser = $user;
59  $wl->mTitle = $title;
60  $wl->mCheckRights = $checkRights;
61 
62  return $wl;
63  }
64 
69  protected function getTitle() {
70  return $this->mTitle;
71  }
72 
77  protected function getTitleNs() {
78  return $this->getTitle()->getNamespace();
79  }
80 
85  protected function getTitleDBkey() {
86  return $this->getTitle()->getDBkey();
87  }
88 
93  protected function getUserId() {
94  return $this->mUser->getId();
95  }
96 
103  private function dbCond() {
104  return array(
105  'wl_user' => $this->getUserId(),
106  'wl_namespace' => $this->getTitleNs(),
107  'wl_title' => $this->getTitleDBkey(),
108  );
109  }
110 
114  private function load() {
115  if ( $this->loaded ) {
116  return;
117  }
118  $this->loaded = true;
119 
120  // Only loggedin user can have a watchlist
121  if ( $this->mUser->isAnon() ) {
122  $this->watched = false;
123  return;
124  }
125 
126  // some pages cannot be watched
127  if ( !$this->getTitle()->isWatchable() ) {
128  $this->watched = false;
129  return;
130  }
131 
132  # Pages and their talk pages are considered equivalent for watching;
133  # remember that talk namespaces are numbered as page namespace+1.
134 
135  $dbr = wfGetDB( DB_SLAVE );
136  $row = $dbr->selectRow( 'watchlist', 'wl_notificationtimestamp',
137  $this->dbCond(), __METHOD__ );
138 
139  if ( $row === false ) {
140  $this->watched = false;
141  } else {
142  $this->watched = true;
143  $this->timestamp = $row->wl_notificationtimestamp;
144  }
145  }
146 
151  private function isAllowed( $what ) {
152  return !$this->mCheckRights || $this->mUser->isAllowed( $what );
153  }
154 
159  public function isWatched() {
160  if ( !$this->isAllowed( 'viewmywatchlist' ) ) {
161  return false;
162  }
163 
164  $this->load();
165  return $this->watched;
166  }
167 
174  public function getNotificationTimestamp() {
175  if ( !$this->isAllowed( 'viewmywatchlist' ) ) {
176  return false;
177  }
178 
179  $this->load();
180  if ( $this->watched ) {
181  return $this->timestamp;
182  } else {
183  return false;
184  }
185  }
186 
194  public function resetNotificationTimestamp( $force = '', $oldid = 0 ) {
195  // Only loggedin user can have a watchlist
196  if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) {
197  return;
198  }
199 
200  if ( $force != 'force' ) {
201  $this->load();
202  if ( !$this->watched || $this->timestamp === null ) {
203  return;
204  }
205  }
206 
207  $title = $this->getTitle();
208  if ( !$oldid ) {
209  // No oldid given, assuming latest revision; clear the timestamp.
210  $notificationTimestamp = null;
211  } elseif ( !$title->getNextRevisionID( $oldid ) ) {
212  // Oldid given and is the latest revision for this title; clear the timestamp.
213  $notificationTimestamp = null;
214  } else {
215  // See if the version marked as read is more recent than the one we're viewing.
216  // Call load() if it wasn't called before due to $force.
217  $this->load();
218 
219  if ( $this->timestamp === null ) {
220  // This can only happen if $force is enabled.
221  $notificationTimestamp = null;
222  } else {
223  // Oldid given and isn't the latest; update the timestamp.
224  // This will result in no further notification emails being sent!
225  $dbr = wfGetDB( DB_SLAVE );
226  $notificationTimestamp = $dbr->selectField(
227  'revision', 'rev_timestamp',
228  array( 'rev_page' => $title->getArticleID(), 'rev_id' => $oldid )
229  );
230  // We need to go one second to the future because of various strict comparisons
231  // throughout the codebase
232  $ts = new MWTimestamp( $notificationTimestamp );
233  $ts->timestamp->add( new DateInterval( 'PT1S' ) );
234  $notificationTimestamp = $ts->getTimestamp( TS_MW );
235 
236  if ( $notificationTimestamp < $this->timestamp ) {
237  if ( $force != 'force' ) {
238  return;
239  } else {
240  // This is a little silly…
241  $notificationTimestamp = $this->timestamp;
242  }
243  }
244  }
245  }
246 
247  // If the page is watched by the user (or may be watched), update the timestamp on any
248  // any matching rows
249  $dbw = wfGetDB( DB_MASTER );
250  $dbw->update( 'watchlist', array( 'wl_notificationtimestamp' => $notificationTimestamp ),
251  $this->dbCond(), __METHOD__ );
252  $this->timestamp = null;
253  }
254 
260  public function addWatch() {
261  wfProfileIn( __METHOD__ );
262 
263  // Only loggedin user can have a watchlist
264  if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) {
265  wfProfileOut( __METHOD__ );
266  return false;
267  }
268 
269  // Use INSERT IGNORE to avoid overwriting the notification timestamp
270  // if there's already an entry for this page
271  $dbw = wfGetDB( DB_MASTER );
272  $dbw->insert( 'watchlist',
273  array(
274  'wl_user' => $this->getUserId(),
275  'wl_namespace' => MWNamespace::getSubject( $this->getTitleNs() ),
276  'wl_title' => $this->getTitleDBkey(),
277  'wl_notificationtimestamp' => null
278  ), __METHOD__, 'IGNORE' );
279 
280  // Every single watched page needs now to be listed in watchlist;
281  // namespace:page and namespace_talk:page need separate entries:
282  $dbw->insert( 'watchlist',
283  array(
284  'wl_user' => $this->getUserId(),
285  'wl_namespace' => MWNamespace::getTalk( $this->getTitleNs() ),
286  'wl_title' => $this->getTitleDBkey(),
287  'wl_notificationtimestamp' => null
288  ), __METHOD__, 'IGNORE' );
289 
290  $this->watched = true;
291 
292  wfProfileOut( __METHOD__ );
293  return true;
294  }
295 
300  public function removeWatch() {
301  wfProfileIn( __METHOD__ );
302 
303  // Only loggedin user can have a watchlist
304  if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) {
305  wfProfileOut( __METHOD__ );
306  return false;
307  }
308 
309  $success = false;
310  $dbw = wfGetDB( DB_MASTER );
311  $dbw->delete( 'watchlist',
312  array(
313  'wl_user' => $this->getUserId(),
314  'wl_namespace' => MWNamespace::getSubject( $this->getTitleNs() ),
315  'wl_title' => $this->getTitleDBkey(),
316  ), __METHOD__
317  );
318  if ( $dbw->affectedRows() ) {
319  $success = true;
320  }
321 
322  # the following code compensates the new behavior, introduced by the
323  # enotif patch, that every single watched page needs now to be listed
324  # in watchlist namespace:page and namespace_talk:page had separate
325  # entries: clear them
326  $dbw->delete( 'watchlist',
327  array(
328  'wl_user' => $this->getUserId(),
329  'wl_namespace' => MWNamespace::getTalk( $this->getTitleNs() ),
330  'wl_title' => $this->getTitleDBkey(),
331  ), __METHOD__
332  );
333 
334  if ( $dbw->affectedRows() ) {
335  $success = true;
336  }
337 
338  $this->watched = false;
339 
340  wfProfileOut( __METHOD__ );
341  return $success;
342  }
343 
351  public static function duplicateEntries( $ot, $nt ) {
352  WatchedItem::doDuplicateEntries( $ot->getSubjectPage(), $nt->getSubjectPage() );
353  WatchedItem::doDuplicateEntries( $ot->getTalkPage(), $nt->getTalkPage() );
354  }
355 
364  private static function doDuplicateEntries( $ot, $nt ) {
365  $oldnamespace = $ot->getNamespace();
366  $newnamespace = $nt->getNamespace();
367  $oldtitle = $ot->getDBkey();
368  $newtitle = $nt->getDBkey();
369 
370  $dbw = wfGetDB( DB_MASTER );
371  $res = $dbw->select( 'watchlist', 'wl_user',
372  array( 'wl_namespace' => $oldnamespace, 'wl_title' => $oldtitle ),
373  __METHOD__, 'FOR UPDATE'
374  );
375  # Construct array to replace into the watchlist
376  $values = array();
377  foreach ( $res as $s ) {
378  $values[] = array(
379  'wl_user' => $s->wl_user,
380  'wl_namespace' => $newnamespace,
381  'wl_title' => $newtitle
382  );
383  }
384 
385  if ( empty( $values ) ) {
386  // Nothing to do
387  return true;
388  }
389 
390  # Perform replace
391  # Note that multi-row replace is very efficient for MySQL but may be inefficient for
392  # some other DBMSes, mostly due to poor simulation by us
393  $dbw->replace( 'watchlist', array( array( 'wl_user', 'wl_namespace', 'wl_title' ) ), $values, __METHOD__ );
394  return true;
395  }
396 }
MWTimestamp
Library for creating and parsing MW-style timestamps.
Definition: MWTimestamp.php:31
DB_MASTER
const DB_MASTER
Definition: Defines.php:56
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
WatchedItem\isWatched
isWatched()
Is mTitle being watched by mUser?
Definition: WatchedItem.php:159
wfGetDB
& wfGetDB( $db, $groups=array(), $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3650
wfProfileIn
wfProfileIn( $functionname)
Begin profiling of a function.
Definition: Profiler.php:33
wfReadOnly
wfReadOnly()
Check whether the wiki is in read-only mode.
Definition: GlobalFunctions.php:1313
WatchedItem\removeWatch
removeWatch()
Same as addWatch, only the opposite.
Definition: WatchedItem.php:300
$s
$s
Definition: mergeMessageFileList.php:156
WatchedItem\getTitle
getTitle()
Title being watched.
Definition: WatchedItem.php:69
$dbr
$dbr
Definition: testCompression.php:48
WatchedItem\$loaded
$loaded
Definition: WatchedItem.php:45
$success
$success
Definition: Utf8Test.php:91
WatchedItem\fromUserTitle
static fromUserTitle( $user, $title, $checkRights=WatchedItem::CHECK_USER_RIGHTS)
Create a WatchedItem object with the given user and title.
Definition: WatchedItem.php:56
WatchedItem\$mCheckRights
$mCheckRights
Definition: WatchedItem.php:44
WatchedItem\IGNORE_USER_RIGHTS
const IGNORE_USER_RIGHTS
Constant to specify that user rights 'editmywatchlist' and 'viewmywatchlist' should not be checked.
Definition: WatchedItem.php:35
wfProfileOut
wfProfileOut( $functionname='missing')
Stop profiling of a function.
Definition: Profiler.php:46
WatchedItem\duplicateEntries
static duplicateEntries( $ot, $nt)
Check if the given title already is watched by the user, and if so add watches on a new title.
Definition: WatchedItem.php:351
WatchedItem\$mUser
$mUser
Definition: WatchedItem.php:44
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
WatchedItem\load
load()
Load the object from the database.
Definition: WatchedItem.php:114
WatchedItem\dbCond
dbCond()
Return an array of conditions to select or update the appropriate database row.
Definition: WatchedItem.php:103
TS_MW
const TS_MW
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
Definition: GlobalFunctions.php:2431
$title
presenting them properly to the user as errors is done by the caller $title
Definition: hooks.txt:1324
WatchedItem\getUserId
getUserId()
Helper to retrieve the user id.
Definition: WatchedItem.php:93
WatchedItem
Representation of a pair of user and title for watchlist entries.
Definition: WatchedItem.php:29
WatchedItem\CHECK_USER_RIGHTS
const CHECK_USER_RIGHTS
Constant to specify that user rights 'editmywatchlist' and 'viewmywatchlist' should be checked.
Definition: WatchedItem.php:42
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:237
WatchedItem\resetNotificationTimestamp
resetNotificationTimestamp( $force='', $oldid=0)
Reset the notification timestamp of this entry.
Definition: WatchedItem.php:194
DB_SLAVE
const DB_SLAVE
Definition: Defines.php:55
WatchedItem\$watched
$watched
Definition: WatchedItem.php:45
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
WatchedItem\addWatch
addWatch()
Given a title and user (assumes the object is setup), add the watch to the database.
Definition: WatchedItem.php:260
WatchedItem\getNotificationTimestamp
getNotificationTimestamp()
Get the notification timestamp of this entry.
Definition: WatchedItem.php:174
WatchedItem\getTitleDBkey
getTitleDBkey()
Helper to retrieve the title DBkey.
Definition: WatchedItem.php:85
WatchedItem\$timestamp
$timestamp
Definition: WatchedItem.php:45
MWNamespace\getTalk
static getTalk( $index)
Get the talk namespace index for a given namespace.
Definition: Namespace.php:118
MWNamespace\getSubject
static getSubject( $index)
Get the subject namespace index for a given namespace Special namespaces (NS_MEDIA,...
Definition: Namespace.php:132
WatchedItem\getTitleNs
getTitleNs()
Helper to retrieve the title namespace.
Definition: WatchedItem.php:77
$res
$res
Definition: database.txt:21
WatchedItem\$mTitle
$mTitle
Definition: WatchedItem.php:44
WatchedItem\isAllowed
isAllowed( $what)
Check permissions.
Definition: WatchedItem.php:151
WatchedItem\doDuplicateEntries
static doDuplicateEntries( $ot, $nt)
Handle duplicate entries.
Definition: WatchedItem.php:364