use MediaWiki\Storage\BlobStore;
use MediaWiki\Storage\BlobStoreFactory;
use MediaWiki\Storage\NameTableStore;
+use MediaWiki\Storage\NameTableStoreFactory;
use MediaWiki\Storage\RevisionFactory;
use MediaWiki\Storage\RevisionLookup;
use MediaWiki\Storage\RevisionStore;
* @return NameTableStore
*/
public function getChangeTagDefStore() {
- return $this->getService( 'ChangeTagDefStore' );
+ return $this->getService( 'NameTableStoreFactory' )->getChangeTagDef();
}
/**
* @return NameTableStore
*/
public function getContentModelStore() {
- return $this->getService( 'ContentModelStore' );
+ return $this->getService( 'NameTableStoreFactory' )->getContentModels();
}
/**
/**
* @since 1.32
+ * @return NameTableStoreFactory
+ */
+ public function getNameTableStoreFactory() {
+ return $this->getService( 'NameTableStoreFactory' );
+ }
+
+ /**
* @return OldRevisionImporter
*/
public function getOldRevisionImporter() {
* @return NameTableStore
*/
public function getSlotRoleStore() {
- return $this->getService( 'SlotRoleStore' );
+ return $this->getService( 'NameTableStoreFactory' )->getSlotRoles();
}
/**
use MediaWiki\Storage\BlobStore;
use MediaWiki\Revision\RevisionRenderer;
use MediaWiki\Storage\BlobStoreFactory;
-use MediaWiki\Storage\NameTableStore;
+use MediaWiki\Storage\NameTableStoreFactory;
use MediaWiki\Storage\RevisionFactory;
use MediaWiki\Storage\RevisionLookup;
use MediaWiki\Storage\RevisionStore;
);
},
- 'ChangeTagDefStore' => function ( MediaWikiServices $services ) : NameTableStore {
- return new NameTableStore(
- $services->getDBLoadBalancer(),
- $services->getMainWANObjectCache(),
- LoggerFactory::getInstance( 'NameTableSqlStore' ),
- 'change_tag_def',
- 'ctd_id',
- 'ctd_name',
- null,
- false,
- function ( $insertFields ) {
- $insertFields['ctd_user_defined'] = 0;
- $insertFields['ctd_count'] = 0;
- return $insertFields;
- }
- );
- },
-
'CommentStore' => function ( MediaWikiServices $services ) : CommentStore {
return new CommentStore(
$services->getContentLanguage(),
return Language::factory( $services->getMainConfig()->get( 'LanguageCode' ) );
},
- 'ContentModelStore' => function ( MediaWikiServices $services ) : NameTableStore {
- return new NameTableStore(
- $services->getDBLoadBalancer(),
- $services->getMainWANObjectCache(),
- LoggerFactory::getInstance( 'NameTableSqlStore' ),
- 'content_models',
- 'model_id',
- 'model_name'
- /**
- * No strtolower normalization is added to the service as there are examples of
- * extensions that do not stick to this assumption.
- * - extensions/examples/DataPages define( 'CONTENT_MODEL_XML_DATA','XML_DATA' );
- * - extensions/Scribunto define( 'CONTENT_MODEL_SCRIBUNTO', 'Scribunto' );
- */
- );
- },
-
'CryptHKDF' => function ( MediaWikiServices $services ) : CryptHKDF {
$config = $services->getMainConfig();
return new MimeMagic( $params );
},
+ 'NameTableStoreFactory' => function ( MediaWikiServices $services ) : NameTableStoreFactory {
+ return new NameTableStoreFactory(
+ $services->getDBLoadBalancerFactory(),
+ $services->getMainWANObjectCache(),
+ LoggerFactory::getInstance( 'NameTableSqlStore' )
+ );
+ },
+
'OldRevisionImporter' => function ( MediaWikiServices $services ) : OldRevisionImporter {
return new ImportableOldRevisionImporter(
true,
$store = new RevisionStoreFactory(
$services->getDBLoadBalancerFactory(),
$services->getBlobStoreFactory(),
+ $services->getNameTableStoreFactory(),
$services->getMainWANObjectCache(),
$services->getCommentStore(),
$services->getActorMigration(),
return $factory;
},
- 'SlotRoleStore' => function ( MediaWikiServices $services ) : NameTableStore {
- return new NameTableStore(
- $services->getDBLoadBalancer(),
- $services->getMainWANObjectCache(),
- LoggerFactory::getInstance( 'NameTableSqlStore' ),
- 'slot_roles',
- 'role_id',
- 'role_name',
- 'strtolower'
- );
- },
-
'SpecialPageFactory' => function ( MediaWikiServices $services ) : SpecialPageFactory {
return new SpecialPageFactory(
$services->getMainConfig(),
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ * @file
+ */
+
+namespace MediaWiki\Storage;
+
+use Wikimedia\Rdbms\ILBFactory;
+use WANObjectCache;
+use Psr\Log\LoggerInterface;
+
+class NameTableStoreFactory {
+ private static $info;
+ private $stores = [];
+
+ /** @var ILBFactory */
+ private $lbFactory;
+
+ /** @var WANObjectCache */
+ private $cache;
+
+ /** @var LoggerInterface */
+ private $logger;
+
+ private static function getTableInfo() {
+ if ( self::$info ) {
+ return self::$info;
+ }
+ self::$info = [
+ 'change_tag_def' => [
+ 'idField' => 'ctd_id',
+ 'nameField' => 'ctd_name',
+ 'normalizationCallback' => null,
+ 'insertCallback' => function ( $insertFields ) {
+ $insertFields['ctd_user_defined'] = 0;
+ $insertFields['ctd_count'] = 0;
+ return $insertFields;
+ }
+ ],
+
+ 'content_models' => [
+ 'idField' => 'model_id',
+ 'nameField' => 'model_name',
+ /**
+ * No strtolower normalization is added to the service as there are examples of
+ * extensions that do not stick to this assumption.
+ * - extensions/examples/DataPages define( 'CONTENT_MODEL_XML_DATA','XML_DATA' );
+ * - extensions/Scribunto define( 'CONTENT_MODEL_SCRIBUNTO', 'Scribunto' );
+ */
+ ],
+
+ 'slot_roles' => [
+ 'idField' => 'role_id',
+ 'nameField' => 'role_name',
+ 'normalizationCallback' => 'strtolower',
+ ],
+ ];
+ return self::$info;
+ }
+
+ public function __construct(
+ ILBFactory $lbFactory,
+ WANObjectCache $cache,
+ LoggerInterface $logger
+ ) {
+ $this->lbFactory = $lbFactory;
+ $this->cache = $cache;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Get a NameTableStore for a specific table
+ *
+ * @param string $tableName The table name
+ * @param string|false $wiki The target wiki ID, or false for the current wiki
+ * @return NameTableStore
+ */
+ public function get( $tableName, $wiki = false ) : NameTableStore {
+ $infos = self::getTableInfo();
+ if ( !isset( $infos[$tableName] ) ) {
+ throw new \InvalidArgumentException( "Invalid table name \$tableName" );
+ }
+ if ( $wiki === wfWikiID() ) {
+ $wiki = false;
+ }
+ if ( isset( $this->stores[$tableName][$wiki] ) ) {
+ return $this->stores[$tableName][$wiki];
+ }
+
+ $info = $infos[$tableName];
+ $store = new NameTableStore(
+ $this->lbFactory->getMainLB( $wiki ),
+ $this->cache,
+ $this->logger,
+ $tableName,
+ $info['idField'],
+ $info['nameField'],
+ $info['normalizationCallback'] ?? null,
+ $wiki,
+ $info['insertCallback'] ?? null
+ );
+ $this->stores[$tableName][$wiki] = $store;
+ return $store;
+ }
+
+ /**
+ * Get a NameTableStore for the change_tag_def table
+ *
+ * @param string|bool $wiki
+ * @return NameTableStore
+ */
+ public function getChangeTagDef( $wiki = false ) : NameTableStore {
+ return $this->get( 'change_tag_def', $wiki );
+ }
+
+ /**
+ * Get a NameTableStore for the content_models table
+ *
+ * @param string|bool $wiki
+ * @return NameTableStore
+ */
+ public function getContentModels( $wiki = false ) : NameTableStore {
+ return $this->get( 'content_models', $wiki );
+ }
+
+ /**
+ * Get a NameTableStore for the slot_roles table
+ *
+ * @param string|bool $wiki
+ * @return NameTableStore
+ */
+ public function getSlotRoles( $wiki = false ) : NameTableStore {
+ return $this->get( 'slot_roles', $wiki );
+ }
+}
*/
private $contentHandlerUseDB;
+ /** @var NameTableStoreFactory */
+ private $nameTables;
+
/**
* @param ILBFactory $dbLoadBalancerFactory
* @param BlobStoreFactory $blobStoreFactory
+ * @param NameTableStoreFactory $nameTables
* @param WANObjectCache $cache
* @param CommentStore $commentStore
* @param ActorMigration $actorMigration
public function __construct(
ILBFactory $dbLoadBalancerFactory,
BlobStoreFactory $blobStoreFactory,
+ NameTableStoreFactory $nameTables,
WANObjectCache $cache,
CommentStore $commentStore,
ActorMigration $actorMigration,
Assert::parameterType( 'integer', $migrationStage, '$migrationStage' );
$this->dbLoadBalancerFactory = $dbLoadBalancerFactory;
$this->blobStoreFactory = $blobStoreFactory;
+ $this->nameTables = $nameTables;
$this->cache = $cache;
$this->commentStore = $commentStore;
$this->actorMigration = $actorMigration;
$this->loggerProvider = $loggerProvider;
$this->contentHandlerUseDB = $contentHandlerUseDB;
}
- /**
/**
* @since 1.32
$this->blobStoreFactory->newSqlBlobStore( $wikiId ),
$this->cache, // Pass local cache instance; Leave cache sharing to RevisionStore.
$this->commentStore,
- $this->getContentModelStore( $wikiId ),
- $this->getSlotRoleStore( $wikiId ),
+ $this->nameTables->getContentModels( $wikiId ),
+ $this->nameTables->getSlotRoles( $wikiId ),
$this->mcrMigrationStage,
$this->actorMigration,
$wikiId
return $store;
}
-
- /**
- * @param string $wikiId
- * @return NameTableStore
- */
- private function getContentModelStore( $wikiId ) {
- // XXX: a dedicated ContentModelStore subclass would avoid hard-coding
- // knowledge about the schema here.
- return new NameTableStore(
- $this->dbLoadBalancerFactory->getMainLB( $wikiId ),
- $this->cache, // Pass local cache instance; Leave cache sharing to NameTableStore.
- $this->loggerProvider->getLogger( 'NameTableSqlStore' ),
- 'content_models',
- 'model_id',
- 'model_name',
- null,
- $wikiId
- );
- }
-
- /**
- * @param string $wikiId
- * @return NameTableStore
- */
- private function getSlotRoleStore( $wikiId ) {
- // XXX: a dedicated ContentModelStore subclass would avoid hard-coding
- // knowledge about the schema here.
- return new NameTableStore(
- $this->dbLoadBalancerFactory->getMainLB( $wikiId ),
- $this->cache, // Pass local cache instance; Leave cache sharing to NameTableStore.
- $this->loggerProvider->getLogger( 'NameTableSqlStore' ),
- 'slot_roles',
- 'role_id',
- 'role_name',
- 'strtolower',
- $wikiId
- );
- }
-
}
*/
private function resetDB( $db, $tablesUsed ) {
if ( $db ) {
- // NOTE: Do not reset the slot_roles and content_models tables, but let them
- // leak across tests. Resetting them would require to reset all NamedTableStore
- // instances for these tables, of which there may be several beyond the ones
- // known to MediaWikiServices. See T202641.
$userTables = [ 'user', 'user_groups', 'user_properties', 'actor' ];
$pageTables = [
'page', 'revision', 'ip_changes', 'revision_comment_temp', 'comment', 'archive',
- 'revision_actor_temp', 'slots', 'content',
+ 'revision_actor_temp', 'slots', 'content', 'content_models', 'slot_roles',
];
$coreDBDataTables = array_merge( $userTables, $pageTables );
}
if ( array_intersect( $tablesUsed, $coreDBDataTables ) ) {
+ // Reset services that may contain information relating to the truncated tables
+ $this->overrideMwServices();
// Re-add core DB data that was deleted
$this->addCoreDBData();
}
$db->delete( $tableName, '*', __METHOD__ );
}
- if ( in_array( $db->getType(), [ 'postgres', 'sqlite' ], true ) ) {
+ if ( $db instanceof DatabasePostgres || $db instanceof DatabaseSqlite ) {
// Reset the table's sequence too.
$db->resetSequenceForTable( $tableName, __METHOD__ );
}
+
+ // re-initialize site_stats table
+ if ( $tableName === 'site_stats' ) {
+ SiteStatsInit::doPlaceholderInit();
+ }
}
private static function unprefixTable( &$tableName, $ind, $prefix ) {
--- /dev/null
+<?php
+
+namespace MediaWiki\Tests\Storage;
+
+use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\NameTableStore;
+use MediaWiki\Storage\NameTableStoreFactory;
+use MediaWikiTestCase;
+use Wikimedia\Rdbms\ILBFactory;
+use Wikimedia\Rdbms\ILoadBalancer;
+
+/**
+ * @covers MediaWiki\Storage\NameTableStoreFactory
+ * @group Database
+ */
+class NameTableStoreFactoryTest extends MediaWikiTestCase {
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|ILoadBalancer
+ */
+ private function getMockLoadBalancer() {
+ return $this->getMockBuilder( ILoadBalancer::class )
+ ->disableOriginalConstructor()->getMock();
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|ILBFactory
+ */
+ private function getMockLoadBalancerFactory( $expectedWiki ) {
+ $mock = $this->getMockBuilder( ILBFactory::class )
+ ->disableOriginalConstructor()->getMock();
+
+ $mock->expects( $this->once() )
+ ->method( 'getMainLB' )
+ ->with( $this->equalTo( $expectedWiki ) )
+ ->willReturnCallback( function ( $domain ) use ( $expectedWiki ) {
+ return $this->getMockLoadBalancer();
+ } );
+
+ return $mock;
+ }
+
+ public static function provideTestGet() {
+ return [
+ [
+ 'change_tag_def',
+ false,
+ false,
+ ],
+ [
+ 'content_models',
+ false,
+ false,
+ ],
+ [
+ 'slot_roles',
+ false,
+ false,
+ ],
+ [
+ 'change_tag_def',
+ 'test7245',
+ 'test7245',
+ ],
+ ];
+ }
+
+ /** @dataProvider provideTestGet */
+ public function testGet( $tableName, $wiki, $expectedWiki ) {
+ $services = MediaWikiServices::getInstance();
+ $db = wfGetDB( DB_MASTER );
+ if ( $wiki === false ) {
+ $wiki2 = $db->getWikiID();
+ } else {
+ $wiki2 = $wiki;
+ }
+ $names = new NameTableStoreFactory(
+ $this->getMockLoadBalancerFactory( $expectedWiki ),
+ $services->getMainWANObjectCache(),
+ LoggerFactory::getInstance( 'NameTableStoreFactory' )
+ );
+
+ $table = $names->get( $tableName, $wiki );
+ $table2 = $names->get( $tableName, $wiki2 );
+ $this->assertSame( $table, $table2 );
+ $this->assertInstanceOf( NameTableStore::class, $table );
+ }
+
+ /*
+ * The next three integration tests verify that the schema information is correct by loading
+ * the relevant information from the database.
+ */
+
+ public function testIntegratedGetChangeTagDef() {
+ $services = MediaWikiServices::getInstance();
+ $factory = $services->getNameTableStoreFactory();
+ $store = $factory->getChangeTagDef();
+ $this->assertType( 'array', $store->getMap() );
+ }
+
+ public function testIntegratedGetContentModels() {
+ $services = MediaWikiServices::getInstance();
+ $factory = $services->getNameTableStoreFactory();
+ $store = $factory->getContentModels();
+ $this->assertType( 'array', $store->getMap() );
+ }
+
+ public function testIntegratedGetSlotRoles() {
+ $services = MediaWikiServices::getInstance();
+ $factory = $services->getNameTableStoreFactory();
+ $store = $factory->getSlotRoles();
+ $this->assertType( 'array', $store->getMap() );
+ }
+}
use MediaWiki\Storage\BlobStore;
use MediaWiki\Storage\BlobStoreFactory;
use MediaWiki\Storage\NameTableStore;
+use MediaWiki\Storage\NameTableStoreFactory;
use MediaWiki\Storage\RevisionStore;
use MediaWiki\Storage\RevisionStoreFactory;
use MediaWiki\Storage\SqlBlobStore;
new RevisionStoreFactory(
$this->getMockLoadBalancerFactory(),
$this->getMockBlobStoreFactory(),
+ $this->getNameTableStoreFactory(),
$this->getHashWANObjectCache(),
$this->getMockCommentStore(),
ActorMigration::newMigration(),
) {
$lbFactory = $this->getMockLoadBalancerFactory();
$blobStoreFactory = $this->getMockBlobStoreFactory();
+ $nameTableStoreFactory = $this->getNameTableStoreFactory();
$cache = $this->getHashWANObjectCache();
$commentStore = $this->getMockCommentStore();
$actorMigration = ActorMigration::newMigration();
$factory = new RevisionStoreFactory(
$lbFactory,
$blobStoreFactory,
+ $nameTableStoreFactory,
$cache,
$commentStore,
$actorMigration,
return $mock;
}
+ /**
+ * @return NameTableStoreFactory
+ */
+ private function getNameTableStoreFactory() {
+ return new NameTableStoreFactory(
+ $this->getMockLoadBalancerFactory(),
+ $this->getHashWANObjectCache(),
+ new NullLogger() );
+ }
+
/**
* @return \PHPUnit_Framework_MockObject_MockObject|CommentStore
*/
$this->setExpectedException( MWException::class );
}
+ $nameTables = MediaWikiServices::getInstance()->getNameTableStoreFactory();
+
$store = new RevisionStore(
$this->getMockLoadBalancer(),
$this->getMockSqlBlobStore(),
$this->getHashWANObjectCache(),
$this->getMockCommentStore(),
- MediaWikiServices::getInstance()->getContentModelStore(),
- MediaWikiServices::getInstance()->getSlotRoleStore(),
+ $nameTables->getContentModels(),
+ $nameTables->getSlotRoles(),
$migrationMode,
MediaWikiServices::getInstance()->getActorMigration()
);
$blobStore = $this->getMockSqlBlobStore();
$cache = $this->getHashWANObjectCache();
$commentStore = $this->getMockCommentStore();
- $contentModelStore = MediaWikiServices::getInstance()->getContentModelStore();
- $slotRoleStore = MediaWikiServices::getInstance()->getSlotRoleStore();
+ $services = MediaWikiServices::getInstance();
+ $nameTables = $services->getNameTableStoreFactory();
+ $contentModelStore = $nameTables->getContentModels();
+ $slotRoleStore = $nameTables->getSlotRoles();
$store = new RevisionStore(
$loadBalancer,
$blobStore,
$cache,
$commentStore,
- MediaWikiServices::getInstance()->getContentModelStore(),
- MediaWikiServices::getInstance()->getSlotRoleStore(),
+ $nameTables->getContentModels(),
+ $nameTables->getSlotRoles(),
$migration,
- MediaWikiServices::getInstance()->getActorMigration()
+ $services->getActorMigration()
);
if ( !$expectException ) {
$store = TestingAccessWrapper::newFromObject( $store );
$dbw = wfGetDB( DB_MASTER );
$dbw->delete( 'change_tag', '*' );
$dbw->delete( 'change_tag_def', '*' );
- MediaWikiServices::getInstance()->resetServiceForTesting( 'ChangeTagDefStore' );
+ MediaWikiServices::getInstance()->resetServiceForTesting( 'NameTableStoreFactory' );
$rcId = 123;
ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
$dbw = wfGetDB( DB_MASTER );
$dbw->delete( 'change_tag', '*' );
$dbw->delete( 'change_tag_def', '*' );
- MediaWikiServices::getInstance()->resetServiceForTesting( 'ChangeTagDefStore' );
+ MediaWikiServices::getInstance()->resetServiceForTesting( 'NameTableStoreFactory' );
$rcId = 123;
ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
$dbw = wfGetDB( DB_MASTER );
$dbw->delete( 'change_tag', '*' );
$dbw->delete( 'change_tag_def', '*' );
- MediaWikiServices::getInstance()->resetServiceForTesting( 'ChangeTagDefStore' );
+ MediaWikiServices::getInstance()->resetServiceForTesting( 'NameTableStoreFactory' );
$rcId = 123;
ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );