Pass $key into CommentStore methods and use MediawikiServices
authoraddshore <addshorewiki@gmail.com>
Wed, 24 Jan 2018 23:41:01 +0000 (15:41 -0800)
committerAddshore <addshorewiki@gmail.com>
Mon, 5 Feb 2018 15:34:12 +0000 (15:34 +0000)
This allows CommentStore to be added to MediaWikiServices
without the need of an aditional Factory.

This change includes a compatability layer to allow the behaviour
from 1.30 to continue to be used while deprecated.

CommentStore::newKey has been deprecated.
Keys are now passed into the public methods of CommentStore
where needed.
The following CommentStore methods have had their signatures changed
to introduced a $key parameter, but when used in conjunction with
CommentStore::newKey behaviour will remain unchanged:
  * CommentStore::getFields
  * CommentStore::getJoin
  * CommentStore::getComment
  * CommentStore::getCommentLegacy
  * CommentStore::insert
  * CommentStore::insertWithTemplate

Change-Id: I3abb62a5cfb0dcd456da9f4eb35583476ae41cfb

50 files changed:
RELEASE-NOTES-1.31
includes/Block.php
includes/CommentStore.php
includes/EditPage.php
includes/FeedUtils.php
includes/MediaWikiServices.php
includes/Revision.php
includes/ServiceWiring.php
includes/Storage/RevisionStore.php
includes/Title.php
includes/api/ApiQueryAllUsers.php
includes/api/ApiQueryBase.php
includes/api/ApiQueryBlocks.php
includes/api/ApiQueryDeletedrevs.php
includes/api/ApiQueryFilearchive.php
includes/api/ApiQueryLogEvents.php
includes/api/ApiQueryProtectedTitles.php
includes/api/ApiQueryRecentChanges.php
includes/api/ApiQueryUserContributions.php
includes/api/ApiQueryUsers.php
includes/api/ApiQueryWatchlist.php
includes/changes/RecentChange.php
includes/export/WikiExporter.php
includes/export/XmlDumpWriter.php
includes/filerepo/file/ArchivedFile.php
includes/filerepo/file/LocalFile.php
includes/filerepo/file/OldLocalFile.php
includes/import/WikiRevision.php
includes/logging/LogEntry.php
includes/logging/LogPage.php
includes/page/WikiPage.php
includes/rcfeed/IRCColourfulRCFeedFormatter.php
includes/revisiondelete/RevDelLogItem.php
includes/revisiondelete/RevDelLogList.php
includes/specials/SpecialNewpages.php
includes/specials/pagers/BlockListPager.php
includes/specials/pagers/DeletedContribsPager.php
includes/specials/pagers/ImageListPager.php
includes/specials/pagers/NewPagesPager.php
includes/specials/pagers/ProtectedPagesPager.php
includes/watcheditem/WatchedItemQueryService.php
maintenance/orphans.php
maintenance/rebuildrecentchanges.php
tests/phpunit/includes/CommentStoreTest.php
tests/phpunit/includes/MediaWikiServicesTest.php
tests/phpunit/includes/PageArchiveTest.php
tests/phpunit/includes/RevisionTest.php
tests/phpunit/includes/Storage/RevisionStoreTest.php
tests/phpunit/includes/page/WikiPageDbTestBase.php
tests/phpunit/includes/watcheditem/WatchedItemQueryServiceUnitTest.php

index b46d3d6..8261a39 100644 (file)
@@ -214,6 +214,15 @@ changes to languages because of Phabricator reports.
 * The no-op method Skin::showIPinHeader(), deprecated in 1.27, was removed.
 * \ObjectFactory (no namespace) is deprecated, the namespaced \Wikimedia\ObjectFactory
   from the wikimedia/object-factory library should be used instead.
+* CommentStore::newKey is deprecated. Get an instance from MediaWikiServices instead.
+* The following CommentStore methods have had their signatures changed to introduce a $key parameter,
+  usage of the methods on instances retrieved from CommentStore::newKey will remain unchanged but deprecated:
+  * CommentStore::getFields
+  * CommentStore::getJoin
+  * CommentStore::getComment
+  * CommentStore::getCommentLegacy
+  * CommentStore::insert
+  * CommentStore::insertWithTemplate
 
 == Compatibility ==
 MediaWiki 1.31 requires PHP 5.5.9 or later. Although HHVM 3.18.5 or later is supported,
index 0999ad2..bdc6702 100644 (file)
@@ -222,7 +222,7 @@ class Block {
                        'ipb_block_email',
                        'ipb_allow_usertalk',
                        'ipb_parent_block_id',
-               ] + CommentStore::newKey( 'ipb_reason' )->getFields();
+               ] + CommentStore::getStore()->getFields( 'ipb_reason' );
        }
 
        /**
@@ -235,7 +235,7 @@ class Block {
         *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
         */
        public static function getQueryInfo() {
-               $commentQuery = CommentStore::newKey( 'ipb_reason' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'ipb_reason' );
                return [
                        'tables' => [ 'ipblocks' ] + $commentQuery['tables'],
                        'fields' => [
@@ -460,9 +460,9 @@ class Block {
                // I wish I didn't have to do this
                $db = wfGetDB( DB_REPLICA );
                $this->mExpiry = $db->decodeExpiry( $row->ipb_expiry );
-               $this->mReason = CommentStore::newKey( 'ipb_reason' )
+               $this->mReason = CommentStore::getStore()
                        // Legacy because $row may have come from self::selectFields()
-                       ->getCommentLegacy( $db, $row )->text;
+                       ->getCommentLegacy( $db, 'ipb_reason', $row )->text;
 
                $this->isHardblock( !$row->ipb_anon_only );
                $this->isAutoblocking( $row->ipb_enable_autoblock );
@@ -654,7 +654,7 @@ class Block {
                        'ipb_block_email'      => $this->prevents( 'sendemail' ),
                        'ipb_allow_usertalk'   => !$this->prevents( 'editownusertalk' ),
                        'ipb_parent_block_id'  => $this->mParentBlockId
-               ] + CommentStore::newKey( 'ipb_reason' )->insert( $dbw, $this->mReason );
+               ] + CommentStore::getStore()->insert( $dbw, 'ipb_reason', $this->mReason );
 
                return $a;
        }
@@ -670,7 +670,7 @@ class Block {
                        'ipb_create_account'   => $this->prevents( 'createaccount' ),
                        'ipb_deleted'          => (int)$this->mHideName, // typecast required for SQLite
                        'ipb_allow_usertalk'   => !$this->prevents( 'editownusertalk' ),
-               ] + CommentStore::newKey( 'ipb_reason' )->insert( $dbw, $this->mReason );
+               ] + CommentStore::getStore()->insert( $dbw, 'ipb_reason', $this->mReason );
        }
 
        /**
index 0d679d3..8447b2c 100644 (file)
@@ -20,6 +20,7 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\IDatabase;
 
 /**
@@ -79,40 +80,71 @@ class CommentStore {
         */
        protected static $formerTempTables = [];
 
-       /** @var string */
-       protected $key;
+       /**
+        * @since 1.30
+        * @deprecated in 1.31
+        * @var string|null
+        */
+       protected $key = null;
 
        /** @var int One of the MIGRATION_* constants */
        protected $stage;
 
-       /** @var array|null Cache for `self::getJoin()` */
-       protected $joinCache = null;
+       /** @var array[] Cache for `self::getJoin()` */
+       protected $joinCache = [];
 
        /** @var Language Language to use for comment truncation */
        protected $lang;
 
        /**
-        * @param string $key A key such as "rev_comment" identifying the comment
-        *  field being fetched.
         * @param Language $lang Language to use for comment truncation. Defaults
         *  to $wgContLang.
+        * @param int $migrationStage One of the MIGRATION_* constants
         */
