+ /**
+ * @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 = $this->lbFactory->getEmptyTransactionTicket( __METHOD__ );
+ $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();
+ $this->lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
+ }
+ }
+
+ return (bool)$affectedRows;
+ }
+