Addshore has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/266572

Change subject: WIP Move counting of watchers to WatchedItemStore
......................................................................

WIP Move counting of watchers to WatchedItemStore

Also adds tests

Still not sure if this will stick hence WIP

Change-Id: I5a465773599cce9f8c9e94847cede6d12282c827
---
M includes/WatchedItem.php
M includes/WatchedItemStore.php
M includes/actions/InfoAction.php
M includes/api/ApiQueryInfo.php
M tests/phpunit/includes/WatchedItemStoreTest.php
5 files changed, 170 insertions(+), 41 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/72/266572/1

diff --git a/includes/WatchedItem.php b/includes/WatchedItem.php
index 1754f09..09df404 100644
--- a/includes/WatchedItem.php
+++ b/includes/WatchedItem.php
@@ -409,7 +409,7 @@
         * @deprecated since 1.27. Use WatchedItemStore::duplicateEntries
         */
        public static function duplicateEntries( $oldTitle, $newTitle ) {
-               $store = new WatchedItemStore( wfGetDB( DB_MASTER ) );
+               $store = WatchedItemStore::newFromGlobalState();
                $store->duplicateEntries( $oldTitle->getTitleValue(), 
$newTitle->getTitleValue() );
        }
 
diff --git a/includes/WatchedItemStore.php b/includes/WatchedItemStore.php
index 52110e4..c41b6ee 100644
--- a/includes/WatchedItemStore.php
+++ b/includes/WatchedItemStore.php
@@ -12,8 +12,81 @@
         */
        private $masterDb;
 