-       public function __construct( $key, Language $lang = null ) {
-               global $wgCommentTableSchemaMigrationStage, $wgContLang;
-
-               $this->key = $key;
-               $this->stage = $wgCommentTableSchemaMigrationStage;
-               $this->lang = $lang ?: $wgContLang;
+       public function __construct( Language $lang, $migrationStage ) {
+               $this->stage = $migrationStage;
+               $this->lang = $lang;
        }
 
        /**
         * Static constructor for easier chaining
+        * @deprecated in 1.31 Should not be constructed with a $key, use CommentStore::getStore
         * @param string $key A key such as "rev_comment" identifying the comment
         *  field being fetched.
         * @return CommentStore
         */
        public static function newKey( $key ) {
-               return new CommentStore( $key );
+               global $wgCommentTableSchemaMigrationStage, $wgContLang;
+               // TODO uncomment once not used in extensions
+               // wfDeprecated( __METHOD__, '1.31' );
+               $store = new CommentStore( $wgContLang, $wgCommentTableSchemaMigrationStage );
+               $store->key = $key;
+               return $store;
+       }
+
+       /**
+        * @since 1.31
+        * @deprecated in 1.31 Use DI to inject a CommentStore instance into your class.
+        * @return CommentStore
+        */
+       public static function getStore() {
+               return MediaWikiServices::getInstance()->getCommentStore();
+       }
+
+       /**
+        * Compat method allowing use of self::newKey until removed.
+        * @param string|null $methodKey
+        * @throw InvalidArgumentException
+        * @return string
+        */
+       private function getKey( $methodKey = null ) {
+               $key = $this->key !== null ? $this->key : $methodKey;
+               if ( $key === null ) {
+                       // @codeCoverageIgnoreStart
+                       throw new InvalidArgumentException( '$key should not be null' );
+                       // @codeCoverageIgnoreEnd
+               }
+               return $key;
        }
 
        /**
@@ -123,23 +155,29 @@ class CommentStore {
         *
         * @note Use of this method may require a subsequent database query to
         *  actually fetch the comment. If possible, use `self::getJoin()` instead.
+        *
+        * @since 1.30
+        * @since 1.31 Method signature changed, $key parameter added (with deprecated back compat)
+        * @param string $key A key such as "rev_comment" identifying the comment
+        *  field being fetched.
         * @return string[] to include in the `$vars` to `IDatabase->select()`. All
         *  fields are aliased, so `+` is safe to use.
         */
-       public function getFields() {
+       public function getFields( $key = null ) {
+               $key = $this->getKey( $key );
                $fields = [];
                if ( $this->stage === MIGRATION_OLD ) {
-                       $fields["{$this->key}_text"] = $this->key;
-                       $fields["{$this->key}_data"] = 'NULL';
-                       $fields["{$this->key}_cid"] = 'NULL';
+                       $fields["{$key}_text"] = $key;
+                       $fields["{$key}_data"] = 'NULL';
+                       $fields["{$key}_cid"] = 'NULL';
                } else {
                        if ( $this->stage < MIGRATION_NEW ) {
-                               $fields["{$this->key}_old"] = $this->key;
+                               $fields["{$key}_old"] = $key;
                        }
-                       if ( isset( self::$tempTables[$this->key] ) ) {
-                               $fields["{$this->key}_pk"] = self::$tempTables[$this->key]['joinPK'];
+                       if ( isset( self::$tempTables[$key] ) ) {
+                               $fields["{$key}_pk"] = self::$tempTables[$key]['joinPK'];
                        } else {
-                               $fields["{$this->key}_id"] = "{$this->key}_id";
+                               $fields["{$key}_id"] = "{$key}_id";
                        }
                }
                return $fields;
@@ -151,56 +189,61 @@ class CommentStore {
         * Each resulting row should be passed to `self::getComment()` to get the
         * actual comment.
         *
+        * @since 1.30
+        * @since 1.31 Method signature changed, $key parameter added (with deprecated back compat)
+        * @param string $key A key such as "rev_comment" identifying the comment
+        *  field being fetched.
         * @return array With three keys:
         *   - tables: (string[]) to include in the `$table` to `IDatabase->select()`
         *   - fields: (string[]) to include in the `$vars` to `IDatabase->select()`
         *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
         *  All tables, fields, and joins are aliased, so `+` is safe to use.
         */
-       public function getJoin() {
-               if ( $this->joinCache === null ) {
+       public function getJoin( $key = null ) {
+               $key = $this->getKey( $key );
+               if ( !array_key_exists( $key, $this->joinCache ) ) {
                        $tables = [];
                        $fields = [];
                        $joins = [];
 
                        if ( $this->stage === MIGRATION_OLD ) {
-                               $fields["{$this->key}_text"] = $this->key;
-                               $fields["{$this->key}_data"] = 'NULL';
-                               $fields["{$this->key}_cid"] = 'NULL';
+                               $fields["{$key}_text"] = $key;
+                               $fields["{$key}_data"] = 'NULL';
+                               $fields["{$key}_cid"] = 'NULL';
                        } else {
                                $join = $this->stage === MIGRATION_NEW ? 'JOIN' : 'LEFT JOIN';
 
-                               if ( isset( self::$tempTables[$this->key] ) ) {
-                                       $t = self::$tempTables[$this->key];
-                                       $alias = "temp_$this->key";
+                               if ( isset( self::$tempTables[$key] ) ) {
+                                       $t = self::$tempTables[$key];
+                                       $alias = "temp_$key";
                                        $tables[$alias] = $t['table'];
                                        $joins[$alias] = [ $join, "{$alias}.{$t['pk']} = {$t['joinPK']}" ];
                                        $joinField = "{$alias}.{$t['field']}";
                                } else {
-                                       $joinField = "{$this->key}_id";
+                                       $joinField = "{$key}_id";
                                }
 
-                               $alias = "comment_$this->key";
+                               $alias = "comment_$key";
                                $tables[$alias] = 'comment';
                                $joins[$alias] = [ $join, "{$alias}.comment_id = {$joinField}" ];
 
                                if ( $this->stage === MIGRATION_NEW ) {
-                                       $fields["{$this->key}_text"] = "{$alias}.comment_text";
+                                       $fields["{$key}_text"] = "{$alias}.comment_text";
                                } else {
-                                       $fields["{$this->key}_text"] = "COALESCE( {$alias}.comment_text, $this->key )";
+                                       $fields["{$key}_text"] = "COALESCE( {$alias}.comment_text, $key )";
                                }
-                               $fields["{$this->key}_data"] = "{$alias}.comment_data";
-                               $fields["{$this->key}_cid"] = "{$alias}.comment_id";
+                               $fields["{$key}_data"] = "{$alias}.comment_data";
+                               $fields["{$key}_cid"] = "{$alias}.comment_id";
                        }
 
-                       $this->joinCache = [
+                       $this->joinCache[$key] = [
                                'tables' => $tables,
                                'fields' => $fields,
                                'joins' => $joins,
                        ];
                }
 
-               return $this->joinCache;
+               return $this->joinCache[$key];
        }
 
        /**
@@ -209,12 +252,13 @@ class CommentStore {
         * Shared implementation for getComment() and getCommentLegacy()
         *
         * @param IDatabase|null $db Database handle for getCommentLegacy(), or null for getComment()
+        * @param string $key A key such as "rev_comment" identifying the comment
+        *  field being fetched.
         * @param object|array $row
         * @param bool $fallback
         * @return CommentStoreComment
         */
-       private function getCommentInternal( IDatabase $db = null, $row, $fallback = false ) {
-               $key = $this->key;
+       private function getCommentInternal( IDatabase $db = null, $key, $row, $fallback = false ) {
                $row = (array)$row;
                if ( array_key_exists( "{$key}_text", $row ) && array_key_exists( "{$key}_data", $row ) ) {
                        $cid = isset( $row["{$key}_cid"] ) ? $row["{$key}_cid"] : null;
@@ -333,12 +377,27 @@ class CommentStore {
         * If you need to fake a comment in a row for some reason, set fields
         * `{$key}_text` (string) and `{$key}_data` (JSON string or null).
         *
+        * @since 1.30
+        * @since 1.31 Method signature changed, $key parameter added (with deprecated back compat)
+        * @param string $key A key such as "rev_comment" identifying the comment
+        *  field being fetched.
         * @param object|array $row Result row.
         * @param bool $fallback If true, fall back as well as possible instead of throwing an exception.
         * @return CommentStoreComment
         */
-       public function getComment( $row, $fallback = false ) {
-               return $this->getCommentInternal( null, $row, $fallback );
+       public function getComment( $key, $row = null, $fallback = false ) {
+               // Compat for method sig change in 1.31 (introduction of $key)
+               if ( $this->key !== null ) {
+                       $fallback = $row;
+                       $row = $key;
+                       $key = $this->getKey();
+               }
+               if ( $row === null ) {
+                       // @codeCoverageIgnoreStart
+                       throw new InvalidArgumentException( '$row must not be null' );
+                       // @codeCoverageIgnoreEnd
+               }
+               return $this->getCommentInternal( null, $key, $row, $fallback );
        }
 
        /**
@@ -351,13 +410,28 @@ class CommentStore {
         * If you need to fake a comment in a row for some reason, set fields
         * `{$key}_text` (string) and `{$key}_data` (JSON string or null).
         *
+        * @since 1.30
+        * @since 1.31 Method signature changed, $key parameter added (with deprecated back compat)
         * @param IDatabase $db Database handle to use for lookup
+        * @param string $key A key such as "rev_comment" identifying the comment
+        *  field being fetched.
         * @param object|array $row Result row.
         * @param bool $fallback If true, fall back as well as possible instead of throwing an exception.
         * @return CommentStoreComment
         */
-       public function getCommentLegacy( IDatabase $db, $row, $fallback = false ) {
-               return $this->getCommentInternal( $db, $row, $fallback );
+       public function getCommentLegacy( IDatabase $db, $key, $row = null, $fallback = false ) {
+               // Compat for method sig change in 1.31 (introduction of $key)
+               if ( $this->key !== null ) {
+                       $fallback = $row;
+                       $row = $key;
+                       $key = $this->getKey();
+               }
+               if ( $row === null ) {
+                       // @codeCoverageIgnoreStart
+                       throw new InvalidArgumentException( '$row must not be null' );
+                       // @codeCoverageIgnoreEnd
+               }
+               return $this->getCommentInternal( $db, $key, $row, $fallback );
        }
 
        /**
@@ -443,23 +517,25 @@ class CommentStore {
        /**
         * Implementation for `self::insert()` and `self::insertWithTempTable()`
         * @param IDatabase $dbw
+        * @param string $key A key such as "rev_comment" identifying the comment
+        *  field being fetched.
         * @param string|Message|CommentStoreComment $comment
         * @param array|null $data
         * @return array [ array $fields, callable $callback ]
         */
-       private function insertInternal( IDatabase $dbw, $comment, $data ) {
+       private function insertInternal( IDatabase $dbw, $key, $comment, $data ) {
                $fields = [];
                $callback = null;
 
                $comment = $this->createComment( $dbw, $comment, $data );
 
                if ( $this->stage <= MIGRATION_WRITE_BOTH ) {
-                       $fields[$this->key] = $this->lang->truncate( $comment->text, 255 );
+                       $fields[$key] = $this->lang->truncate( $comment->text, 255 );
                }
 
                if ( $this->stage >= MIGRATION_WRITE_BOTH ) {
-                       if ( isset( self::$tempTables[$this->key] ) ) {
-                               $t = self::$tempTables[$this->key];
+                       if ( isset( self::$tempTables[$key] ) ) {
+                               $t = self::$tempTables[$key];
                                $func = __METHOD__;
                                $commentId = $comment->id;
                                $callback = function ( $id ) use ( $dbw, $commentId, $t, $func ) {
@@ -473,7 +549,7 @@ class CommentStore {
                                        );
                                };
                        } else {
-                               $fields["{$this->key}_id"] = $comment->id;
+                               $fields["{$key}_id"] = $comment->id;
                        }
                }
 
@@ -485,17 +561,34 @@ class CommentStore {
         *
         * @note It's recommended to include both the call to this method and the
         *  row insert in the same transaction.
+        *
+        * @since 1.30
+        * @since 1.31 Method signature changed, $key parameter added (with deprecated back compat)
         * @param IDatabase $dbw Database handle to insert on
+        * @param string $key A key such as "rev_comment" identifying the comment
+        *  field being fetched.
         * @param string|Message|CommentStoreComment $comment As for `self::createComment()`
         * @param array|null $data As for `self::createComment()`
         * @return array Fields for the insert or update
         */
-       public function insert( IDatabase $dbw, $comment, $data = null ) {
-               if ( isset( self::$tempTables[$this->key] ) ) {
-                       throw new InvalidArgumentException( "Must use insertWithTempTable() for $this->key" );
+       public function insert( IDatabase $dbw, $key, $comment = null, $data = null ) {
+               // Compat for method sig change in 1.31 (introduction of $key)
+               if ( $this->key !== null ) {
+                       $data = $comment;
+                       $comment = $key;
+                       $key = $this->key;
+               }
+               if ( $comment === null ) {
+                       // @codeCoverageIgnoreStart
+                       throw new InvalidArgumentException( '$comment can not be null' );
+                       // @codeCoverageIgnoreEnd
+               }
+
+               if ( isset( self::$tempTables[$key] ) ) {
+                       throw new InvalidArgumentException( "Must use insertWithTempTable() for $key" );
                }
 
-               list( $fields ) = $this->insertInternal( $dbw, $comment, $data );
+               list( $fields ) = $this->insertInternal( $dbw, $key, $comment, $data );
                return $fields;
        }
 
@@ -507,7 +600,12 @@ class CommentStore {
         *
         * @note It's recommended to include both the call to this method and the
         *  row insert in the same transaction.
+        *
+        * @since 1.30
+        * @since 1.31 Method signature changed, $key parameter added (with deprecated back compat)
         * @param IDatabase $dbw Database handle to insert on
+        * @param string $key A key such as "rev_comment" identifying the comment
+        *  field being fetched.
         * @param string|Message|CommentStoreComment $comment As for `self::createComment()`
         * @param array|null $data As for `self::createComment()`
         * @return array Two values:
@@ -515,14 +613,26 @@ class CommentStore {
         *  - callable Function to call when the primary key of the row being
         *    inserted/updated is known. Pass it that primary key.
         */
-       public function insertWithTempTable( IDatabase $dbw, $comment, $data = null ) {
-               if ( isset( self::$formerTempTables[$this->key] ) ) {
-                       wfDeprecated( __METHOD__ . " for $this->key", self::$formerTempTables[$this->key] );
-               } elseif ( !isset( self::$tempTables[$this->key] ) ) {
-                       throw new InvalidArgumentException( "Must use insert() for $this->key" );
+       public function insertWithTempTable( IDatabase $dbw, $key, $comment = null, $data = null ) {
+               // Compat for method sig change in 1.31 (introduction of $key)
+               if ( $this->key !== null ) {
+                       $data = $comment;
+                       $comment = $key;
+                       $key = $this->getKey();
+               }
+               if ( $comment === null ) {
+                       // @codeCoverageIgnoreStart
+                       throw new InvalidArgumentException( '$comment can not be null' );
+                       // @codeCoverageIgnoreEnd
+               }
+
+               if ( isset( self::$formerTempTables[$key] ) ) {
+                       wfDeprecated( __METHOD__ . " for $key", self::$formerTempTables[$key] );
+               } elseif ( !isset( self::$tempTables[$key] ) ) {
+                       throw new InvalidArgumentException( "Must use insert() for $key" );
                }
 
-               list( $fields, $callback ) = $this->insertInternal( $dbw, $comment, $data );
+               list( $fields, $callback ) = $this->insertInternal( $dbw, $key, $comment, $data );
                if ( !$callback ) {
                        $callback = function () {
                                // Do nothing.
index 6bf3c89..6fbeed7 100644 (file)
@@ -2798,7 +2798,8 @@ ERROR;
 
                if ( $this->wasDeletedSinceLastEdit() && 'save' == $this->formtype ) {
                        $username = $this->lastDelete->user_name;
-                       $comment = CommentStore::newKey( 'log_comment' )->getComment( $this->lastDelete )->text;
+                       $comment = CommentStore::getStore()
+                               ->getComment( 'log_comment', $this->lastDelete )->text;
 
                        // It is better to not parse the comment at all than to have templates expanded in the middle
                        // TODO: can the checkLabel be moved outside of the div so that wrapWikiMsg could be used?
@@ -3810,7 +3811,7 @@ ERROR;
         */
        protected function getLastDelete() {
                $dbr = wfGetDB( DB_REPLICA );
-               $commentQuery = CommentStore::newKey( 'log_comment' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'log_comment' );
                $data = $dbr->selectRow(
                        [ 'logging', 'user' ] + $commentQuery['tables'],
                        [
index 6108ca1..4dde52d 100644 (file)
@@ -89,7 +89,7 @@ class FeedUtils {
                        $timestamp,
                        $row->rc_deleted & Revision::DELETED_COMMENT
                                ? wfMessage( 'rev-deleted-comment' )->escaped()
-                               : CommentStore::newKey( 'rc_comment' )->getComment( $row )->text,
+                               : CommentStore::getStore()->getComment( 'rc_comment', $row )->text,
                        $actiontext
                );
        }
index c283793..9077666 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 namespace MediaWiki;
 
+use CommentStore;
 use Config;
 use ConfigFactory;
 use CryptHKDF;
@@ -761,6 +762,14 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'HttpRequestFactory' );
        }
 
+       /**
+        * @since 1.31
+        * @return CommentStore
+        */
+       public function getCommentStore() {
+               return $this->getService( 'CommentStore' );
+       }
+
        ///////////////////////////////////////////////////////////////////////////
        // NOTE: When adding a service getter here, don't forget to add a test
        // case for it in MediaWikiServicesTest::provideGetters() and in
index d5449b4..eba563c 100644 (file)
@@ -357,7 +357,7 @@ class Revision implements IDBAccessObject {
                        'rev_sha1',
                ];
 
-               $fields += CommentStore::newKey( 'rev_comment' )->getFields();
+               $fields += CommentStore::getStore()->getFields( 'rev_comment' );
 
                if ( $wgContentHandlerUseDB ) {
                        $fields[] = 'rev_content_format';
@@ -394,7 +394,7 @@ class Revision implements IDBAccessObject {
                        'ar_sha1',
                ];
 
-               $fields += CommentStore::newKey( 'ar_comment' )->getFields();
+               $fields += CommentStore::getStore()->getFields( 'ar_comment' );
 
                if ( $wgContentHandlerUseDB ) {
                        $fields[] = 'ar_content_format';
index 847c1bb..dc397a2 100644 (file)
@@ -521,6 +521,14 @@ return [
                return new \MediaWiki\Http\HttpRequestFactory();
        },
 
+       'CommentStore' => function ( MediaWikiServices $services ) {
+               global $wgContLang;
+               return new CommentStore(
+                       $wgContLang,
+                       $services->getMainConfig()->get( 'CommentTableSchemaMigrationStage' )
+               );
+       }
+
        ///////////////////////////////////////////////////////////////////////////
        // NOTE: When adding a service here, don't forget to add a getter function
        // in the MediaWikiServices class. The convenience getter should just call
index 79ecec6..b358631 100644 (file)
@@ -360,7 +360,7 @@ class RevisionStore implements IDBAccessObject, RevisionFactory, RevisionLookup
                }
 
                list( $commentFields, $commentCallback ) =
-                       CommentStore::newKey( 'rev_comment' )->insertWithTempTable( $dbw, $comment );
+                       CommentStore::getStore()->insertWithTempTable( $dbw, 'rev_comment', $comment );
                $row += $commentFields;
 
                if ( $this->contentHandlerUseDB ) {
@@ -1036,9 +1036,9 @@ class RevisionStore implements IDBAccessObject, RevisionFactory, RevisionLookup
 
                $user = $this->getUserIdentityFromRowObject( $row, 'ar_' );
 
-               $comment = CommentStore::newKey( 'ar_comment' )
+               $comment = CommentStore::getStore()
                        // Legacy because $row may have come from self::selectFields()
-                       ->getCommentLegacy( $this->getDBConnection( DB_REPLICA ), $row, true );
+                       ->getCommentLegacy( $this->getDBConnection( DB_REPLICA ), 'ar_comment', $row, true );
 
                $mainSlot = $this->emulateMainSlot_1_29( $row, $queryFlags, $title );
                $slots = new RevisionSlots( [ 'main' => $mainSlot ] );
@@ -1106,9 +1106,9 @@ class RevisionStore implements IDBAccessObject, RevisionFactory, RevisionLookup
 
                $user = $this->getUserIdentityFromRowObject( $row );
 
-               $comment = CommentStore::newKey( 'rev_comment' )
+               $comment = CommentStore::getStore()
                        // Legacy because $row may have come from self::selectFields()
-                       ->getCommentLegacy( $this->getDBConnection( DB_REPLICA ), $row, true );
+                       ->getCommentLegacy( $this->getDBConnection( DB_REPLICA ), 'rev_comment', $row, true );
 
                $mainSlot = $this->emulateMainSlot_1_29( $row, $queryFlags, $title );
                $slots = new RevisionSlots( [ 'main' => $mainSlot ] );
@@ -1581,7 +1581,7 @@ class RevisionStore implements IDBAccessObject, RevisionFactory, RevisionLookup
                        'rev_sha1',
                ] );
 
-               $commentQuery = CommentStore::newKey( 'rev_comment' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'rev_comment' );
                $ret['tables'] = array_merge( $ret['tables'], $commentQuery['tables'] );
                $ret['fields'] = array_merge( $ret['fields'], $commentQuery['fields'] );
                $ret['joins'] = array_merge( $ret['joins'], $commentQuery['joins'] );
@@ -1638,7 +1638,7 @@ class RevisionStore implements IDBAccessObject, RevisionFactory, RevisionLookup
         *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
         */
        public function getArchiveQueryInfo() {
-               $commentQuery = CommentStore::newKey( 'ar_comment' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'ar_comment' );
                $ret = [
                        'tables' => [ 'archive' ] + $commentQuery['tables'],
                        'fields' => [
index c4cf434..0cdea35 100644 (file)
@@ -2735,8 +2735,8 @@ class Title implements LinkTarget {
 
                if ( $this->mTitleProtection === null ) {
                        $dbr = wfGetDB( DB_REPLICA );
-                       $commentStore = new CommentStore( 'pt_reason' );
-                       $commentQuery = $commentStore->getJoin();
+                       $commentStore = CommentStore::getStore();
+                       $commentQuery = $commentStore->getJoin( 'pt_reason' );
                        $res = $dbr->select(
                                [ 'protected_titles' ] + $commentQuery['tables'],
                                [
@@ -2757,7 +2757,7 @@ class Title implements LinkTarget {
                                        'user' => $row['user'],
                                        'expiry' => $dbr->decodeExpiry( $row['expiry'] ),
                                        'permission' => $row['permission'],
-                                       'reason' => $commentStore->getComment( $row )->text,
+                                       'reason' => $commentStore->getComment( 'pt_reason', $row )->text,
                                ];
                        } else {
                                $this->mTitleProtection = false;
index 65a4b32..26844f3 100644 (file)
@@ -45,7 +45,7 @@ class ApiQueryAllUsers extends ApiQueryBase {
                $activeUserDays = $this->getConfig()->get( 'ActiveUserDays' );
 
                $db = $this->getDB();
-               $commentStore = new CommentStore( 'ipb_reason' );
+               $commentStore = CommentStore::getStore();
 
                $prop = $params['prop'];
                if ( !is_null( $prop ) ) {
@@ -260,7 +260,7 @@ class ApiQueryAllUsers extends ApiQueryBase {
                                $data['blockedby'] = $row->ipb_by_text;
                                $data['blockedbyid'] = (int)$row->ipb_by;
                                $data['blockedtimestamp'] = wfTimestamp( TS_ISO_8601, $row->ipb_timestamp );
-                               $data['blockreason'] = $commentStore->getComment( $row )->text;
+                               $data['blockreason'] = $commentStore->getComment( 'ipb_reason', $row )->text;
                                $data['blockexpiry'] = $row->ipb_expiry;
                        }
                        if ( $row->ipb_deleted ) {
index e0ab53a..57a70bc 100644 (file)
@@ -451,7 +451,7 @@ abstract class ApiQueryBase extends ApiBase {
                                'ipb_expiry',
                                'ipb_timestamp'
                        ] );
-                       $commentQuery = CommentStore::newKey( 'ipb_reason' )->getJoin();
+                       $commentQuery = CommentStore::getStore()->getJoin( 'ipb_reason' );
                        $this->addTables( $commentQuery['tables'] );
                        $this->addFields( $commentQuery['fields'] );
                        $this->addJoinConds( $commentQuery['joins'] );
index d02fefa..10695b3 100644 (file)
@@ -33,7 +33,7 @@ class ApiQueryBlocks extends ApiQueryBase {
 
        public function execute() {
                $db = $this->getDB();
-               $commentStore = new CommentStore( 'ipb_reason' );
+               $commentStore = CommentStore::getStore();
                $params = $this->extractRequestParams();
                $this->requireMaxOneParameter( $params, 'users', 'ip' );
 
@@ -64,7 +64,7 @@ class ApiQueryBlocks extends ApiQueryBase {
                        $fld_flags );
 
                if ( $fld_reason ) {
-                       $commentQuery = $commentStore->getJoin();
+                       $commentQuery = $commentStore->getJoin( 'ipb_reason' );
                        $this->addTables( $commentQuery['tables'] );
                        $this->addFields( $commentQuery['fields'] );
                        $this->addJoinConds( $commentQuery['joins'] );
@@ -208,7 +208,7 @@ class ApiQueryBlocks extends ApiQueryBase {
                                $block['expiry'] = ApiResult::formatExpiry( $row->ipb_expiry );
                        }
                        if ( $fld_reason ) {
-                               $block['reason'] = $commentStore->getComment( $row )->text;
+                               $block['reason'] = $commentStore->getComment( 'ipb_reason', $row )->text;
                        }
                        if ( $fld_range && !$row->ipb_auto ) {
                                $block['rangestart'] = IP::formatHex( $row->ipb_range_start );
index 5c1f6ba..6e6757e 100644 (file)
@@ -40,7 +40,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
 
                $user = $this->getUser();
                $db = $this->getDB();
-               $commentStore = new CommentStore( 'ar_comment' );
+               $commentStore = CommentStore::getStore();
                $params = $this->extractRequestParams( false );
                $prop = array_flip( $params['prop'] );
                $fld_parentid = isset( $prop['parentid'] );
@@ -117,7 +117,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
                $this->addFieldsIf( 'ar_sha1', $fld_sha1 );
 
                if ( $fld_comment || $fld_parsedcomment ) {
-                       $commentQuery = $commentStore->getJoin();
+                       $commentQuery = $commentStore->getJoin( 'ar_comment' );
                        $this->addTables( $commentQuery['tables'] );
                        $this->addFields( $commentQuery['fields'] );
                        $this->addJoinConds( $commentQuery['joins'] );
@@ -325,7 +325,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
                                        $anyHidden = true;
                                }
                                if ( Revision::userCanBitfield( $row->ar_deleted, Revision::DELETED_COMMENT, $user ) ) {
-                                       $comment = $commentStore->getComment( $row )->text;
+                                       $comment = $commentStore->getComment( 'ar_comment', $row )->text;
                                        if ( $fld_comment ) {
                                                $rev['comment'] = $comment;
                                        }
index d401511..ebffb15 100644 (file)
@@ -41,7 +41,7 @@ class ApiQueryFilearchive extends ApiQueryBase {
 
                $user = $this->getUser();
                $db = $this->getDB();
-               $commentStore = new CommentStore( 'fa_description' );
+               $commentStore = CommentStore::getStore();
 
                $params = $this->extractRequestParams();
 
@@ -155,7 +155,7 @@ class ApiQueryFilearchive extends ApiQueryBase {
                        if ( $fld_description &&
                                Revision::userCanBitfield( $row->fa_deleted, File::DELETED_COMMENT, $user )
                        ) {
-                               $file['description'] = $commentStore->getComment( $row )->text;
+                               $file['description'] = $commentStore->getComment( 'fa_description', $row )->text;
                                if ( isset( $prop['parseddescription'] ) ) {
                                        $file['parseddescription'] = Linker::formatComment(
                                                $file['description'], $title );
index 9d24794..f345300 100644 (file)
@@ -41,7 +41,7 @@ class ApiQueryLogEvents extends ApiQueryBase {
        public function execute() {
                $params = $this->extractRequestParams();
                $db = $this->getDB();
-               $this->commentStore = new CommentStore( 'log_comment' );
+               $this->commentStore = CommentStore::getStore();
                $this->requireMaxOneParameter( $params, 'title', 'prefix', 'namespace' );
 
                $prop = array_flip( $params['prop'] );
@@ -93,7 +93,7 @@ class ApiQueryLogEvents extends ApiQueryBase {
                $this->addFieldsIf( 'log_params', $this->fld_details );
 
                if ( $this->fld_comment || $this->fld_parsedcomment ) {
-                       $commentQuery = $this->commentStore->getJoin();
+                       $commentQuery = $this->commentStore->getJoin( 'log_comment' );
                        $this->addTables( $commentQuery['tables'] );
                        $this->addFields( $commentQuery['fields'] );
                        $this->addJoinConds( $commentQuery['joins'] );
@@ -338,7 +338,7 @@ class ApiQueryLogEvents extends ApiQueryBase {
                                $anyHidden = true;
                        }
                        if ( LogEventsList::userCan( $row, LogPage::DELETED_COMMENT, $user ) ) {
-                               $comment = $this->commentStore->getComment( $row )->text;
+                               $comment = $this->commentStore->getComment( 'log_comment', $row )->text;
                                if ( $this->fld_comment ) {
                                        $vals['comment'] = $comment;
                                }
index 843e209..f526685 100644 (file)
@@ -55,8 +55,8 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase {
                $this->addFieldsIf( 'pt_create_perm', isset( $prop['level'] ) );
 
                if ( isset( $prop['comment'] ) || isset( $prop['parsedcomment'] ) ) {
-                       $commentStore = new CommentStore( 'pt_reason' );
-                       $commentQuery = $commentStore->getJoin();
+                       $commentStore = CommentStore::getStore();
+                       $commentQuery = $commentStore->getJoin( 'pt_reason' );
                        $this->addTables( $commentQuery['tables'] );
                        $this->addFields( $commentQuery['fields'] );
                        $this->addJoinConds( $commentQuery['joins'] );
@@ -130,12 +130,12 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase {
                                }
 
                                if ( isset( $prop['comment'] ) ) {
-                                       $vals['comment'] = $commentStore->getComment( $row )->text;
+                                       $vals['comment'] = $commentStore->getComment( 'pt_reason', $row )->text;
                                }
 
                                if ( isset( $prop['parsedcomment'] ) ) {
                                        $vals['parsedcomment'] = Linker::formatComment(
-                                               $commentStore->getComment( $row )->text, $titles
+                                               $commentStore->getComment( 'pt_reason', $row )->text, $titles
                                        );
                                }
 
index 517cf1f..e289e42 100644 (file)
@@ -350,8 +350,8 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
                $this->token = $params['token'];
 
                if ( $this->fld_comment || $this->fld_parsedcomment || $this->token ) {
-                       $this->commentStore = new CommentStore( 'rc_comment' );
-                       $commentQuery = $this->commentStore->getJoin();
+                       $this->commentStore = CommentStore::getStore();
+                       $commentQuery = $this->commentStore->getJoin( 'rc_comment' );
                        $this->addTables( $commentQuery['tables'] );
                        $this->addFields( $commentQuery['fields'] );
                        $this->addJoinConds( $commentQuery['joins'] );
@@ -506,7 +506,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
                                $anyHidden = true;
                        }
                        if ( Revision::userCanBitfield( $row->rc_deleted, Revision::DELETED_COMMENT, $user ) ) {
-                               $comment = $this->commentStore->getComment( $row )->text;
+                               $comment = $this->commentStore->getComment( 'rc_comment', $row )->text;
                                if ( $this->fld_comment ) {
                                        $vals['comment'] = $comment;
                                }
index 99a582e..1705c57 100644 (file)
@@ -41,7 +41,7 @@ class ApiQueryContributions extends ApiQueryBase {
                // Parse some parameters
                $this->params = $this->extractRequestParams();
 
-               $this->commentStore = new CommentStore( 'rev_comment' );
+               $this->commentStore = CommentStore::getStore();
 
                $prop = array_flip( $this->params['prop'] );
                $this->fld_ids = isset( $prop['ids'] );
@@ -345,7 +345,7 @@ class ApiQueryContributions extends ApiQueryBase {
                $this->addFieldsIf( 'rc_patrolled', $this->fld_patrolled );
 
                if ( $this->fld_comment || $this->fld_parsedcomment ) {
-                       $commentQuery = $this->commentStore->getJoin();
+                       $commentQuery = $this->commentStore->getJoin( 'rev_comment' );
                        $this->addTables( $commentQuery['tables'] );
                        $this->addFields( $commentQuery['fields'] );
                        $this->addJoinConds( $commentQuery['joins'] );
@@ -432,7 +432,7 @@ class ApiQueryContributions extends ApiQueryBase {
                        );
 
                        if ( $userCanView ) {
-                               $comment = $this->commentStore->getComment( $row )->text;
+                               $comment = $this->commentStore->getComment( 'rev_comment', $row )->text;
                                if ( $this->fld_comment ) {
                                        $vals['comment'] = $comment;
                                }
index 6de512b..824c4d5 100644 (file)
@@ -95,7 +95,7 @@ class ApiQueryUsers extends ApiQueryBase {
 
        public function execute() {
                $db = $this->getDB();
-               $commentStore = new CommentStore( 'ipb_reason' );
+               $commentStore = CommentStore::getStore();
 
                $params = $this->extractRequestParams();
                $this->requireMaxOneParameter( $params, 'userids', 'users' );
@@ -235,7 +235,8 @@ class ApiQueryUsers extends ApiQueryBase {
                                        $data[$key]['blockedby'] = $row->ipb_by_text;
                                        $data[$key]['blockedbyid'] = (int)$row->ipb_by;
                                        $data[$key]['blockedtimestamp'] = wfTimestamp( TS_ISO_8601, $row->ipb_timestamp );
-                                       $data[$key]['blockreason'] = $commentStore->getComment( $row )->text;
+                                       $data[$key]['blockreason'] = $commentStore->getComment( 'ipb_reason', $row )
+                                               ->text;
                                        $data[$key]['blockexpiry'] = $row->ipb_expiry;
                                }
 
index f9ac44a..69f1838 100644 (file)
@@ -87,7 +87,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
                        }
 
                        if ( $this->fld_comment || $this->fld_parsedcomment ) {
-                               $this->commentStore = new CommentStore( 'rc_comment' );
+                               $this->commentStore = CommentStore::getStore();
                        }
                }
 
@@ -357,7 +357,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
                                Revision::DELETED_COMMENT,
                                $user
                        ) ) {
-                               $comment = $this->commentStore->getComment( $recentChangeInfo )->text;
+                               $comment = $this->commentStore->getComment( 'rc_comment', $recentChangeInfo )->text;
                                if ( $this->fld_comment ) {
                                        $vals['comment'] = $comment;
                                }
index a471865..678e39a 100644 (file)
@@ -235,7 +235,7 @@ class RecentChange {
                        'rc_log_type',
                        'rc_log_action',
                        'rc_params',
-               ] + CommentStore::newKey( 'rc_comment' )->getFields();
+               ] + CommentStore::getStore()->getFields( 'rc_comment' );
        }
 
        /**
@@ -248,7 +248,7 @@ class RecentChange {
         *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
         */
        public static function getQueryInfo() {
-               $commentQuery = CommentStore::newKey( 'rc_comment' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'rc_comment' );
                return [
                        'tables' => [ 'recentchanges' ] + $commentQuery['tables'],
                        'fields' => [
@@ -372,7 +372,7 @@ class RecentChange {
                $row = $this->mAttribs;
                $comment = $row['rc_comment'];
                unset( $row['rc_comment'], $row['rc_comment_text'], $row['rc_comment_data'] );
-               $row += CommentStore::newKey( 'rc_comment' )->insert( $dbw, $comment );
+               $row += CommentStore::getStore()->insert( $dbw, 'rc_comment', $comment );
 
                # Don't reuse an existing rc_id for the new row, if one happens to be
                # set for some reason.
@@ -995,9 +995,10 @@ class RecentChange {
                        }
                }
 
-               $comment = CommentStore::newKey( 'rc_comment' )
+               $comment = CommentStore::getStore()
                        // Legacy because $row may have come from self::selectFields()
-                       ->getCommentLegacy( wfGetDB( DB_REPLICA ), $row, true )->text;
+                       ->getCommentLegacy( wfGetDB( DB_REPLICA ), 'rc_comment', $row, true )
+                       ->text;
                $this->mAttribs['rc_comment'] = &$comment;
                $this->mAttribs['rc_comment_text'] = &$comment;
                $this->mAttribs['rc_comment_data'] = null;
@@ -1011,7 +1012,8 @@ class RecentChange {
         */
        public function getAttribute( $name ) {
                if ( $name === 'rc_comment' ) {
-                       return CommentStore::newKey( 'rc_comment' )->getComment( $this->mAttribs, true )->text;
+                       return CommentStore::getStore()
+                               ->getComment( 'rc_comment', $this->mAttribs, true )->text;
                }
                return isset( $this->mAttribs[$name] ) ? $this->mAttribs[$name] : null;
        }
index 6e2a5a4..6ce55ea 100644 (file)
@@ -278,7 +278,7 @@ class WikiExporter {
                        }
                        $result = null; // Assuring $result is not undefined, if exception occurs early
 
-                       $commentQuery = CommentStore::newKey( 'log_comment' )->getJoin();
+                       $commentQuery = CommentStore::getStore()->getJoin( 'log_comment' );
 
                        try {
                                $result = $this->db->select( [ 'logging', 'user' ] + $commentQuery['tables'],
@@ -399,7 +399,7 @@ class WikiExporter {
                                Hooks::run( 'ModifyExportQuery',
                                                [ $this->db, &$tables, &$cond, &$opts, &$join ] );
 
-                               $commentQuery = CommentStore::newKey( 'rev_comment' )->getJoin();
+                               $commentQuery = CommentStore::getStore()->getJoin( 'rev_comment' );
 
                                # Do the query!
                                $result = $this->db->select(
index c46eb61..e1c12de 100644 (file)
@@ -219,7 +219,7 @@ class XmlDumpWriter {
                if ( isset( $row->rev_deleted ) && ( $row->rev_deleted & Revision::DELETED_COMMENT ) ) {
                        $out .= "      " . Xml::element( 'comment', [ 'deleted' => 'deleted' ] ) . "\n";
                } else {
-                       $comment = CommentStore::newKey( 'rev_comment' )->getComment( $row )->text;
+                       $comment = CommentStore::getStore()->getComment( 'rev_comment', $row )->text;
                        if ( $comment != '' ) {
                                $out .= "      " . Xml::elementClean( 'comment', [], strval( $comment ) ) . "\n";
                        }
@@ -303,7 +303,7 @@ class XmlDumpWriter {
                if ( $row->log_deleted & LogPage::DELETED_COMMENT ) {
                        $out .= "    " . Xml::element( 'comment', [ 'deleted' => 'deleted' ] ) . "\n";
                } else {
-                       $comment = CommentStore::newKey( 'log_comment' )->getComment( $row )->text;
+                       $comment = CommentStore::getStore()->getComment( 'log_comment', $row )->text;
                        if ( $comment != '' ) {
                                $out .= "    " . Xml::elementClean( 'comment', null, strval( $comment ) ) . "\n";
                        }
index 7f48659..6577ab6 100644 (file)
@@ -242,7 +242,7 @@ class ArchivedFile {
                        'fa_deleted',
                        'fa_deleted_timestamp', /* Used by LocalFileRestoreBatch */
                        'fa_sha1',
-               ] + CommentStore::newKey( 'fa_description' )->getFields();
+               ] + CommentStore::getStore()->getFields( 'fa_description' );
        }
 
        /**
@@ -255,7 +255,7 @@ class ArchivedFile {
         *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
         */
        public static function getQueryInfo() {
-               $commentQuery = CommentStore::newKey( 'fa_description' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'fa_description' );
                return [
                        'tables' => [ 'filearchive' ] + $commentQuery['tables'],
                        'fields' => [
@@ -302,9 +302,9 @@ class ArchivedFile {
                $this->metadata = $row->fa_metadata;
                $this->mime = "$row->fa_major_mime/$row->fa_minor_mime";
                $this->media_type = $row->fa_media_type;
-               $this->description = CommentStore::newKey( 'fa_description' )
+               $this->description = CommentStore::getStore()
                        // Legacy because $row may have come from self::selectFields()
-                       ->getCommentLegacy( wfGetDB( DB_REPLICA ), $row )->text;
+                       ->getCommentLegacy( wfGetDB( DB_REPLICA ), 'fa_description', $row )->text;
                $this->user = $row->fa_user;
                $this->user_text = $row->fa_user_text;
                $this->timestamp = $row->fa_timestamp;
index 7be8f06..bf1181f 100644 (file)
@@ -215,7 +215,7 @@ class LocalFile extends File {
                        'img_user_text',
                        'img_timestamp',
                        'img_sha1',
-               ] + CommentStore::newKey( 'img_description' )->getFields();
+               ] + CommentStore::getStore()->getFields( 'img_description' );
        }
 
        /**
@@ -230,7 +230,7 @@ class LocalFile extends File {
         *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
         */
        public static function getQueryInfo( array $options = [] ) {
-               $commentQuery = CommentStore::newKey( 'img_description' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'img_description' );
                $ret = [
                        'tables' => [ 'image' ] + $commentQuery['tables'],
                        'fields' => [
@@ -566,8 +566,8 @@ class LocalFile extends File {
        function decodeRow( $row, $prefix = 'img_' ) {
                $decoded = $this->unprefixRow( $row, $prefix );
 
-               $decoded['description'] = CommentStore::newKey( 'description' )
-                       ->getComment( (object)$decoded )->text;
+               $decoded['description'] = CommentStore::getStore()
+                       ->getComment( 'description', (object)$decoded )->text;
 
                $decoded['timestamp'] = wfTimestamp( TS_MW, $decoded['timestamp'] );
 
@@ -1424,9 +1424,9 @@ class LocalFile extends File {
                # Test to see if the row exists using INSERT IGNORE
                # This avoids race conditions by locking the row until the commit, and also
                # doesn't deadlock. SELECT FOR UPDATE causes a deadlock for every race condition.
-               $commentStore = new CommentStore( 'img_description' );
+               $commentStore = CommentStore::getStore();
                list( $commentFields, $commentCallback ) =
-                       $commentStore->insertWithTempTable( $dbw, $comment );
+                       $commentStore->insertWithTempTable( $dbw, 'img_description', $comment );
                $dbw->insert( 'image',
                        [
                                'img_name' => $this->getName(),
@@ -1522,7 +1522,9 @@ class LocalFile extends File {
                                        [ 'image_comment_temp' => [ 'LEFT JOIN', [ 'imgcomment_name = img_name' ] ] ]
                                );
                                foreach ( $res as $row ) {
-                                       list( , $callback ) = $commentStore->insertWithTempTable( $dbw, $row->img_description );
+                                       list( , $callback ) = $commentStore->insertWithTempTable(
+                                               $dbw, 'img_description', $row->img_description
+                                       );
                                        $callback( $row->img_name );
                                }
                        }
@@ -2403,10 +2405,7 @@ class LocalFileDeleteBatch {
                $now = time();
                $dbw = $this->file->repo->getMasterDB();
 
-               $commentStoreImgDesc = new CommentStore( 'img_description' );
-               $commentStoreOiDesc = new CommentStore( 'oi_description' );
-               $commentStoreFaDesc = new CommentStore( 'fa_description' );
-               $commentStoreFaReason = new CommentStore( 'fa_deleted_reason' );
+               $commentStore = CommentStore::getStore();
 
                $encTimestamp = $dbw->addQuotes( $dbw->timestamp( $now ) );
                $encUserId = $dbw->addQuotes( $this->user->getId() );
@@ -2454,7 +2453,7 @@ class LocalFileDeleteBatch {
 
                        $fields += array_map(
                                [ $dbw, 'addQuotes' ],
-                               $commentStoreFaReason->insert( $dbw, $this->reason )
+                               $commentStore->insert( $dbw, 'fa_deleted_reason', $this->reason )
                        );
 
                        if ( $wgCommentTableSchemaMigrationStage <= MIGRATION_WRITE_BOTH ) {
@@ -2484,7 +2483,9 @@ class LocalFileDeleteBatch {
                                        [ 'image_comment_temp' => [ 'LEFT JOIN', [ 'imgcomment_name = img_name' ] ] ]
                                );
                                foreach ( $res as $row ) {
-                                       list( , $callback ) = $commentStoreImgDesc->insertWithTempTable( $dbw, $row->img_description );
+                                       list( , $callback ) = $commentStore->insertWithTempTable(
+                                               $dbw, 'img_description', $row->img_description
+                                       );
                                        $callback( $row->img_name );
                                }
                        }
@@ -2508,9 +2509,9 @@ class LocalFileDeleteBatch {
                        );
                        $rowsInsert = [];
                        if ( $res->numRows() ) {
-                               $reason = $commentStoreFaReason->createComment( $dbw, $this->reason );
+                               $reason = $commentStore->createComment( $dbw, 'fa_deleted_reason', $this->reason );
                                foreach ( $res as $row ) {
-                                       $comment = $commentStoreOiDesc->getComment( $row );
+                                       $comment = $commentStore->getComment( 'oi_description', $row );
                                        $rowsInsert[] = [
                                                // Deletion-specific fields
                                                'fa_storage_group' => 'deleted',
@@ -2535,8 +2536,8 @@ class LocalFileDeleteBatch {
                                                'fa_user_text' => $row->oi_user_text,
                                                'fa_timestamp' => $row->oi_timestamp,
                                                'fa_sha1' => $row->oi_sha1
-                                       ] + $commentStoreFaReason->insert( $dbw, $reason )
-                                       + $commentStoreFaDesc->insert( $dbw, $comment );
+                                       ] + $commentStore->insert( $dbw, 'fa_deleted_reason', $reason )
+                                       + $commentStore->insert( $dbw, 'fa_description', $comment );
                                }
                        }
 
@@ -2734,9 +2735,7 @@ class LocalFileRestoreBatch {
 
                $dbw = $this->file->repo->getMasterDB();
 
-               $commentStoreImgDesc = new CommentStore( 'img_description' );
-               $commentStoreOiDesc = new CommentStore( 'oi_description' );
-               $commentStoreFaDesc = new CommentStore( 'fa_description' );
+               $commentStore = CommentStore::getStore();
 
                $status = $this->file->repo->newGood();
 
@@ -2824,12 +2823,12 @@ class LocalFileRestoreBatch {
                                ];
                        }
 
-                       $comment = $commentStoreFaDesc->getComment( $row );
+                       $comment = $commentStore->getComment( 'fa_description', $row );
                        if ( $first && !$exists ) {
                                // This revision will be published as the new current version
                                $destRel = $this->file->getRel();
                                list( $commentFields, $commentCallback ) =
-                                       $commentStoreImgDesc->insertWithTempTable( $dbw, $comment );
+                                       $commentStore->insertWithTempTable( $dbw, 'img_description', $comment );
                                $insertCurrent = [
                                        'img_name' => $row->fa_name,
                                        'img_size' => $row->fa_size,
@@ -2885,7 +2884,7 @@ class LocalFileRestoreBatch {
                                        'oi_minor_mime' => $props['minor_mime'],
                                        'oi_deleted' => $this->unsuppress ? 0 : $row->fa_deleted,
                                        'oi_sha1' => $sha1
-                               ] + $commentStoreOiDesc->insert( $dbw, $comment );
+                               ] + $commentStore->insert( $dbw, 'oi_description', $comment );
                        }
 
                        $deleteIds[] = $row->fa_id;
index 69e6896..d08d0ae 100644 (file)
@@ -127,7 +127,7 @@ class OldLocalFile extends LocalFile {
                        'oi_timestamp',
                        'oi_deleted',
                        'oi_sha1',
-               ] + CommentStore::newKey( 'oi_description' )->getFields();
+               ] + CommentStore::getStore()->getFields( 'oi_description' );
        }
 
        /**
@@ -142,7 +142,7 @@ class OldLocalFile extends LocalFile {
         *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
         */
        public static function getQueryInfo( array $options = [] ) {
-               $commentQuery = CommentStore::newKey( 'oi_description' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'oi_description' );
                $ret = [
                        'tables' => [ 'oldimage' ] + $commentQuery['tables'],
                        'fields' => [
@@ -434,7 +434,7 @@ class OldLocalFile extends LocalFile {
                        return false;
                }
 
-               $commentFields = CommentStore::newKey( 'oi_description' )->insert( $dbw, $comment );
+               $commentFields = CommentStore::getStore()->insert( $dbw, 'oi_description', $comment );
                $dbw->insert( 'oldimage',
                        [
                                'oi_name' => $this->getName(),
index edb0c9a..3513f8c 100644 (file)
@@ -729,7 +729,7 @@ class WikiRevision {
                        'log_namespace' => $this->getTitle()->getNamespace(),
                        'log_title' => $this->getTitle()->getDBkey(),
                        'log_params' => $this->params
-               ] + CommentStore::newKey( 'log_comment' )->insert( $dbw, $this->getComment() );
+               ] + CommentStore::getStore()->insert( $dbw, 'log_comment', $this->getComment() );
                $dbw->insert( 'logging', $data, __METHOD__ );
 
                return true;
index bf35d78..16b3593 100644 (file)
@@ -170,7 +170,7 @@ class DatabaseLogEntry extends LogEntryBase {
         * @return array
         */
        public static function getSelectQueryData() {
-               $commentQuery = CommentStore::newKey( 'log_comment' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'log_comment' );
 
                $tables = [ 'logging', 'user' ] + $commentQuery['tables'];
                $fields = [
@@ -324,7 +324,7 @@ class DatabaseLogEntry extends LogEntryBase {
        }
 
        public function getComment() {
-               return CommentStore::newKey( 'log_comment' )->getComment( $this->row )->text;
+               return CommentStore::getStore()->getComment( 'log_comment', $this->row )->text;
        }
 
        public function getDeleted() {
@@ -382,9 +382,9 @@ class RCDatabaseLogEntry extends DatabaseLogEntry {
        }
 
        public function getComment() {
-               return CommentStore::newKey( 'rc_comment' )
+               return CommentStore::getStore()
                        // Legacy because the row may have used RecentChange::selectFields()
-                       ->getCommentLegacy( wfGetDB( DB_REPLICA ), $this->row )->text;
+                       ->getCommentLegacy( wfGetDB( DB_REPLICA ), 'rc_comment', $this->row )->text;
        }
 
        public function getDeleted() {
@@ -626,7 +626,7 @@ class ManualLogEntry extends LogEntryBase {
                if ( isset( $this->deleted ) ) {
                        $data['log_deleted'] = $this->deleted;
                }
-               $data += CommentStore::newKey( 'log_comment' )->insert( $dbw, $comment );
+               $data += CommentStore::getStore()->insert( $dbw, 'log_comment', $comment );
 
                $dbw->insert( 'logging', $data, __METHOD__ );
                $this->id = $dbw->insertId();
index 77d9aa2..c84352e 100644 (file)
@@ -104,7 +104,7 @@ class LogPage {
                        'log_page' => $this->target->getArticleID(),
                        'log_params' => $this->params
                ];
-               $data += CommentStore::newKey( 'log_comment' )->insert( $dbw, $this->comment );
+               $data += CommentStore::getStore()->insert( $dbw, 'log_comment', $this->comment );
                $dbw->insert( 'logging', $data, __METHOD__ );
                $newId = $dbw->insertId();
 
index a7f53df..a7eed5a 100644 (file)
@@ -2517,7 +2517,7 @@ class WikiPage implements Page, IDBAccessObject {
                        $cascade = false;
 
                        if ( $limit['create'] != '' ) {
-                               $commentFields = CommentStore::newKey( 'pt_reason' )->insert( $dbw, $reason );
+                               $commentFields = CommentStore::getStore()->insert( $dbw, 'pt_reason', $reason );
                                $dbw->replace( 'protected_titles',
                                        [ [ 'pt_namespace', 'pt_title' ] ],
                                        [
@@ -2844,8 +2844,7 @@ class WikiPage implements Page, IDBAccessObject {
                        $content = null;
                }
 
-               $revCommentStore = new CommentStore( 'rev_comment' );
-               $arCommentStore = new CommentStore( 'ar_comment' );
+               $commentStore = CommentStore::getStore();
 
                $revQuery = Revision::getQueryInfo();
                $bitfield = false;
@@ -2881,7 +2880,7 @@ class WikiPage implements Page, IDBAccessObject {
                $ipRevIds = [];
 
                foreach ( $res as $row ) {
-                       $comment = $revCommentStore->getComment( $row );
+                       $comment = $commentStore->getComment( 'rev_comment', $row );
                        $rowInsert = [
                                'ar_namespace'  => $namespace,
                                'ar_title'      => $dbKey,
@@ -2898,7 +2897,7 @@ class WikiPage implements Page, IDBAccessObject {
                                'ar_page_id'    => $id,
                                'ar_deleted'    => $suppress ? $bitfield : $row->rev_deleted,
                                'ar_sha1'       => $row->rev_sha1,
-                       ] + $arCommentStore->insert( $dbw, $comment );
+                       ] + $commentStore->insert( $dbw, 'ar_comment', $comment );
                        if ( $wgContentHandlerUseDB ) {
                                $rowInsert['ar_content_model'] = $row->rev_content_model;
                                $rowInsert['ar_content_format'] = $row->rev_content_format;
index 531a3eb..158ee59 100644 (file)
@@ -94,7 +94,7 @@ class IRCColourfulRCFeedFormatter implements RCFeedFormatter {
                        $flag = $attribs['rc_log_action'];
                } else {
                        $comment = self::cleanupForIRC(
-                               CommentStore::newKey( 'rc_comment' )->getComment( $attribs )->text
+                               CommentStore::getStore()->getComment( 'rc_comment', $attribs )->text
                        );
                        $flag = '';
                        if ( !$attribs['rc_patrolled']
index 998c695..b8b0c5c 100644 (file)
@@ -102,7 +102,7 @@ class RevDelLogItem extends RevDelItem {
                // User links and action text
                $action = $formatter->getActionText();
                // Comment
-               $comment = CommentStore::newKey( 'log_comment' )->getComment( $this->row )->text;
+               $comment = CommentStore::getStore()->getComment( 'log_comment', $this->row )->text;
                $comment = $this->list->getLanguage()->getDirMark()
                        . Linker::commentBlock( $comment );
 
@@ -136,7 +136,8 @@ class RevDelLogItem extends RevDelItem {
                }
                if ( LogEventsList::userCan( $this->row, LogPage::DELETED_COMMENT, $user ) ) {
                        $ret += [
-                               'comment' => CommentStore::newKey( 'log_comment' )->getComment( $this->row )->text,
+                               'comment' => CommentStore::getStore()->getComment( 'log_comment', $this->row )
+                                       ->text,
                        ];
                }
 
index 728deb8..f4e4faf 100644 (file)
@@ -63,7 +63,7 @@ class RevDelLogList extends RevDelList {
        public function doQuery( $db ) {
                $ids = array_map( 'intval', $this->ids );
 
-               $commentQuery = CommentStore::newKey( 'log_comment' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'log_comment' );
 
                return $db->select(
                        [ 'logging' ] + $commentQuery['tables'],
index 1639386..ea0f0ed 100644 (file)
@@ -295,7 +295,7 @@ class SpecialNewpages extends IncludableSpecialPage {
         */
        protected function revisionFromRcResult( stdClass $result, Title $title ) {
                return new Revision( [
-                       'comment' => CommentStore::newKey( 'rc_comment' )->getComment( $result )->text,
+                       'comment' => CommentStore::getStore()->getComment( 'rc_comment', $result )->text,
                        'deleted' => $result->rc_deleted,
                        'user_text' => $result->rc_user_text,
                        'user' => $result->rc_user,
index 924fd06..fe7cac0 100644 (file)
@@ -173,7 +173,7 @@ class BlockListPager extends TablePager {
                                break;
 
                        case 'ipb_reason':
-                               $value = CommentStore::newKey( 'ipb_reason' )->getComment( $row )->text;
+                               $value = CommentStore::getStore()->getComment( 'ipb_reason', $row )->text;
                                $formatted = Linker::formatComment( $value );
                                break;
 
@@ -209,7 +209,7 @@ class BlockListPager extends TablePager {
        }
 
        function getQueryInfo() {
-               $commentQuery = CommentStore::newKey( 'ipb_reason' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'ipb_reason' );
 
                $info = [
                        'tables' => [ 'ipblocks', 'user' ] + $commentQuery['tables'],
index 38a332e..8a76efb 100644 (file)
@@ -69,7 +69,7 @@ class DeletedContribsPager extends IndexPager {
                                ' != ' . Revision::SUPPRESSED_USER;
                }
 
-               $commentQuery = CommentStore::newKey( 'ar_comment' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'ar_comment' );
 
                return [
                        'tables' => [ 'archive' ] + $commentQuery['tables'],
@@ -256,7 +256,7 @@ class DeletedContribsPager extends IndexPager {
                $rev = new Revision( [
                        'title' => $page,
                        'id' => $row->ar_rev_id,
-                       'comment' => CommentStore::newKey( 'ar_comment' )->getComment( $row )->text,
+                       'comment' => CommentStore::getStore()->getComment( 'ar_comment', $row )->text,
                        'user' => $row->ar_user,
                        'user_text' => $row->ar_user_text,
                        'timestamp' => $row->ar_timestamp,
index d80946a..ae19d59 100644 (file)
@@ -267,7 +267,7 @@ class ImageListPager extends TablePager {
                $options = $join_conds = [];
 
                # Description field
-               $commentQuery = CommentStore::newKey( $prefix . '_description' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( $prefix . '_description' );
                $tables += $commentQuery['tables'];
                $fields += $commentQuery['fields'];
                $join_conds += $commentQuery['joins'];
@@ -498,7 +498,7 @@ class ImageListPager extends TablePager {
                                return htmlspecialchars( $this->getLanguage()->formatSize( $value ) );
                        case 'img_description':
                                $field = $this->mCurrentRow->description_field;
-                               $value = CommentStore::newKey( $field )->getComment( $this->mCurrentRow )->text;
+                               $value = CommentStore::getStore()->getComment( $field, $this->mCurrentRow )->text;
                                return Linker::formatComment( $value );
                        case 'count':
                                return $this->getLanguage()->formatNum( intval( $value ) + 1 );
index a87bbb7..61b648d 100644 (file)
@@ -90,7 +90,7 @@ class NewPagesPager extends ReverseChronologicalPager {
                        $conds['page_is_redirect'] = 0;
                }
 
-               $commentQuery = CommentStore::newKey( 'rc_comment' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'rc_comment' );
 
                // Allow changes to the New Pages query
                $tables = [ 'recentchanges', 'page' ] + $commentQuery['tables'];
index af04703..c4ea5f8 100644 (file)
@@ -234,7 +234,7 @@ class ProtectedPagesPager extends TablePager {
                                                LogPage::DELETED_COMMENT,
                                                $this->getUser()
                                        ) ) {
-                                               $value = CommentStore::newKey( 'log_comment' )->getComment( $row )->text;
+                                               $value = CommentStore::getStore()->getComment( 'log_comment', $row )->text;
                                                $formatted = Linker::formatComment( $value !== null ? $value : '' );
                                        } else {
                                                $formatted = $this->msg( 'rev-deleted-comment' )->escaped();
@@ -283,7 +283,7 @@ class ProtectedPagesPager extends TablePager {
                        $conds[] = 'page_namespace=' . $this->mDb->addQuotes( $this->namespace );
                }
 
-               $commentQuery = CommentStore::newKey( 'log_comment' )->getJoin();
+               $commentQuery = CommentStore::getStore()->getJoin( 'log_comment' );
 
                return [
                        'tables' => [ 'page', 'page_restrictions', 'log_search', 'logging' ] + $commentQuery['tables'],
index 3478b08..d546f0a 100644 (file)
@@ -56,12 +56,12 @@ class WatchedItemQueryService {
        /** @var WatchedItemQueryServiceExtension[]|null */
        private $extensions = null;
 
-       /**
-        * @var CommentStore|null */
-       private $commentStore = null;
+       /** @var CommentStore */
+       private $commentStore;
 
        public function __construct( LoadBalancer $loadBalancer ) {
                $this->loadBalancer = $loadBalancer;
+               $this->commentStore = CommentStore::getStore();
        }
 
        /**
@@ -83,13 +83,6 @@ class WatchedItemQueryService {
                return $this->loadBalancer->getConnectionRef( DB_REPLICA, [ 'watchlist' ] );
        }
 
-       private function getCommentStore() {
-               if ( !$this->commentStore ) {
-                       $this->commentStore = new CommentStore( 'rc_comment' );
-               }
-               return $this->commentStore;
-       }
-
        /**
         * @param User $user
         * @param array $options Allowed keys:
@@ -334,7 +327,7 @@ class WatchedItemQueryService {
                        $tables[] = 'page';
                }
                if ( in_array( self::INCLUDE_COMMENT, $options['includeFields'] ) ) {
-                       $tables += $this->getCommentStore()->getJoin()['tables'];
+                       $tables += $this->commentStore->getJoin( 'rc_comment' )['tables'];
                }
                if ( in_array( self::INCLUDE_TAGS, $options['includeFields'] ) ) {
                        $tables[] = 'tag_summary';
@@ -377,7 +370,7 @@ class WatchedItemQueryService {
                        $fields[] = 'rc_user';
                }
                if ( in_array( self::INCLUDE_COMMENT, $options['includeFields'] ) ) {
-                       $fields += $this->getCommentStore()->getJoin()['fields'];
+                       $fields += $this->commentStore->getJoin( 'rc_comment' )['fields'];
                }
                if ( in_array( self::INCLUDE_PATROL_INFO, $options['includeFields'] ) ) {
                        $fields = array_merge( $fields, [ 'rc_patrolled', 'rc_log_type' ] );
@@ -684,7 +677,7 @@ class WatchedItemQueryService {
                        $joinConds['page'] = [ 'LEFT JOIN', 'rc_cur_id=page_id' ];
                }
                if ( in_array( self::INCLUDE_COMMENT, $options['includeFields'] ) ) {
-                       $joinConds += $this->getCommentStore()->getJoin()['joins'];
+                       $joinConds += $this->commentStore->getJoin( 'rc_comment' )['joins'];
                }
                if ( in_array( self::INCLUDE_TAGS, $options['includeFields'] ) ) {
                        $joinConds['tag_summary'] = [ 'LEFT JOIN', [ 'rc_id=ts_rc_id' ] ];
index a1cf166..945df32 100644 (file)
@@ -75,13 +75,13 @@ class Orphans extends Maintenance {
         */
        private function checkOrphans( $fix ) {
                $dbw = $this->getDB( DB_MASTER );
-               $commentStore = new CommentStore( 'rev_comment' );
+               $commentStore = CommentStore::getStore();
 
                if ( $fix ) {
                        $this->lockTables( $dbw );
                }
 
-               $commentQuery = $commentStore->getJoin();
+               $commentQuery = $commentStore->getJoin( 'rev_comment' );
 
                $this->output( "Checking for orphan revision table entries... "
                        . "(this may take a while on a large wiki)\n" );
@@ -104,7 +104,7 @@ class Orphans extends Maintenance {
                        ) );
 
                        foreach ( $result as $row ) {
-                               $comment = $commentStore->getComment( $row )->text;
+                               $comment = $commentStore->getComment( 'rev_comment', $row )->text;
                                if ( $comment !== '' ) {
                                        $comment = '(' . $wgContLang->truncate( $comment, 40 ) . ')';
                                }
index f26d8b3..672bae8 100644 (file)
@@ -80,8 +80,7 @@ class RebuildRecentchanges extends Maintenance {
         */
        private function rebuildRecentChangesTablePass1() {
                $dbw = $this->getDB( DB_MASTER );
-               $revCommentStore = new CommentStore( 'rev_comment' );
-               $rcCommentStore = new CommentStore( 'rc_comment' );
+               $commentStore = CommentStore::getStore();
 
                if ( $this->hasOption( 'from' ) && $this->hasOption( 'to' ) ) {
                        $this->cutoffFrom = wfTimestamp( TS_UNIX, $this->getOption( 'from' ) );
@@ -116,7 +115,7 @@ class RebuildRecentchanges extends Maintenance {
 
                $this->output( "Loading from page and revision tables...\n" );
 
-               $commentQuery = $revCommentStore->getJoin();
+               $commentQuery = $commentStore->getJoin( 'rev_comment' );
                $res = $dbw->select(
                        [ 'revision', 'page' ] + $commentQuery['tables'],
                        [
@@ -145,7 +144,7 @@ class RebuildRecentchanges extends Maintenance {
                $this->output( "Inserting from page and revision tables...\n" );
                $inserted = 0;
                foreach ( $res as $row ) {
-                       $comment = $revCommentStore->getComment( $row );
+                       $comment = $commentStore->getComment( 'rev_comment', $row );
                        $dbw->insert(
                                'recentchanges',
                                [
@@ -163,7 +162,7 @@ class RebuildRecentchanges extends Maintenance {
                                        'rc_type' => $row->page_is_new ? RC_NEW : RC_EDIT,
                                        'rc_source' => $row->page_is_new ? RecentChange::SRC_NEW : RecentChange::SRC_EDIT,
                                        'rc_deleted' => $row->rev_deleted
-                               ] + $rcCommentStore->insert( $dbw, $comment ),
+                               ] + $commentStore->insert( $dbw, 'rc_comment', $comment ),
                                __METHOD__
                        );
                        if ( ( ++$inserted % $this->getBatchSize() ) == 0 ) {
@@ -270,12 +269,11 @@ class RebuildRecentchanges extends Maintenance {
                global $wgLogTypes, $wgLogRestrictions;
 
                $dbw = $this->getDB( DB_MASTER );
-               $logCommentStore = new CommentStore( 'log_comment' );
-               $rcCommentStore = new CommentStore( 'rc_comment' );
+               $commentStore = CommentStore::getStore();
 
                $this->output( "Loading from user, page, and logging tables...\n" );
 
-               $commentQuery = $logCommentStore->getJoin();
+               $commentQuery = $commentStore->getJoin( 'log_comment' );
                $res = $dbw->select(
                        [ 'user', 'logging', 'page' ] + $commentQuery['tables'],
                        [
@@ -311,7 +309,7 @@ class RebuildRecentchanges extends Maintenance {
 
                $inserted = 0;
                foreach ( $res as $row ) {
-                       $comment = $logCommentStore->getComment( $row );
+                       $comment = $commentStore->getComment( 'log_comment', $row );
                        $dbw->insert(
                                'recentchanges',
                                [
@@ -336,7 +334,7 @@ class RebuildRecentchanges extends Maintenance {
                                        'rc_logid' => $row->log_id,
                                        'rc_params' => $row->log_params,
                                        'rc_deleted' => $row->log_deleted
-                               ] + $rcCommentStore->insert( $dbw, $comment ),
+                               ] + $commentStore->insert( $dbw, 'rc_comment', $comment ),
                                __METHOD__
                        );
 
index 9369f30..84e1f32 100644 (file)
@@ -20,11 +20,22 @@ class CommentStoreTest extends MediaWikiLangTestCase {
        /**
         * Create a store for a particular stage
         * @param int $stage
+        * @return CommentStore
+        */
+       protected function makeStore( $stage ) {
+               global $wgContLang;
+               $store = new CommentStore( $wgContLang, $stage );
+               return $store;
+       }
+
+       /**
+        * Create a store for a particular stage and key (for testing deprecated behaviour)
+        * @param int $stage
         * @param string $key
         * @return CommentStore
         */
-       protected function makeStore( $stage, $key ) {
-               $store = new CommentStore( $key );
+       protected function makeStoreWithKey( $stage, $key ) {
+               $store = CommentStore::newKey( $key );
                TestingAccessWrapper::newFromObject( $store )->stage = $stage;
                return $store;
        }
@@ -35,12 +46,24 @@ class CommentStoreTest extends MediaWikiLangTestCase {
         * @param string $key
         * @param array $expect
         */
-       public function testGetFields( $stage, $key, $expect ) {
-               $store = $this->makeStore( $stage, $key );
+       public function testGetFields_withKeyConstruction( $stage, $key, $expect ) {
+               $store = $this->makeStoreWithKey( $stage, $key );
                $result = $store->getFields();
                $this->assertEquals( $expect, $result );
        }
 
+       /**
+        * @dataProvider provideGetFields
+        * @param int $stage
+        * @param string $key
+        * @param array $expect
+        */
+       public function testGetFields( $stage, $key, $expect ) {
+               $store = $this->makeStore( $stage );
+               $result = $store->getFields( $key );
+               $this->assertEquals( $expect, $result );
+       }
+
        public static function provideGetFields() {
                return [
                        'Simple table, old' => [
@@ -110,12 +133,24 @@ class CommentStoreTest extends MediaWikiLangTestCase {
         * @param string $key
         * @param array $expect
         */
-       public function testGetJoin( $stage, $key, $expect ) {
-               $store = $this->makeStore( $stage, $key );
+       public function testGetJoin_withKeyConstruction( $stage, $key, $expect ) {
+               $store = $this->makeStoreWithKey( $stage, $key );
                $result = $store->getJoin();
                $this->assertEquals( $expect, $result );
        }
 
+       /**
+        * @dataProvider provideGetJoin
+        * @param int $stage
+        * @param string $key
+        * @param array $expect
+        */
+       public function testGetJoin( $stage, $key, $expect ) {
+               $store = $this->makeStore( $stage );
+               $result = $store->getJoin( $key );
+               $this->assertEquals( $expect, $result );
+       }
+
        public static function provideGetJoin() {
                return [
                        'Simple table, old' => [
@@ -343,11 +378,106 @@ class CommentStoreTest extends MediaWikiLangTestCase {
                                $extraFields['ipb_address'] = __CLASS__ . "#$writeStage";
                        }
 
-                       $wstore = $this->makeStore( $writeStage, $key );
+                       $wstore = $this->makeStore( $writeStage );
                        $usesTemp = $key === 'rev_comment';
 
                        if ( $usesTemp ) {
-                               list( $fields, $callback ) = $wstore->insertWithTempTable( $this->db, $comment, $data );
+                               list( $fields, $callback ) = $wstore->insertWithTempTable(
+                                       $this->db, $key, $comment, $data
+                               );
+                       } else {
+                               $fields = $wstore->insert( $this->db, $key, $comment, $data );
+                       }
+
+                       if ( $writeStage <= MIGRATION_WRITE_BOTH ) {
+                               $this->assertSame( $expect['text'], $fields[$key], "old field, stage=$writeStage" );
+                       } else {
+                               $this->assertArrayNotHasKey( $key, $fields, "old field, stage=$writeStage" );
+                       }
+                       if ( $writeStage >= MIGRATION_WRITE_BOTH && !$usesTemp ) {
+                               $this->assertArrayHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
+                       } else {
+                               $this->assertArrayNotHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
+                       }
+
+                       $this->db->insert( $table, $extraFields + $fields, __METHOD__ );
+                       $id = $this->db->insertId();
+                       if ( $usesTemp ) {
+                               $callback( $id );
+                       }
+
+                       for ( $readStage = $readRange[0]; $readStage <= $readRange[1]; $readStage++ ) {
+                               $rstore = $this->makeStore( $readStage );
+
+                               $fieldRow = $this->db->selectRow(
+                                       $table,
+                                       $rstore->getFields( $key ),
+                                       [ $pk => $id ],
+                                       __METHOD__
+                               );
+
+                               $queryInfo = $rstore->getJoin( $key );
+                               $joinRow = $this->db->selectRow(
+                                       [ $table ] + $queryInfo['tables'],
+                                       $queryInfo['fields'],
+                                       [ $pk => $id ],
+                                       __METHOD__,
+                                       [],
+                                       $queryInfo['joins']
+                               );
+
+                               $this->assertComment(
+                                       $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
+                                       $rstore->getCommentLegacy( $this->db, $key, $fieldRow ),
+                                       "w=$writeStage, r=$readStage, from getFields()"
+                               );
+                               $this->assertComment(
+                                       $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
+                                       $rstore->getComment( $key, $joinRow ),
+                                       "w=$writeStage, r=$readStage, from getJoin()"
+                               );
+                       }
+               }
+       }
+
+       /**
+        * @dataProvider provideInsertRoundTrip
+        * @param string $table
+        * @param string $key
+        * @param string $pk
+        * @param string $extraFields
+        * @param string|Message $comment
+        * @param array|null $data
+        * @param array $expect
+        */
+       public function testInsertRoundTrip_withKeyConstruction(
+               $table, $key, $pk, $extraFields, $comment, $data, $expect
+       ) {
+               $expectOld = [
+                       'text' => $expect['text'],
+                       'message' => new RawMessage( '$1', [ $expect['text'] ] ),
+                       'data' => null,
+               ];
+
+               $stages = [
+                       MIGRATION_OLD => [ MIGRATION_OLD, MIGRATION_WRITE_NEW ],
+                       MIGRATION_WRITE_BOTH => [ MIGRATION_OLD, MIGRATION_NEW ],
+                       MIGRATION_WRITE_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_NEW ],
+                       MIGRATION_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_NEW ],
+               ];
+
+               foreach ( $stages as $writeStage => $readRange ) {
+                       if ( $key === 'ipb_reason' ) {
+                               $extraFields['ipb_address'] = __CLASS__ . "#$writeStage";
+                       }
+
+                       $wstore = $this->makeStoreWithKey( $writeStage, $key );
+                       $usesTemp = $key === 'rev_comment';
+
+                       if ( $usesTemp ) {
+                               list( $fields, $callback ) = $wstore->insertWithTempTable(
+                                       $this->db, $comment, $data
+                               );
                        } else {
                                $fields = $wstore->insert( $this->db, $comment, $data );
                        }
@@ -370,7 +500,7 @@ class CommentStoreTest extends MediaWikiLangTestCase {
                        }
 
                        for ( $readStage = $readRange[0]; $readStage <= $readRange[1]; $readStage++ ) {
-                               $rstore = $this->makeStore( $readStage, $key );
+                               $rstore = $this->makeStoreWithKey( $readStage, $key );
 
                                $fieldRow = $this->db->selectRow(
                                        $table,
@@ -521,23 +651,23 @@ class CommentStoreTest extends MediaWikiLangTestCase {
                MediaWiki\suppressWarnings();
                $reset = new ScopedCallback( 'MediaWiki\restoreWarnings' );
 
-               $store = $this->makeStore( MIGRATION_OLD, 'dummy' );
-               $res = $store->getComment( [ 'dummy' => 'comment' ] );
+               $store = $this->makeStore( MIGRATION_OLD );
+               $res = $store->getComment( 'dummy', [ 'dummy' => 'comment' ] );
                $this->assertSame( '', $res->text );
-               $res = $store->getComment( [ 'dummy' => 'comment' ], true );
+               $res = $store->getComment( 'dummy', [ 'dummy' => 'comment' ], true );
                $this->assertSame( 'comment', $res->text );
 
-               $store = $this->makeStore( MIGRATION_NEW, 'dummy' );
+               $store = $this->makeStore( MIGRATION_NEW );
                try {
-                       $store->getComment( [ 'dummy' => 'comment' ] );
+                       $store->getComment( 'dummy', [ 'dummy' => 'comment' ] );
                        $this->fail( 'Expected exception not thrown' );
                } catch ( InvalidArgumentException $ex ) {
                        $this->assertSame( '$row does not contain fields needed for comment dummy', $ex->getMessage() );
                }
-               $res = $store->getComment( [ 'dummy' => 'comment' ], true );
+               $res = $store->getComment( 'dummy', [ 'dummy' => 'comment' ], true );
                $this->assertSame( 'comment', $res->text );
                try {
-                       $store->getComment( [ 'dummy_id' => 1 ] );
+                       $store->getComment( 'dummy', [ 'dummy_id' => 1 ] );
                        $this->fail( 'Expected exception not thrown' );
                } catch ( InvalidArgumentException $ex ) {
                        $this->assertSame(
@@ -547,19 +677,19 @@ class CommentStoreTest extends MediaWikiLangTestCase {
                        );
                }
 
-               $store = $this->makeStore( MIGRATION_NEW, 'rev_comment' );
+               $store = $this->makeStore( MIGRATION_NEW );
                try {
-                       $store->getComment( [ 'rev_comment' => 'comment' ] );
+                       $store->getComment( 'rev_comment', [ 'rev_comment' => 'comment' ] );
                        $this->fail( 'Expected exception not thrown' );
                } catch ( InvalidArgumentException $ex ) {
                        $this->assertSame(
                                '$row does not contain fields needed for comment rev_comment', $ex->getMessage()
                        );
                }
-               $res = $store->getComment( [ 'rev_comment' => 'comment' ], true );
+               $res = $store->getComment( 'rev_comment', [ 'rev_comment' => 'comment' ], true );
                $this->assertSame( 'comment', $res->text );
                try {
-                       $store->getComment( [ 'rev_comment_pk' => 1 ] );
+                       $store->getComment( 'rev_comment', [ 'rev_comment_pk' => 1 ] );
                        $this->fail( 'Expected exception not thrown' );
                } catch ( InvalidArgumentException $ex ) {
                        $this->assertSame(
@@ -586,8 +716,8 @@ class CommentStoreTest extends MediaWikiLangTestCase {
         * @expectedExceptionMessage Must use insertWithTempTable() for rev_comment
         */
        public function testInsertWrong( $stage ) {
-               $store = $this->makeStore( $stage, 'rev_comment' );
-               $store->insert( $this->db, 'foo' );
+               $store = $this->makeStore( $stage );
+               $store->insert( $this->db, 'rev_comment', 'foo' );
        }
 
        /**
@@ -597,8 +727,8 @@ class CommentStoreTest extends MediaWikiLangTestCase {
         * @expectedExceptionMessage Must use insert() for ipb_reason
         */
        public function testInsertWithTempTableWrong( $stage ) {
-               $store = $this->makeStore( $stage, 'ipb_reason' );
-               $store->insertWithTempTable( $this->db, 'foo' );
+               $store = $this->makeStore( $stage );
+               $store->insertWithTempTable( $this->db, 'ipb_reason', 'foo' );
        }
 
        /**
@@ -610,8 +740,8 @@ class CommentStoreTest extends MediaWikiLangTestCase {
                $wrap->formerTempTables += [ 'ipb_reason' => '1.30' ];
 
                $this->hideDeprecated( 'CommentStore::insertWithTempTable for ipb_reason' );
-               $store = $this->makeStore( $stage, 'ipb_reason' );
-               list( $fields, $callback ) = $store->insertWithTempTable( $this->db, 'foo' );
+               $store = $this->makeStore( $stage );
+               list( $fields, $callback ) = $store->insertWithTempTable( $this->db, 'ipb_reason', 'foo' );
                $this->assertTrue( is_callable( $callback ) );
        }
 
@@ -620,8 +750,8 @@ class CommentStoreTest extends MediaWikiLangTestCase {
                $truncated1 = str_repeat( '💣', 63 ) . '...';
                $truncated2 = str_repeat( '💣', CommentStore::COMMENT_CHARACTER_LIMIT - 3 ) . '...';
 
-               $store = $this->makeStore( MIGRATION_WRITE_BOTH, 'ipb_reason' );
-               $fields = $store->insert( $this->db, $comment );
+               $store = $this->makeStore( MIGRATION_WRITE_BOTH );
+               $fields = $store->insert( $this->db, 'ipb_reason', $comment );
                $this->assertSame( $truncated1, $fields['ipb_reason'] );
                $stored = $this->db->selectField(
                        'comment', 'comment_text', [ 'comment_id' => $fields['ipb_reason_id'] ], __METHOD__
@@ -634,13 +764,17 @@ class CommentStoreTest extends MediaWikiLangTestCase {
         * @expectedExceptionMessage Comment data is too long (65611 bytes, maximum is 65535)
         */
        public function testInsertTooMuchData() {
-               $store = $this->makeStore( MIGRATION_WRITE_BOTH, 'ipb_reason' );
-               $store->insert( $this->db, 'foo', [
+               $store = $this->makeStore( MIGRATION_WRITE_BOTH );
+               $store->insert( $this->db, 'ipb_reason', 'foo', [
                        'long' => str_repeat( '💣', 16400 )
                ] );
        }
 
-       public function testConstructor() {
+       public function testGetStore() {
+               $this->assertInstanceOf( CommentStore::class, CommentStore::getStore() );
+       }
+
+       public function testNewKey() {
                $this->assertInstanceOf( CommentStore::class, CommentStore::newKey( 'dummy' ) );
        }
 
index 859a40f..2e93f36 100644 (file)
@@ -344,6 +344,7 @@ class MediaWikiServicesTest extends MediaWikiTestCase {
                        'RevisionStore' => [ 'RevisionStore', RevisionStore::class ],
                        'RevisionLookup' => [ 'RevisionLookup', RevisionLookup::class ],
                        'HttpRequestFactory' => [ 'HttpRequestFactory', HttpRequestFactory::class ],
+                       'CommentStore' => [ 'CommentStore', CommentStore::class ],
                ];
        }
 
index 15b26c2..6fbe053 100644 (file)
@@ -114,6 +114,9 @@ class PageArchiveTest extends MediaWikiTestCase {
         * @covers PageArchive::listRevisions
         */
        public function testListRevisions() {
+               $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
+               $this->overrideMwServices();
+
                $revisions = $this->archivedPage->listRevisions();
                $this->assertEquals( 2, $revisions->numRows() );
 
index 73d69a5..4518e15 100644 (file)
@@ -934,6 +934,7 @@ class RevisionTest extends MediaWikiTestCase {
                $this->hideDeprecated( 'Revision::selectFields' );
                $this->setMwGlobals( 'wgContentHandlerUseDB', $contentHandlerUseDB );
                $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
+               $this->overrideMwServices();
                $this->assertEquals( $expected, Revision::selectFields() );
        }
 
@@ -993,6 +994,7 @@ class RevisionTest extends MediaWikiTestCase {
                $this->hideDeprecated( 'Revision::selectArchiveFields' );
                $this->setMwGlobals( 'wgContentHandlerUseDB', $contentHandlerUseDB );
                $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
+               $this->overrideMwServices();
                $this->assertEquals( $expected, Revision::selectArchiveFields() );
        }
 
index c9e9978..b6aed7f 100644 (file)
@@ -224,9 +224,10 @@ class RevisionStoreTest extends MediaWikiTestCase {
         * @covers \MediaWiki\Storage\RevisionStore::getQueryInfo
         */
        public function testGetQueryInfo( $contentHandlerUseDb, $options, $expected ) {
+               $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
+               $this->overrideMwServices();
                $store = $this->getRevisionStore();
                $store->setContentHandlerUseDB( $contentHandlerUseDb );
-               $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
                $this->assertEquals( $expected, $store->getQueryInfo( $options ) );
        }
 
@@ -254,9 +255,10 @@ class RevisionStoreTest extends MediaWikiTestCase {
         * @covers \MediaWiki\Storage\RevisionStore::getArchiveQueryInfo
         */
        public function testGetArchiveQueryInfo_contentHandlerDb() {
+               $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
+               $this->overrideMwServices();
                $store = $this->getRevisionStore();
                $store->setContentHandlerUseDB( true );
-               $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
                $this->assertEquals(
                        [
                                'tables' => [
@@ -282,9 +284,10 @@ class RevisionStoreTest extends MediaWikiTestCase {
         * @covers \MediaWiki\Storage\RevisionStore::getArchiveQueryInfo
         */
        public function testGetArchiveQueryInfo_noContentHandlerDb() {
+               $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
+               $this->overrideMwServices();
                $store = $this->getRevisionStore();
                $store->setContentHandlerUseDB( false );
-               $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
                $this->assertEquals(
                        [
                                'tables' => [
index b7fe47e..6b680e5 100644 (file)
@@ -1084,6 +1084,8 @@ more stuff
         */
        public function testCommentMigrationOnDeletion( $writeStage, $readStage ) {
                $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', $writeStage );
+               $this->overrideMwServices();
+
                $dbr = wfGetDB( DB_REPLICA );
 
                $page = $this->createPage(
@@ -1102,6 +1104,7 @@ more stuff
                }
 
                $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', $readStage );
+               $this->overrideMwServices();
 
                $page->doDeleteArticle( "testing deletion" );
 
index ef2486d..cb0e376 100644 (file)
@@ -1,15 +1,32 @@
 <?php
 
-use Wikimedia\ScopedCallback;
 use Wikimedia\TestingAccessWrapper;
 
 /**
  * @covers WatchedItemQueryService
  */
-class WatchedItemQueryServiceUnitTest extends PHPUnit_Framework_TestCase {
+class WatchedItemQueryServiceUnitTest extends MediaWikiTestCase {
 
        use MediaWikiCoversValidator;
 
+       private function overrideCommentStore() {
+               $mockStore = $this->getMockBuilder( CommentStore::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $mockStore->expects( $this->any() )
+                       ->method( 'getFields' )
+                       ->willReturn( [ 'commentstore' => 'fields' ] );
+               $mockStore->expects( $this->any() )
+                       ->method( 'getJoin' )
+                       ->willReturn( [
+                               'tables' => [ 'commentstore' => 'table' ],
+                               'fields' => [ 'commentstore' => 'field' ],
+                               'joins' => [ 'commentstore' => 'join' ],
+                       ] );
+
+               $this->setService( 'CommentStore', $mockStore );
+       }
+
        /**
         * @return PHPUnit_Framework_MockObject_MockObject|Database
         */
@@ -477,58 +494,11 @@ class WatchedItemQueryServiceUnitTest extends PHPUnit_Framework_TestCase {
                        [
                                [ 'includeFields' => [ WatchedItemQueryService::INCLUDE_COMMENT ] ],
                                null,
-                               [],
-                               [
-                                       'rc_comment_text' => 'rc_comment',
-                                       'rc_comment_data' => 'NULL',
-                                       'rc_comment_cid' => 'NULL',
-                               ],
-                               [],
-                               [],
-                               [],
-                               [ 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD ],
-                       ],
-                       [
-                               [ 'includeFields' => [ WatchedItemQueryService::INCLUDE_COMMENT ] ],
-                               null,
-                               [ 'comment_rc_comment' => 'comment' ],
-                               [
-                                       'rc_comment_text' => 'COALESCE( comment_rc_comment.comment_text, rc_comment )',
-                                       'rc_comment_data' => 'comment_rc_comment.comment_data',
-                                       'rc_comment_cid' => 'comment_rc_comment.comment_id',
-                               ],
+                               [ 'commentstore' => 'table' ],
+                               [ 'commentstore' => 'field' ],
                                [],
                                [],
-                               [ 'comment_rc_comment' => [ 'LEFT JOIN', 'comment_rc_comment.comment_id = rc_comment_id' ] ],
-                               [ 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH ],
-                       ],
-                       [
-                               [ 'includeFields' => [ WatchedItemQueryService::INCLUDE_COMMENT ] ],
-                               null,
-                               [ 'comment_rc_comment' => 'comment' ],
-                               [
-                                       'rc_comment_text' => 'COALESCE( comment_rc_comment.comment_text, rc_comment )',
-                                       'rc_comment_data' => 'comment_rc_comment.comment_data',
-                                       'rc_comment_cid' => 'comment_rc_comment.comment_id',
-                               ],
-                               [],
-                               [],
-                               [ 'comment_rc_comment' => [ 'LEFT JOIN', 'comment_rc_comment.comment_id = rc_comment_id' ] ],
-                               [ 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_NEW ],
-                       ],
-                       [
-                               [ 'includeFields' => [ WatchedItemQueryService::INCLUDE_COMMENT ] ],
-                               null,
-                               [ 'comment_rc_comment' => 'comment' ],
-                               [
-                                       'rc_comment_text' => 'comment_rc_comment.comment_text',
-                                       'rc_comment_data' => 'comment_rc_comment.comment_data',
-                                       'rc_comment_cid' => 'comment_rc_comment.comment_id',
-                               ],
-                               [],
-                               [],
-                               [ 'comment_rc_comment' => [ 'JOIN', 'comment_rc_comment.comment_id = rc_comment_id' ] ],
-                               [ 'wgCommentTableSchemaMigrationStage' => MIGRATION_NEW ],
+                               [ 'commentstore' => 'join' ],
                        ],
                        [
                                [ 'includeFields' => [ WatchedItemQueryService::INCLUDE_PATROL_INFO ] ],
@@ -836,22 +806,9 @@ class WatchedItemQueryServiceUnitTest extends PHPUnit_Framework_TestCase {
                array $expectedExtraFields,
                array $expectedExtraConds,
                array $expectedDbOptions,
-               array $expectedExtraJoinConds,
-               array $globals = []
+               array $expectedExtraJoinConds
        ) {
-               // Sigh. This test class doesn't extend MediaWikiTestCase, so we have to reinvent setMwGlobals().
-               if ( $globals ) {
-                       $resetGlobals = [];
-                       foreach ( $globals as $k => $v ) {
-                               $resetGlobals[$k] = $GLOBALS[$k];
-                               $GLOBALS[$k] = $v;
-                       }
-                       $reset = new ScopedCallback( function () use ( $resetGlobals ) {
-                               foreach ( $resetGlobals as $k => $v ) {
-                                       $GLOBALS[$k] = $v;
-                               }
-                       } );
-               }
+               $this->overrideCommentStore();
 
                $expectedTables = array_merge( [ 'recentchanges', 'watchlist', 'page' ], $expectedExtraTables );
                $expectedFields = array_merge(