return $return;
}
+ /**
+ * Number of page watchers who also visited a "recent" edit
+ *
+ * @param LinkTarget $target
+ * @param mixed $threshold timestamp accepted by wfTimestamp
+ *
+ * @return int
+ * @throws DBUnexpectedError
+ * @throws MWException
+ */
+ public function countVisitingWatchers( LinkTarget $target, $threshold ) {
+ $dbr = $this->loadBalancer->getConnection( DB_SLAVE, [ 'watchlist' ] );
+ $visitingWatchers = (int)$dbr->selectField(
+ 'watchlist',
+ 'COUNT(*)',
+ [
+ 'wl_namespace' => $target->getNamespace(),
+ 'wl_title' => $target->getDBkey(),
+ 'wl_notificationtimestamp >= ' .
+ $dbr->addQuotes( $dbr->timestamp( $threshold ) ) .
+ ' OR wl_notificationtimestamp IS NULL'
+ ],
+ __METHOD__
+ );
+ $this->loadBalancer->reuseConnection( $dbr );
+
+ return $visitingWatchers;
+ }
+
/**
* @param LinkTarget[] $targets
* @param array $options Allowed keys:
$setOpts += Database::getCacheSetOptions( $dbr, $dbrWatchlist );
+ $watchedItemStore = WatchedItemStore::getDefaultInstance();
+
$result = [];
- $result['watchers'] = WatchedItemStore::getDefaultInstance()->countWatchers( $title );
+ $result['watchers'] = $watchedItemStore->countWatchers( $title );
if ( $config->get( 'ShowUpdatedMarker' ) ) {
- // Threshold: last visited about 26 weeks before latest edit
$updated = wfTimestamp( TS_UNIX, $page->getTimestamp() );
- $age = $config->get( 'WatchersMaxAge' );
- $threshold = $dbrWatchlist->timestamp( $updated - $age );
- // Number of page watchers who also visited a "recent" edit
- $visitingWatchers = (int)$dbrWatchlist->selectField(
- 'watchlist',
- 'COUNT(*)',
- [
- 'wl_namespace' => $title->getNamespace(),
- 'wl_title' => $title->getDBkey(),
- 'wl_notificationtimestamp >= ' .
- $dbrWatchlist->addQuotes( $threshold ) .
- ' OR wl_notificationtimestamp IS NULL'
- ],
- $fname
+ $result['visitingWatchers'] = $watchedItemStore->countVisitingWatchers(
+ $title,
+ $updated - $config->get( 'WatchersMaxAge' )
);
- $result['visitingWatchers'] = $visitingWatchers;
}
// Total number of edits
$store = WatchedItemStore::getDefaultInstance();
$store->addWatch( $user, $title );
$this->assertNull( $store->loadWatchedItem( $user, $title )->getNotificationTimestamp() );
+ $initialVisitingWatchers = $store->countVisitingWatchers( $title, '20150202020202' );
$store->updateNotificationTimestamp( $otherUser, $title, '20150202010101' );
$this->assertEquals(
'20150202010101',
$store->loadWatchedItem( $user, $title )->getNotificationTimestamp()
);
+ $this->assertEquals(
+ $initialVisitingWatchers - 1,
+ $store->countVisitingWatchers( $title, '20150202020202' )
+ );
$this->assertTrue( $store->resetNotificationTimestamp( $user, $title ) );
$this->assertNull( $store->getWatchedItem( $user, $title )->getNotificationTimestamp() );
+ $this->assertEquals(
+ $initialVisitingWatchers,
+ $store->countVisitingWatchers( $title, '20150202020202' )
+ );
}
public function testDuplicateAllAssociatedEntries() {
);
}
+ public function testCountVisitingWatchers() {
+ $titleValue = new TitleValue( 0, 'SomeDbKey' );
+
+ $mockDb = $this->getMockDb();
+ $mockDb->expects( $this->exactly( 1 ) )
+ ->method( 'selectField' )
+ ->with(
+ 'watchlist',
+ 'COUNT(*)',
+ [
+ 'wl_namespace' => $titleValue->getNamespace(),
+ 'wl_title' => $titleValue->getDBkey(),
+ 'wl_notificationtimestamp >= \'TS111TS\' OR wl_notificationtimestamp IS NULL',
+ ],
+ $this->isType( 'string' )
+ )
+ ->will( $this->returnValue( 7 ) );
+ $mockDb->expects( $this->exactly( 1 ) )
+ ->method( 'addQuotes' )
+ ->will( $this->returnCallback( function( $value ) {
+ return "'$value'";
+ } ) );
+ $mockDb->expects( $this->exactly( 1 ) )
+ ->method( 'timestamp' )
+ ->will( $this->returnCallback( function( $value ) {
+ return 'TS' . $value . 'TS';
+ } ) );
+
+ $mockCache = $this->getMockCache();
+ $mockCache->expects( $this->never() )->method( 'set' );
+ $mockCache->expects( $this->never() )->method( 'get' );
+ $mockCache->expects( $this->never() )->method( 'delete' );
+
+ $store = new WatchedItemStore(
+ $this->getMockLoadBalancer( $mockDb ),
+ $mockCache
+ );
+
+ $this->assertEquals( 7, $store->countVisitingWatchers( $titleValue, '111' ) );
+ }
+
public function testDuplicateEntry_nothingToDuplicate() {
$mockDb = $this->getMockDb();
$mockDb->expects( $this->once() )