WatchedItem.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. <?php
  2. /**
  3. * @file
  4. * @ingroup Watchlist
  5. */
  6. /**
  7. * @ingroup Watchlist
  8. */
  9. class WatchedItem {
  10. var $mTitle, $mUser, $id, $ns, $ti;
  11. /**
  12. * Create a WatchedItem object with the given user and title
  13. * @param $user User: the user to use for (un)watching
  14. * @param $title Title: the title we're going to (un)watch
  15. * @return WatchedItem object
  16. */
  17. public static function fromUserTitle( $user, $title ) {
  18. $wl = new WatchedItem;
  19. $wl->mUser = $user;
  20. $wl->mTitle = $title;
  21. $wl->id = $user->getId();
  22. # Patch (also) for email notification on page changes T.Gries/M.Arndt 11.09.2004
  23. # TG patch: here we do not consider pages and their talk pages equivalent - why should we ?
  24. # The change results in talk-pages not automatically included in watchlists, when their parent page is included
  25. # $wl->ns = $title->getNamespace() & ~1;
  26. $wl->ns = $title->getNamespace();
  27. $wl->ti = $title->getDBkey();
  28. return $wl;
  29. }
  30. /**
  31. * Is mTitle being watched by mUser?
  32. * @return bool
  33. */
  34. public function isWatched() {
  35. # Pages and their talk pages are considered equivalent for watching;
  36. # remember that talk namespaces are numbered as page namespace+1.
  37. $dbr = wfGetDB( DB_SLAVE );
  38. $res = $dbr->select( 'watchlist', 1, array( 'wl_user' => $this->id, 'wl_namespace' => $this->ns,
  39. 'wl_title' => $this->ti ), __METHOD__ );
  40. $iswatched = ($dbr->numRows( $res ) > 0) ? 1 : 0;
  41. return $iswatched;
  42. }
  43. /**
  44. * Given a title and user (assumes the object is setup), add the watch to the
  45. * database.
  46. * @return bool (always true)
  47. */
  48. public function addWatch() {
  49. wfProfileIn( __METHOD__ );
  50. // Use INSERT IGNORE to avoid overwriting the notification timestamp
  51. // if there's already an entry for this page
  52. $dbw = wfGetDB( DB_MASTER );
  53. $dbw->insert( 'watchlist',
  54. array(
  55. 'wl_user' => $this->id,
  56. 'wl_namespace' => MWNamespace::getSubject($this->ns),
  57. 'wl_title' => $this->ti,
  58. 'wl_notificationtimestamp' => NULL
  59. ), __METHOD__, 'IGNORE' );
  60. // Every single watched page needs now to be listed in watchlist;
  61. // namespace:page and namespace_talk:page need separate entries:
  62. $dbw->insert( 'watchlist',
  63. array(
  64. 'wl_user' => $this->id,
  65. 'wl_namespace' => MWNamespace::getTalk($this->ns),
  66. 'wl_title' => $this->ti,
  67. 'wl_notificationtimestamp' => NULL
  68. ), __METHOD__, 'IGNORE' );
  69. wfProfileOut( __METHOD__ );
  70. return true;
  71. }
  72. /**
  73. * Same as addWatch, only the opposite.
  74. * @return bool
  75. */
  76. public function removeWatch() {
  77. $success = false;
  78. $dbw = wfGetDB( DB_MASTER );
  79. $dbw->delete( 'watchlist',
  80. array(
  81. 'wl_user' => $this->id,
  82. 'wl_namespace' => MWNamespace::getSubject($this->ns),
  83. 'wl_title' => $this->ti
  84. ), __METHOD__
  85. );
  86. if ( $dbw->affectedRows() ) {
  87. $success = true;
  88. }
  89. # the following code compensates the new behaviour, introduced by the
  90. # enotif patch, that every single watched page needs now to be listed
  91. # in watchlist namespace:page and namespace_talk:page had separate
  92. # entries: clear them
  93. $dbw->delete( 'watchlist',
  94. array(
  95. 'wl_user' => $this->id,
  96. 'wl_namespace' => MWNamespace::getTalk($this->ns),
  97. 'wl_title' => $this->ti
  98. ), __METHOD__
  99. );
  100. if ( $dbw->affectedRows() ) {
  101. $success = true;
  102. }
  103. return $success;
  104. }
  105. /**
  106. * Check if the given title already is watched by the user, and if so
  107. * add watches on a new title. To be used for page renames and such.
  108. *
  109. * @param $ot Title: page title to duplicate entries from, if present
  110. * @param $nt Title: page title to add watches on
  111. */
  112. public static function duplicateEntries( $ot, $nt ) {
  113. WatchedItem::doDuplicateEntries( $ot->getSubjectPage(), $nt->getSubjectPage() );
  114. WatchedItem::doDuplicateEntries( $ot->getTalkPage(), $nt->getTalkPage() );
  115. }
  116. /**
  117. * Handle duplicate entries. Backend for duplicateEntries().
  118. */
  119. private static function doDuplicateEntries( $ot, $nt ) {
  120. $oldnamespace = $ot->getNamespace();
  121. $newnamespace = $nt->getNamespace();
  122. $oldtitle = $ot->getDBkey();
  123. $newtitle = $nt->getDBkey();
  124. $dbw = wfGetDB( DB_MASTER );
  125. $res = $dbw->select( 'watchlist', 'wl_user',
  126. array( 'wl_namespace' => $oldnamespace, 'wl_title' => $oldtitle ),
  127. __METHOD__, 'FOR UPDATE'
  128. );
  129. # Construct array to replace into the watchlist
  130. $values = array();
  131. while ( $s = $dbw->fetchObject( $res ) ) {
  132. $values[] = array(
  133. 'wl_user' => $s->wl_user,
  134. 'wl_namespace' => $newnamespace,
  135. 'wl_title' => $newtitle
  136. );
  137. }
  138. $dbw->freeResult( $res );
  139. if( empty( $values ) ) {
  140. // Nothing to do
  141. return true;
  142. }
  143. # Perform replace
  144. # Note that multi-row replace is very efficient for MySQL but may be inefficient for
  145. # some other DBMSes, mostly due to poor simulation by us
  146. $dbw->replace( 'watchlist', array( array( 'wl_user', 'wl_namespace', 'wl_title' ) ), $values, __METHOD__ );
  147. return true;
  148. }
  149. }