-       public function __construct( IDatabase $masterDb ) {
+       /**
+        * @var IDatabase
+        */
+       private $slaveDb;
+
+       /**
+        * @var Config
+        */
+       private $config;
+
+       public function __construct( IDatabase $masterDb, IDatabase $slaveDb, 
Config $config ) {
                $this->masterDb = $masterDb;
+               $this->slaveDb = $slaveDb;
+               $this->config = $config;
+       }
+
+       public static function newFromGlobalState() {
+               return new self(
+                       wfGetDB( DB_MASTER, 'watchlist' ),
+                       wfGetDB( DB_SLAVE, 'watchlist' ),
+                       RequestContext::getMain()->getConfig()
+               );
+       }
+
+       /**
+        * @param TitleValue $titleValue
+        *
+        * @return int
+        */
+       public function countWatchers( TitleValue $titleValue ) {
+               return (int)$this->slaveDb->selectField(
+                       'watchlist',
+                       'COUNT(*)',
+                       array(
+                               'wl_namespace' => $titleValue->getNamespace(),
+                               'wl_title' => $titleValue->getDBkey(),
+                       ),
+                       __METHOD__
+               );
+       }
+
+       /**
+        * @param TitleValue[]|Title[] $titleValues
+        * @param bool $unwatchedPages show unwatched pages obeying 
UnwatchedPageThreshold setting
+        *
+        * @return array multi dimensional like 
$return[$namespaceId][$titleString] = $watchers
+        */
+       public function countWatchersMultiple( array $titleValues, 
$unwatchedPages = false ) {
+               $unwatchedPageThreshold = $this->config->get( 
'UnwatchedPageThreshold' );
+
+               if ( !$unwatchedPages && !is_int( $unwatchedPageThreshold ) ) {
+                       // TODO throw exception?
+                       return array();
+               }
+
+               $options = array( 'GROUP BY' => array( 'wl_namespace', 
'wl_title' ) );
+               if ( !$unwatchedPages ) {
+                       $options['HAVING'] = "COUNT(*) >= 
$unwatchedPageThreshold";
+               }
+
+               $lb = new LinkBatch( $titleValues );
+               $res = $this->slaveDb->select(
+                       'watchlist',
+                       array( 'wl_title', 'wl_namespace', 'count' => 
'COUNT(*)' ),
+                       array( $lb->constructSet( 'wl', $this->slaveDb ) ),
+                       __METHOD__,
+                       $options
+               );
+
+               $watchCounts = array();
+               foreach ( $res as $row ) {
+                       $watchCounts[$row->wl_namespace][$row->wl_title] = 
(int)$row->count;
+               }
+
+               return $watchCounts;
        }
 
        /**
diff --git a/includes/actions/InfoAction.php b/includes/actions/InfoAction.php
index 6f33db7..b2ac800 100644
--- a/includes/actions/InfoAction.php
+++ b/includes/actions/InfoAction.php
@@ -670,6 +670,7 @@
                        86400 * 7,
                        function ( $oldValue, &$ttl, &$setOpts ) use ( $page, 
$config, $fname ) {
                                $title = $page->getTitle();
+                               $titleValue = $title->getTitleValue();
                                $id = $title->getArticleID();
 
                                $dbr = wfGetDB( DB_SLAVE );
@@ -678,18 +679,7 @@
                                $setOpts += Database::getCacheSetOptions( $dbr, 
$dbrWatchlist );
 
                                $result = array();
-
-                               // Number of page watchers
-                               $watchers = (int)$dbrWatchlist->selectField(
-                                       'watchlist',
-                                       'COUNT(*)',
-                                       array(
-                                               'wl_namespace' => 
$title->getNamespace(),
-                                               'wl_title' => 
$title->getDBkey(),
-                                       ),
-                                       $fname
-                               );
-                               $result['watchers'] = $watchers;
+                               $result['watchers'] = 
WatchedItemStore::newFromGlobalState()->countWatchers( $titleValue );
 
                                if ( $config->get( 'ShowUpdatedMarker' ) ) {
                                        // Threshold: last visited about 26 
weeks before latest edit
diff --git a/includes/api/ApiQueryInfo.php b/includes/api/ApiQueryInfo.php
index 6f1e2e5..45e4bc2 100644
--- a/includes/api/ApiQueryInfo.php
+++ b/includes/api/ApiQueryInfo.php
@@ -778,28 +778,12 @@
                        return;
                }
 
-               $this->watchers = array();
                $this->showZeroWatchers = $canUnwatchedpages;
-               $db = $this->getDB();
 
-               $lb = new LinkBatch( $this->everything );
-
-               $this->resetQueryParams();
-               $this->addTables( array( 'watchlist' ) );
-               $this->addFields( array( 'wl_title', 'wl_namespace', 'count' => 
'COUNT(*)' ) );
-               $this->addWhere( array(
-                       $lb->constructSet( 'wl', $db )
-               ) );
-               $this->addOption( 'GROUP BY', array( 'wl_namespace', 'wl_title' 
) );
-               if ( !$canUnwatchedpages ) {
-                       $this->addOption( 'HAVING', "COUNT(*) >= 
$unwatchedPageThreshold" );
-               }
-
-               $res = $this->select( __METHOD__ );
-
-               foreach ( $res as $row ) {
-                       $this->watchers[$row->wl_namespace][$row->wl_title] = 
(int)$row->count;
-               }
+               $this->watchers = 
WatchedItemStore::newFromGlobalState()->countWatchersMultiple(
+                       $this->everything,
+                       $canUnwatchedpages
+               );
        }
 
        public function getCacheMode( $params ) {
diff --git a/tests/phpunit/includes/WatchedItemStoreTest.php 
b/tests/phpunit/includes/WatchedItemStoreTest.php
index a1ba3f5..97e50cd 100644
--- a/tests/phpunit/includes/WatchedItemStoreTest.php
+++ b/tests/phpunit/includes/WatchedItemStoreTest.php
@@ -14,11 +14,93 @@
                return $this->getMock( 'IDatabase' );
        }
 
-       private function getFakeRow( $userId, $timestamp ) {
+       /**
+        * @return PHPUnit_Framework_MockObject_MockObject|Config
+        */
+       private function getMockConfig() {
+               return $this->getMock( 'Config' );
+       }
+
+       private function getFakeRow( array $rowValues ) {
                $fakeRow = new stdClass();
-               $fakeRow->wl_user = $userId;
-               $fakeRow->wl_notificationtimestamp = $timestamp;
+               foreach ( $rowValues as $valueName => $value ) {
+                       $fakeRow->$valueName = $value;
+               }
                return $fakeRow;
+       }
+
+       public function testCountWatchers() {
+               $titleValue = new TitleValue( 0, 'SomeDbKey' );
+
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->exactly( 1 ) )
+                       ->method( 'selectField' )
+                       ->with(
+                               'watchlist',
+                               'COUNT(*)',
+                               array(
+                                       'wl_namespace' => 
$titleValue->getNamespace(),
+                                       'wl_title' => $titleValue->getDBkey(),
+                               ),
+                               $this->isType( 'string' )
+                       )
+                       ->will( $this->returnValue( 7 ) );
+
+               $store = new WatchedItemStore( $this->getMockDb(), $mockDb, 
$this->getMockConfig() );
+
+               $this->assertEquals( 7, $store->countWatchers( $titleValue ) );
+       }
+
+       public function testCountWatchersMultiple() {
+               $titleValues = array(
+                       new TitleValue( 0, 'SomeDbKey' ),
+                       new TitleValue( 0, 'OtherDbKey' ),
+                       new TitleValue( 1, 'AnotherDbKey' ),
+               );
+
+               $mockDb = $this->getMockDb();
+               $mockConfig = $this->getMockConfig();
+
+               $dbResult = array(
+                       $this->getFakeRow( array( 'wl_title' => 'SomeDbKey', 
'wl_namespace' => 0, 'count' => 100 ) ),
+                       $this->getFakeRow( array( 'wl_title' => 'OtherDbKey', 
'wl_namespace' => 0, 'count' => 300 ) ),
+                       $this->getFakeRow( array( 'wl_title' => 'AnotherDbKey', 
'wl_namespace' => 1, 'count' => 500 ) ),
+               );
+               $mockDb->expects( $this->once() )
+                       ->method( 'makeWhereFrom2d' )
+                       ->with(
+                               array( array( 'SomeDbKey' => 1, 'OtherDbKey' => 
1 ), array( 'AnotherDbKey' => 1 ) ),
+                               $this->isType( 'string' ),
+                               $this->isType( 'string' )
+                               )
+                       ->will( $this->returnValue( 'makeWhereFrom2d return 
value' ) );
+               $mockDb->expects( $this->once() )
+                       ->method( 'select' )
+                       ->with(
+                               'watchlist',
+                               array( 'wl_title', 'wl_namespace', 'count' => 
'COUNT(*)' ),
+                               array( 'makeWhereFrom2d return value' ),
+                               $this->isType( 'string' ),
+                               array(
+                                       'GROUP BY' => array( 'wl_namespace', 
'wl_title' ),
+                                       'HAVING' => 'COUNT(*) >= 60',
+                               )
+                       )
+                       ->will(
+                               $this->returnValue( $dbResult )
+                       );
+               $mockConfig->expects( $this->exactly( 1 ) )
+                       ->method( 'get' )
+                       ->with( 'UnwatchedPageThreshold' )
+                       ->will( $this->returnValue( 60 ) );
+
+               $store = new WatchedItemStore( $this->getMockDb(), $mockDb, 
$mockConfig );
+
+               $expected = array(
+                       0 => array( 'SomeDbKey' => 100, 'OtherDbKey' => 300 ),
+                       1 => array( 'AnotherDbKey' => 500 ),
+               );
+               $this->assertEquals( $expected, $store->countWatchersMultiple( 
$titleValues ) );
        }
 
        public function testDuplicateEntries_nothingToDuplicate() {
@@ -27,7 +109,7 @@
                        ->method( 'select' )
                        ->will( $this->returnValue( new FakeResultWrapper( 
array() ) ) );
 
-               $store = new WatchedItemStore( $mockDb );
+               $store = new WatchedItemStore( $mockDb, $this->getMockDb(), 
$this->getMockConfig() );
 
                $store->duplicateEntries(
                        new TitleValue( 0, 'Old_Title' ),
@@ -37,8 +119,8 @@
 
        public function testDuplicateEntries_somethingToDuplicate() {
                $fakeRows = array(
-                       $this->getFakeRow( 1, '20151212010101' ),
-                       $this->getFakeRow( 2, null ),
+                       $this->getFakeRow( array( 'wl_user' => 1, 
'wl_notificationtimestamp' => '20151212010101' ) ),
+                       $this->getFakeRow( array( 'wl_user' => 2, 
'wl_notificationtimestamp' => null ) ),
                );
 
                $mockDb = $this->getMockDb();
@@ -91,7 +173,7 @@
                                $this->isType( 'string' )
                        );
 
-               $store = new WatchedItemStore( $mockDb );
+               $store = new WatchedItemStore( $mockDb, $this->getMockDb(), 
$this->getMockConfig() );
 
                $store->duplicateEntries(
                        new TitleValue( 0, 'Old_Title' ),

-- 
To view, visit https://gerrit.wikimedia.org/r/266572
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I5a465773599cce9f8c9e94847cede6d12282c827
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Addshore <addshorew...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to