X-Git-Url: http://git.cyclocoop.org/%7B%24www_url%7Dadmin/membres/fiche.php?a=blobdiff_plain;f=includes%2Fwatcheditem%2FWatchedItemStore.php;h=85668959d0338944ca3e18a8070e255c80442f10;hb=70d9fbb0bfacaf837b7e8efb3770245d646ab522;hp=c76301046c37b494aee4e6121478bacf7fb02a36;hpb=69d27cc0b6d779af8d870fd0e8ccb5cd41f887ab;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/watcheditem/WatchedItemStore.php b/includes/watcheditem/WatchedItemStore.php index c76301046c..85668959d0 100644 --- a/includes/watcheditem/WatchedItemStore.php +++ b/includes/watcheditem/WatchedItemStore.php @@ -367,6 +367,50 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac return $visitingWatchers; } + /** + * @param User $user + * @param TitleValue[] $titles + * @return bool + * @throws MWException + */ + public function removeWatchBatchForUser( User $user, array $titles ) { + if ( $this->readOnlyMode->isReadOnly() ) { + return false; + } + if ( $user->isAnon() ) { + return false; + } + if ( !$titles ) { + return true; + } + + $rows = $this->getTitleDbKeysGroupedByNamespace( $titles ); + $this->uncacheTitlesForUser( $user, $titles ); + + $dbw = $this->getConnectionRef( DB_MASTER ); + $ticket = count( $titles ) > $this->updateRowsPerQuery ? + $this->lbFactory->getEmptyTransactionTicket( __METHOD__ ) : null; + $affectedRows = 0; + + // Batch delete items per namespace. + foreach ( $rows as $namespace => $namespaceTitles ) { + $rowBatches = array_chunk( $namespaceTitles, $this->updateRowsPerQuery ); + foreach ( $rowBatches as $toDelete ) { + $dbw->delete( 'watchlist', [ + 'wl_user' => $user->getId(), + 'wl_namespace' => $namespace, + 'wl_title' => $toDelete + ], __METHOD__ ); + $affectedRows += $dbw->affectedRows(); + if ( $ticket ) { + $this->lbFactory->commitAndWaitForReplication( __METHOD__, $ticket ); + } + } + } + + return (bool)$affectedRows; + } + /** * @since 1.27 * @param LinkTarget[] $targets @@ -655,6 +699,7 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac * @since 1.27 * @param User $user * @param LinkTarget $target + * @throws MWException */ public function addWatch( User $user, LinkTarget $target ) { $this->addWatchBatchForUser( $user, [ $target ] ); @@ -665,12 +710,13 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac * @param User $user * @param LinkTarget[] $targets * @return bool + * @throws MWException */ public function addWatchBatchForUser( User $user, array $targets ) { if ( $this->readOnlyMode->isReadOnly() ) { return false; } - // Only loggedin user can have a watchlist + // Only logged-in user can have a watchlist if ( $user->isAnon() ) { return false; } @@ -697,10 +743,18 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac } $dbw = $this->getConnectionRef( DB_MASTER ); - foreach ( array_chunk( $rows, 100 ) as $toInsert ) { + $ticket = count( $targets ) > $this->updateRowsPerQuery ? + $this->lbFactory->getEmptyTransactionTicket( __METHOD__ ) : null; + $affectedRows = 0; + $rowBatches = array_chunk( $rows, $this->updateRowsPerQuery ); + foreach ( $rowBatches as $toInsert ) { // Use INSERT IGNORE to avoid overwriting the notification timestamp // if there's already an entry for this page $dbw->insert( 'watchlist', $toInsert, __METHOD__, 'IGNORE' ); + $affectedRows += $dbw->affectedRows(); + if ( $ticket ) { + $this->lbFactory->commitAndWaitForReplication( __METHOD__, $ticket ); + } } // Update process cache to ensure skin doesn't claim that the current // page is unwatched in the response of action=watch itself (T28292). @@ -709,7 +763,7 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac $this->cache( $item ); } - return true; + return (bool)$affectedRows; } /** @@ -717,26 +771,10 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac * @param User $user * @param LinkTarget $target * @return bool + * @throws MWException */ public function removeWatch( User $user, LinkTarget $target ) { - // Only logged in user can have a watchlist - if ( $this->readOnlyMode->isReadOnly() || $user->isAnon() ) { - return false; - } - - $this->uncache( $user, $target ); - - $dbw = $this->getConnectionRef( DB_MASTER ); - $dbw->delete( 'watchlist', - [ - 'wl_user' => $user->getId(), - 'wl_namespace' => $target->getNamespace(), - 'wl_title' => $target->getDBkey(), - ], __METHOD__ - ); - $success = (bool)$dbw->affectedRows(); - - return $success; + return $this->removeWatchBatchForUser( $user, [ $target ] ); } /** @@ -869,6 +907,10 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac return false; } + if ( ! Hooks::run( 'BeforeResetNotificationTimestamp', [ &$user, &$title, $force, &$oldid ] ) ) { + return false; + } + $item = null; if ( $force != 'force' ) { $item = $this->loadWatchedItem( $user, $title ); @@ -1044,4 +1086,27 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac } } + /** + * @param TitleValue[] $titles + * @return array + */ + private function getTitleDbKeysGroupedByNamespace( array $titles ) { + $rows = []; + foreach ( $titles as $title ) { + // Group titles by namespace. + $rows[ $title->getNamespace() ][] = $title->getDBkey(); + } + return $rows; + } + + /** + * @param User $user + * @param Title[] $titles + */ + private function uncacheTitlesForUser( User $user, array $titles ) { + foreach ( $titles as $title ) { + $this->uncache( $user, $title ); + } + } + }