MediaWiki  REL1_21
WatchedItem.php
Go to the documentation of this file.
00001 <?php
00029 class WatchedItem {
00030         var $mTitle, $mUser;
00031         private $loaded = false, $watched, $timestamp;
00032 
00039         public static function fromUserTitle( $user, $title ) {
00040                 $wl = new WatchedItem;
00041                 $wl->mUser = $user;
00042                 $wl->mTitle = $title;
00043 
00044                 return $wl;
00045         }
00046 
00051         protected function getTitle() {
00052                 return $this->mTitle;
00053         }
00054 
00056         protected function getTitleNs() {
00057                 return $this->getTitle()->getNamespace();
00058         }
00059 
00061         protected function getTitleDBkey() {
00062                 return $this->getTitle()->getDBkey();
00063         }
00065         protected function getUserId() {
00066                 return $this->mUser->getId();
00067         }
00068 
00075         private function dbCond() {
00076                 return array(
00077                         'wl_user' => $this->getUserId(),
00078                         'wl_namespace' => $this->getTitleNs(),
00079                         'wl_title' => $this->getTitleDBkey(),
00080                 );
00081         }
00082 
00086         private function load() {
00087                 if ( $this->loaded ) {
00088                         return;
00089                 }
00090                 $this->loaded = true;
00091 
00092                 # Pages and their talk pages are considered equivalent for watching;
00093                 # remember that talk namespaces are numbered as page namespace+1.
00094 
00095                 $dbr = wfGetDB( DB_SLAVE );
00096                 $row = $dbr->selectRow( 'watchlist', 'wl_notificationtimestamp',
00097                         $this->dbCond(), __METHOD__ );
00098 
00099                 if ( $row === false ) {
00100                         $this->watched = false;
00101                 } else {
00102                         $this->watched = true;
00103                         $this->timestamp = $row->wl_notificationtimestamp;
00104                 }
00105         }
00106 
00111         public function isWatched() {
00112                 $this->load();
00113                 return $this->watched;
00114         }
00115 
00122         public function getNotificationTimestamp() {
00123                 $this->load();
00124                 if ( $this->watched ) {
00125                         return $this->timestamp;
00126                 } else {
00127                         return false;
00128                 }
00129         }
00130 
00137         public function resetNotificationTimestamp( $force = '' ) {
00138                 if ( $force != 'force' ) {
00139                         $this->load();
00140                         if ( !$this->watched || $this->timestamp === null ) {
00141                                 return;
00142                         }
00143                 }
00144 
00145                 // If the page is watched by the user (or may be watched), update the timestamp on any
00146                 // any matching rows
00147                 $dbw = wfGetDB( DB_MASTER );
00148                 $dbw->update( 'watchlist', array( 'wl_notificationtimestamp' => null ),
00149                         $this->dbCond(), __METHOD__ );
00150                 $this->timestamp = null;
00151         }
00152 
00158         public function addWatch() {
00159                 wfProfileIn( __METHOD__ );
00160 
00161                 // Use INSERT IGNORE to avoid overwriting the notification timestamp
00162                 // if there's already an entry for this page
00163                 $dbw = wfGetDB( DB_MASTER );
00164                 $dbw->insert( 'watchlist',
00165                         array(
00166                                 'wl_user' => $this->getUserId(),
00167                                 'wl_namespace' => MWNamespace::getSubject( $this->getTitleNs() ),
00168                                 'wl_title' => $this->getTitleDBkey(),
00169                                 'wl_notificationtimestamp' => null
00170                         ), __METHOD__, 'IGNORE' );
00171 
00172                 // Every single watched page needs now to be listed in watchlist;
00173                 // namespace:page and namespace_talk:page need separate entries:
00174                 $dbw->insert( 'watchlist',
00175                         array(
00176                                 'wl_user' => $this->getUserId(),
00177                                 'wl_namespace' => MWNamespace::getTalk( $this->getTitleNs() ),
00178                                 'wl_title' => $this->getTitleDBkey(),
00179                                 'wl_notificationtimestamp' => null
00180                         ), __METHOD__, 'IGNORE' );
00181 
00182                 $this->watched = true;
00183 
00184                 wfProfileOut( __METHOD__ );
00185                 return true;
00186         }
00187 
00192         public function removeWatch() {
00193                 wfProfileIn( __METHOD__ );
00194 
00195                 $success = false;
00196                 $dbw = wfGetDB( DB_MASTER );
00197                 $dbw->delete( 'watchlist',
00198                         array(
00199                                 'wl_user' => $this->getUserId(),
00200                                 'wl_namespace' => MWNamespace::getSubject( $this->getTitleNs() ),
00201                                 'wl_title' => $this->getTitleDBkey(),
00202                         ), __METHOD__
00203                 );
00204                 if ( $dbw->affectedRows() ) {
00205                         $success = true;
00206                 }
00207 
00208                 # the following code compensates the new behavior, introduced by the
00209                 # enotif patch, that every single watched page needs now to be listed
00210                 # in watchlist namespace:page and namespace_talk:page had separate
00211                 # entries: clear them
00212                 $dbw->delete( 'watchlist',
00213                         array(
00214                                 'wl_user' => $this->getUserId(),
00215                                 'wl_namespace' => MWNamespace::getTalk( $this->getTitleNs() ),
00216                                 'wl_title' => $this->getTitleDBkey(),
00217                         ), __METHOD__
00218                 );
00219 
00220                 if ( $dbw->affectedRows() ) {
00221                         $success = true;
00222                 }
00223 
00224                 $this->watched = false;
00225 
00226                 wfProfileOut( __METHOD__ );
00227                 return $success;
00228         }
00229 
00237         public static function duplicateEntries( $ot, $nt ) {
00238                 WatchedItem::doDuplicateEntries( $ot->getSubjectPage(), $nt->getSubjectPage() );
00239                 WatchedItem::doDuplicateEntries( $ot->getTalkPage(), $nt->getTalkPage() );
00240         }
00241 
00250         private static function doDuplicateEntries( $ot, $nt ) {
00251                 $oldnamespace = $ot->getNamespace();
00252                 $newnamespace = $nt->getNamespace();
00253                 $oldtitle = $ot->getDBkey();
00254                 $newtitle = $nt->getDBkey();
00255 
00256                 $dbw = wfGetDB( DB_MASTER );
00257                 $res = $dbw->select( 'watchlist', 'wl_user',
00258                         array( 'wl_namespace' => $oldnamespace, 'wl_title' => $oldtitle ),
00259                         __METHOD__, 'FOR UPDATE'
00260                 );
00261                 # Construct array to replace into the watchlist
00262                 $values = array();
00263                 foreach ( $res as $s ) {
00264                         $values[] = array(
00265                                 'wl_user' => $s->wl_user,
00266                                 'wl_namespace' => $newnamespace,
00267                                 'wl_title' => $newtitle
00268                         );
00269                 }
00270 
00271                 if( empty( $values ) ) {
00272                         // Nothing to do
00273                         return true;
00274                 }
00275 
00276                 # Perform replace
00277                 # Note that multi-row replace is very efficient for MySQL but may be inefficient for
00278                 # some other DBMSes, mostly due to poor simulation by us
00279                 $dbw->replace( 'watchlist', array( array( 'wl_user', 'wl_namespace', 'wl_title' ) ), $values, __METHOD__ );
00280                 return true;
00281         }
00282 }