jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/400415 )
Change subject: Integrate all Client's repository settings into a single setting ...................................................................... Integrate all Client's repository settings into a single setting This renames "foreignRepositories" setting to "repositories", and moves the configuration of the "local" repository, to the "repositories" setting. Bug: T153767 Change-Id: I2eee36256260490d7b3ddf6c83389f810239835c --- M client/config/WikibaseClient.default.php M client/config/WikibaseClient.example.php M client/includes/Hooks/UpdateRepoHookHandlers.php M client/includes/WikibaseClient.php M client/maintenance/updateSubscriptions.php M client/tests/phpunit/ClientDefaultsTest.php M client/tests/phpunit/includes/DataAccess/DataAccessSnakFormatterOutputFormatTest.php M client/tests/phpunit/includes/Usage/UsageTrackingIntegrationTest.php A client/tests/phpunit/includes/WikibaseClientRepositorySettingsTest.php M docs/federation.wiki M docs/options.wiki M lib/includes/WikibaseSettings.php 12 files changed, 392 insertions(+), 105 deletions(-) Approvals: WMDE-leszek: Looks good to me, approved jenkins-bot: Verified diff --git a/client/config/WikibaseClient.default.php b/client/config/WikibaseClient.default.php index 312edac..7380d59 100644 --- a/client/config/WikibaseClient.default.php +++ b/client/config/WikibaseClient.default.php @@ -90,8 +90,6 @@ // repo and clients for multiwiki setups. 'sharedCacheType' => $GLOBALS['wgMainCacheType'], - 'foreignRepositories' => [], - // Enable writing of term_full_entity_id column in wb_terms table. 'writeFullEntityIdColumn' => function ( SettingsArray $settings ) { return $settings->hasSetting( 'hasFullEntityIdColumn' ) ? @@ -132,6 +130,30 @@ return WikibaseSettings::isRepoEnabled(); }; + $defaults['repositories'] = function ( SettingsArray $settings ) { + // XXX: Default to having Items in the main namespace, and properties in NS 120. + // That is the live setup at wikidata.org, it is NOT consistent with the example settings! + // FIXME: throw an exception, instead of making assumptions that may brak the site in strange ways! + $entityNamespaces = [ + 'item' => 0, + 'property' => 120 + ]; + if ( $settings->getSetting( 'thisWikiIsTheRepo' ) ) { + $entityNamespaces = WikibaseSettings::getRepoSettings()->getSetting( 'entityNamespaces' ); + } + + return [ + '' => [ + // Use false (meaning the local wiki's database) if this wiki is the repo, + // otherwise default to null (meaning we can't access the repo's DB directly). + 'repoDatabase' => $settings->getSetting( 'thisWikiIsTheRepo' ) ? false : null, + 'baseUri' => $settings->getSetting( 'repoUrl' ) . '/entity/', + 'entityNamespaces' => $entityNamespaces, + 'prefixMapping' => [ '' => '' ], + ] + ]; + }; + $defaults['repoSiteName'] = function ( SettingsArray $settings ) { // This uses $wgSitename if this wiki is the repo. Otherwise, set this to // either an i18n message key and the message will be used, if it exists. @@ -144,10 +166,6 @@ return $settings->getSetting( 'thisWikiIsTheRepo' ) ? $GLOBALS['wgServer'] : '//www.wikidata.org'; }; - $defaults['repoConceptBaseUri'] = function ( SettingsArray $settings ) { - return $settings->getSetting( 'repoUrl' ) . '/entity/'; - }; - $defaults['repoArticlePath'] = function ( SettingsArray $settings ) { // use $wgArticlePath if this wiki is the repo, otherwise default to /wiki/$1 return $settings->getSetting( 'thisWikiIsTheRepo' ) ? $GLOBALS['wgArticlePath'] : '/wiki/$1'; @@ -158,32 +176,12 @@ return $settings->getSetting( 'thisWikiIsTheRepo' ) ? $GLOBALS['wgScriptPath'] : '/w'; }; - $defaults['repoDatabase'] = function ( SettingsArray $settings ) { - // Use false (meaning the local wiki's database) if this wiki is the repo, - // otherwise default to null (meaning we can't access the repo's DB directly). - return $settings->getSetting( 'thisWikiIsTheRepo' ) ? false : null; - }; - - $defaults['entityNamespaces'] = function ( SettingsArray $settings ) { - if ( $settings->getSetting( 'thisWikiIsTheRepo' ) ) { - return WikibaseSettings::getRepoSettings()->getSetting( 'entityNamespaces' ); - } else { - // XXX: Default to having Items in the main namespace, and properties in NS 120. - // That is the live setup at wikidata.org, it is NOT consistent with the example settings! - // FIXME: throw an exception, instead of making assumptions that may brak the site in strange ways! - return [ - 'item' => 0, - 'property' => 120 - ]; - } - }; - $defaults['repoNamespaces'] = function ( SettingsArray $settings ) { if ( $settings->getSetting( 'thisWikiIsTheRepo' ) ) { // if this is the repo wiki, look up the namespace names based on the entityNamespaces setting $namespaceNames = array_map( [ MWNamespace::class, 'getCanonicalName' ], - $settings->getSetting( 'entityNamespaces' ) + WikibaseSettings::getRepoSettings()->getSetting( 'entityNamespaces' ) ); return $namespaceNames; } else { @@ -198,10 +196,11 @@ }; $defaults['changesDatabase'] = function ( SettingsArray $settings ) { - // Per default, the database for tracking changes is the repo's database. + // Per default, the database for tracking changes is the local repo's database. // Note that the value for the repoDatabase setting may be calculated dynamically, - // see above. - return $settings->getSetting( 'repoDatabase' ); + // see above in 'repositories' setting. + $repositorySettings = $settings->getSetting( 'repositories' ); + return $repositorySettings['']['repoDatabase']; }; $defaults['siteGlobalID'] = function ( SettingsArray $settings ) { @@ -213,9 +212,12 @@ $defaults['repoSiteId'] = function( SettingsArray $settings ) { // If repoDatabase is set, then default is same as repoDatabase // otherwise, defaults to siteGlobalID - return ( $settings->getSetting( 'repoDatabase' ) === false ) + $repositorySettings = $settings->getSetting( 'repositories' ); + $repoDatabase = $repositorySettings['']['repoDatabase']; + + return ( $repoDatabase === false ) ? $settings->getSetting( 'siteGlobalID' ) - : $settings->getSetting( 'repoDatabase' ); + : $repoDatabase; }; $defaults['siteGroup'] = function ( SettingsArray $settings ) { diff --git a/client/config/WikibaseClient.example.php b/client/config/WikibaseClient.example.php index 7a5b509..52a9969 100644 --- a/client/config/WikibaseClient.example.php +++ b/client/config/WikibaseClient.example.php @@ -46,22 +46,22 @@ // default to what you have $wgScriptPath set in the client. $wgWBClientSettings['repoScriptPath'] = "/w"; - // Database name of the repository, for direct access from the client. - // repoDatabase and changesDatabase will generally be the same. - // This requires the given database name to be known to LBFactory, see - // $wgLBFactoryConf below. - $wgWBClientSettings['repoDatabase'] = "repo"; - // Tell the client which namespace ID on the repo holds which type of entity. $baseRepoNs = 120; define( 'WB_REPO_NS_ITEM', $baseRepoNs ); define( 'WB_REPO_NS_PROPERTY', $baseRepoNs + 2 ); - // Tell Wikibase which namespace on the repo to use for which kind of entity - $wgWBClientSettings['entityNamespaces'] = [ - 'item' => WB_REPO_NS_ITEM, - 'property' => WB_REPO_NS_PROPERTY + $wgWBClientSettings['repositories'] = [ + '' => [ + 'repoDatabase' => 'repo', + 'baseUri' => $wgWBClientSettings['repoUrl'] . '/entity', + 'entityNamespaces' => [ + 'item' => WB_REPO_NS_ITEM, + 'property' => WB_REPO_NS_PROPERTY + ], + 'prefixMapping' => [ '' => '' ], + ] ]; } diff --git a/client/includes/Hooks/UpdateRepoHookHandlers.php b/client/includes/Hooks/UpdateRepoHookHandlers.php index aaf87ee..591ff21 100644 --- a/client/includes/Hooks/UpdateRepoHookHandlers.php +++ b/client/includes/Hooks/UpdateRepoHookHandlers.php @@ -64,7 +64,7 @@ $namespaceChecker = $wikibaseClient->getNamespaceChecker(); - $repoDB = $settings->getSetting( 'repoDatabase' ); + $repoDB = $wikibaseClient->getRepositoryDefinitions()->getDatabaseNames()['']; $jobQueueGroup = JobQueueGroup::singleton( $repoDB ); if ( !$jobQueueGroup ) { @@ -78,7 +78,7 @@ $namespaceChecker, $jobQueueGroup, $siteLinkLookup, - $settings->getSetting( 'repoDatabase' ), + $repoDB, $settings->getSetting( 'siteGlobalID' ), $settings->getSetting( 'propagateChangesToRepo' ) ); diff --git a/client/includes/WikibaseClient.php b/client/includes/WikibaseClient.php index c433758..e0a7fda 100644 --- a/client/includes/WikibaseClient.php +++ b/client/includes/WikibaseClient.php @@ -531,17 +531,13 @@ */ public function getStore() { if ( $this->store === null ) { - // NOTE: $repoDatabase is null per default, meaning no direct access to the repo's - // database. If $repoDatabase is false, the local wiki IS the repository. Otherwise, - // $repoDatabase needs to be a logical database name that LBFactory understands. - $repoDatabase = $this->settings->getSetting( 'repoDatabase' ); $this->store = new DirectSqlStore( $this->getEntityChangeFactory(), $this->getEntityIdParser(), $this->getEntityIdComposer(), $this->getEntityNamespaceLookup(), $this->getWikibaseServices(), - $repoDatabase, + $this->getRepositoryDefinitions()->getDatabaseNames()[''], $this->getContentLanguage()->getCode() ); } @@ -671,16 +667,30 @@ * @return RepositoryDefinitions */ private static function getRepositoryDefinitionsFromSettings( SettingsArray $settings ) { - // FIXME: It might no longer be needed to check different settings (repoDatabase vs foreignRepositories) - // once repository settings are unified, see: T153767. - $definitions = [ '' => [ - 'database' => $settings->getSetting( 'repoDatabase' ), - 'base-uri' => $settings->getSetting( 'repoConceptBaseUri' ), - 'prefix-mapping' => [ '' => '' ], - 'entity-namespaces' => $settings->getSetting( 'entityNamespaces' ), - ] ]; + $definitions = []; - foreach ( $settings->getSetting( 'foreignRepositories' ) as $repository => $repositorySettings ) { + // Backwards compatibility: if the old "foreignRepositories" settings is there, + // use its values. + $repoSettingsArray = $settings->hasSetting( 'foreignRepositories' ) + ? $settings->getSetting( 'foreignRepositories' ) + : $settings->getSetting( 'repositories' ); + + // Backwards compatibility: if settings of the "local" repository + // are not defined in the "repositories" settings but with individual settings, + // fallback to old single-repo settings + if ( $settings->hasSetting( 'repoDatabase' ) + && $settings->hasSetting( 'entityNamespaces' ) + && $settings->hasSetting( 'repoConceptBaseUri' ) + ) { + $definitions = [ '' => [ + 'database' => $settings->getSetting( 'repoDatabase' ), + 'base-uri' => $settings->getSetting( 'repoConceptBaseUri' ), + 'prefix-mapping' => [ '' => '' ], + 'entity-namespaces' => $settings->getSetting( 'entityNamespaces' ), + ] ]; + } + + foreach ( $repoSettingsArray as $repository => $repositorySettings ) { $definitions[$repository] = [ 'database' => $repositorySettings['repoDatabase'], 'base-uri' => $repositorySettings['baseUri'], @@ -842,8 +852,10 @@ * @return EntityIdParser */ private function getRepoItemUriParser() { + // B/C compatibility, should be removed soon + // TODO: Move to check repo that has item entity not the default repo return new SuffixEntityIdParser( - $this->settings->getSetting( 'repoConceptBaseUri' ), + $this->getRepositoryDefinitions()->getConceptBaseUris()[''], new ItemIdParser() ); } diff --git a/client/maintenance/updateSubscriptions.php b/client/maintenance/updateSubscriptions.php index ac240d1..4dee496 100644 --- a/client/maintenance/updateSubscriptions.php +++ b/client/maintenance/updateSubscriptions.php @@ -58,7 +58,7 @@ $wikibaseClient = WikibaseClient::getDefaultInstance(); $settings = $wikibaseClient->getSettings(); - $repoDB = $settings->getSetting( 'repoDatabase' ); + $repoDB = $wikibaseClient->getRepositoryDefinitions()->getDatabaseNames()['']; $clientId = $settings->getSetting( 'siteGlobalID' ); $idParser = $wikibaseClient->getEntityIdParser(); diff --git a/client/tests/phpunit/ClientDefaultsTest.php b/client/tests/phpunit/ClientDefaultsTest.php index 16612a7..4a01b7c 100644 --- a/client/tests/phpunit/ClientDefaultsTest.php +++ b/client/tests/phpunit/ClientDefaultsTest.php @@ -60,7 +60,16 @@ 'repoArticlePath' => '/wiki/$1', // hardcoded default 'repoScriptPath' => '/w', // hardcoded default 'siteGlobalID' => 'mw_mywiki', - 'repoDatabase' => null, + 'repositories' => [ + '' => [ + 'repoDatabase' => null, + 'baseUri' => '//www.wikidata.org/entity/', + 'entityNamespaces' => [ + 'item' => 0, + 'property' => 120, + ], + ], + ], 'changesDatabase' => null, 'sharedCacheKeyPrefix' => 'wikibase_shared/' . rawurlencode( WBL_VERSION ) . '-mw_mywiki', ] @@ -93,8 +102,10 @@ 'sharedCacheKeyPrefix' => 'foo:WBL/' . rawurlencode( WBL_VERSION ), ] ], + ]; - [ // #3: local repo, no values set + if ( WikibaseSettings::isRepoEnabled() ) { + $cases[] = [ // #3: local repo, no values set [ // $settings ], [ // $wg @@ -102,6 +113,9 @@ 'wgArticlePath' => '/mywiki', 'wgScriptPath' => '/mediawiki', 'wgDBname' => 'mw_mywiki', + 'wgWBRepoSettings' => [ + 'entityNamespaces' => [ 'item' => 303 ], + ], ], true, // $repoIsLocal [ // $expected @@ -109,25 +123,36 @@ 'repoArticlePath' => '/mywiki', 'repoScriptPath' => '/mediawiki', 'siteGlobalID' => 'mw_mywiki', - 'repoDatabase' => false, + 'repositories' => [ + '' => [ + 'repoDatabase' => false, + 'baseUri' => 'http://www.acme.com/entity/', + ], + ], 'changesDatabase' => false, 'sharedCacheKeyPrefix' => 'wikibase_shared/' . rawurlencode( WBL_VERSION ) . '-mw_mywiki', ] - ], + ]; + } - [ // #4: derive changesDatabase - [ // $settings - 'repoDatabase' => 'mw_foowiki', + $cases[] = [ // #4: derive changesDatabase + [ // $settings + 'repositories' => [ + '' => [ + 'repoDatabase' => 'mw_foowiki' + ], ], - [ // $wg - ], - false, // $repoIsLocal - [ // $expected - 'repoDatabase' => 'mw_foowiki', - 'changesDatabase' => 'mw_foowiki', - ] ], - [ // #5: sharedCacheKeyPrefix explicitly set + [ // $wg + ], + false, // $repoIsLocal + [ // $expected + 'changesDatabase' => 'mw_foowiki', + ] + ]; + + if ( WikibaseSettings::isRepoEnabled() ) { + $cases[] = [ // #5: sharedCacheKeyPrefix explicitly set [ // $settings 'sharedCacheKeyPrefix' => 'wikibase_shared/wikidata_1_25wmf24' ], @@ -136,6 +161,7 @@ 'wgArticlePath' => '/mywiki', 'wgScriptPath' => '/mediawiki', 'wgDBname' => 'mw_mywiki', + 'wgWBRepoSettings' => [ 'entityNamespaces' => [ 'item' => 303 ] ], ], true, // $repoIsLocal [ // $expected @@ -143,22 +169,26 @@ 'repoArticlePath' => '/mywiki', 'repoScriptPath' => '/mediawiki', 'siteGlobalID' => 'mw_mywiki', - 'repoDatabase' => false, 'changesDatabase' => false, 'sharedCacheKeyPrefix' => 'wikibase_shared/wikidata_1_25wmf24', ] + ]; + } + + $cases[] = [ // #6: derive repoNamespaces and entityNamespaces + [ // $settings ], - [ // #6: derive repoNamespaces and entityNamespaces - [ // $settings - ], - [ // $wg - ], - false, // $repoIsLocal - [ // $expected - 'repoNamespaces' => [ 'item' => '', 'property' => 'Property' ], - 'entityNamespaces' => [ 'item' => 0, 'property' => 120 ], - ] + [ // $wg ], + false, // $repoIsLocal + [ // $expected + 'repoNamespaces' => [ 'item' => '', 'property' => 'Property' ], + 'repositories' => [ + '' => [ + 'entityNamespaces' => [ 'item' => 0, 'property' => 120 ], + ], + ], + ] ]; if ( WikibaseSettings::isRepoEnabled() ) { @@ -172,7 +202,11 @@ true, // $repoIsLocal [ // $expected 'repoNamespaces' => $namespaceNames, - 'entityNamespaces' => $entityNamespaces, + 'repositories' => [ + '' => [ + 'entityNamespaces' => $entityNamespaces, + ], + ], ] ]; } @@ -198,8 +232,21 @@ foreach ( $expected as $key => $exp ) { $actual = $settings->getSetting( $key ); + + if ( $key === 'repositories' ) { + $this->assertRepositorySettingsEqual( $exp, $actual ); + continue; + } + $this->assertSame( $exp, $actual, "Setting $key" ); } } + private function assertRepositorySettingsEqual( $expected, $actual ) { + foreach ( $expected as $repoName => $expectedRepoSettings ) { + $actualToCompare = array_intersect_key( $actual[$repoName], $expectedRepoSettings ); + $this->assertSame( $expectedRepoSettings, $actualToCompare ); + } + } + } diff --git a/client/tests/phpunit/includes/DataAccess/DataAccessSnakFormatterOutputFormatTest.php b/client/tests/phpunit/includes/DataAccess/DataAccessSnakFormatterOutputFormatTest.php index 47d864f..bee2326 100644 --- a/client/tests/phpunit/includes/DataAccess/DataAccessSnakFormatterOutputFormatTest.php +++ b/client/tests/phpunit/includes/DataAccess/DataAccessSnakFormatterOutputFormatTest.php @@ -125,8 +125,8 @@ * @return array[] */ private function getGenericSnaks() { - $settings = WikibaseClient::getDefaultInstance()->getSettings(); - $repoConceptBaseUri = $settings->getSetting( 'repoConceptBaseUri' ); + $repositories = WikibaseClient::getDefaultInstance()->getRepositoryDefinitions(); + $repoConceptBaseUri = $repositories->getConceptBaseUris()['']; $p4 = new PropertyId( 'P4' ); $sampleUrl = 'https://www.wikidata.org/w/index.php?title=Q2013&action=history'; diff --git a/client/tests/phpunit/includes/Usage/UsageTrackingIntegrationTest.php b/client/tests/phpunit/includes/Usage/UsageTrackingIntegrationTest.php index 6b99c5a..29dcb30 100644 --- a/client/tests/phpunit/includes/Usage/UsageTrackingIntegrationTest.php +++ b/client/tests/phpunit/includes/Usage/UsageTrackingIntegrationTest.php @@ -53,9 +53,10 @@ parent::setUp(); - $settings = WikibaseClient::getDefaultInstance()->getSettings(); + $wikibaseClient = WikibaseClient::getDefaultInstance(); + $settings = $wikibaseClient->getSettings(); $this->oldAllowDataTransclusion = $settings->getSetting( 'allowDataTransclusion' ); - $this->oldEntityNamespaces = $settings->getSetting( 'entityNamespaces' ); + $this->oldEntityNamespaces = $wikibaseClient->getRepositoryDefinitions()->getEntityNamespaces(); $settings->setSetting( 'allowDataTransclusion', true ); $settings->setSetting( 'entityNamespaces', [ 'item' => 0 ] ); diff --git a/client/tests/phpunit/includes/WikibaseClientRepositorySettingsTest.php b/client/tests/phpunit/includes/WikibaseClientRepositorySettingsTest.php new file mode 100644 index 0000000..43443cc --- /dev/null +++ b/client/tests/phpunit/includes/WikibaseClientRepositorySettingsTest.php @@ -0,0 +1,191 @@ +<?php + +namespace Wikibase\Client\Tests; + +use Wikibase\Client\WikibaseClient; + +/** + * @covers Wikibase\Client\WikibaseClient + * + * @group Wikibase + * @group WikibaseClient + * + * @license GPL-2.0+ + */ +class WikibaseClientRepositorySettingsTest extends \MediaWikiTestCase { + + public function testGivenOldRepositorySettings_individualSettingsAreUsedForLocalRepo() { + $clientSettings = $this->getDefaultSettings(); + + $clientSettings['foreignRepositories'] = []; + $clientSettings['repoDatabase'] = 'foodb'; + $clientSettings['entityNamespaces'] = [ 'item' => 303, 'property' => 808 ]; + $clientSettings['repoConceptBaseUri'] = 'http://foo.oof/entity/'; + + $this->setMwGlobals( 'wgWBClientSettings', $clientSettings ); + $this->setMwGlobals( 'wgHooks', [] ); + + $client = WikibaseClient::getDefaultInstance( 'reset' ); + $repositoryDefinitions = $client->getRepositoryDefinitions(); + + $this->assertEquals( + [ '' => 'foodb' ], + $repositoryDefinitions->getDatabaseNames() + ); + $this->assertEquals( + [ 'item' => 303, 'property' => 808 ], + $repositoryDefinitions->getEntityNamespaces() + ); + $this->assertEquals( + [ '' => 'http://foo.oof/entity/' ], + $repositoryDefinitions->getConceptBaseUris() + ); + } + + public function testGivenOldForeignRepositorySettings_oldSettingsAreUsedForForeignRepository() { + $clientSettings = $this->getDefaultSettings(); + + $clientSettings['foreignRepositories'] = [ + 'coolrepo' => [ + 'repoDatabase' => 'cooldb', + 'entityNamespaces' => [ 'cool' => 666 ], + 'baseUri' => 'http://soooo.cooooool/entity/', + 'prefixMapping' => [ '' => '' ], + ] + ]; + $clientSettings['repoDatabase'] = 'foodb'; + $clientSettings['entityNamespaces'] = [ 'item' => 303, 'property' => 808 ]; + $clientSettings['repoConceptBaseUri'] = 'http://foo.oof/entity/'; + + $this->setMwGlobals( 'wgWBClientSettings', $clientSettings ); + $this->setMwGlobals( 'wgHooks', [] ); + + $client = WikibaseClient::getDefaultInstance( 'reset' ); + $repositoryDefinitions = $client->getRepositoryDefinitions(); + + $this->assertEquals( + [ '' => 'foodb', 'coolrepo' => 'cooldb' ], + $repositoryDefinitions->getDatabaseNames() + ); + $this->assertEquals( + [ 'item' => 303, 'property' => 808, 'cool' => 666 ], + $repositoryDefinitions->getEntityNamespaces() + ); + $this->assertEquals( + [ '' => 'http://foo.oof/entity/', 'coolrepo' => 'http://soooo.cooooool/entity/' ], + $repositoryDefinitions->getConceptBaseUris() + ); + } + + public function testGivenOnlyRepositorySettingPresent_theSettingIsUsedToDefineRepositories() { + $clientSettings = $this->getDefaultSettings(); + + $clientSettings['repositories'] = [ + '' => [ + 'repoDatabase' => 'foodb', + 'entityNamespaces' => [ 'item' => 303, 'property' => 808 ], + 'baseUri' => 'http://foo.oof/entity/', + 'prefixMapping' => [ '' => '' ], + ], + 'coolrepo' => [ + 'repoDatabase' => 'cooldb', + 'entityNamespaces' => [ 'cool' => 666 ], + 'baseUri' => 'http://soooo.cooooool/entity/', + 'prefixMapping' => [ '' => '' ], + ] + ]; + unset( $clientSettings['repoDatabase'] ); + unset( $clientSettings['entityNamespaces'] ); + unset( $clientSettings['repoConceptBaseUri'] ); + unset( $clientSettings['foreignRepositories'] ); + + $this->setMwGlobals( 'wgWBClientSettings', $clientSettings ); + $this->setMwGlobals( 'wgHooks', [] ); + + $client = WikibaseClient::getDefaultInstance( 'reset' ); + $repositoryDefinitions = $client->getRepositoryDefinitions(); + + $this->assertEquals( + [ '' => 'foodb', 'coolrepo' => 'cooldb' ], + $repositoryDefinitions->getDatabaseNames() + ); + $this->assertEquals( + [ 'item' => 303, 'property' => 808, 'cool' => 666 ], + $repositoryDefinitions->getEntityNamespaces() + ); + $this->assertEquals( + [ '' => 'http://foo.oof/entity/', 'coolrepo' => 'http://soooo.cooooool/entity/' ], + $repositoryDefinitions->getConceptBaseUris() + ); + } + + public function testGivenCustomEntityTypeAssignedToParticularRepo_entityNamespaceOnlyDefinedForThisRepo() { + $clientSettings = $this->getDefaultSettings(); + + $clientSettings['repositories'] = [ + '' => [ + 'repoDatabase' => 'foodb', + 'entityNamespaces' => [ 'item' => 303, 'property' => 808 ], + 'baseUri' => 'http://foo.oof/entity/', + 'prefixMapping' => [ '' => '' ], + ], + 'coolrepo' => [ + 'repoDatabase' => 'cooldb', + 'entityNamespaces' => [ 'cool' => 666 ], + 'baseUri' => 'http://soooo.cooooool/entity/', + 'prefixMapping' => [ '' => '' ], + ] + ]; + + $this->setMwGlobals( 'wgWBClientSettings', $clientSettings ); + $this->setMwGlobals( 'wgHooks', [ + 'WikibaseEntityNamespaces' => [ + function ( &$namespaces ) { + $namespaces['cool'] = 666; + }, + ] + ] ); + + $client = WikibaseClient::getDefaultInstance( 'reset' ); + $repositoryDefinitions = $client->getRepositoryDefinitions(); + + $this->assertEquals( 666, $repositoryDefinitions->getEntityNamespaces()['cool'] ); + $this->assertEquals( [ 'cool' ], $repositoryDefinitions->getEntityTypesPerRepository()['coolrepo'] ); + } + + public function testGivenNoRepoAssignedForCustomEntityType_entityNamespaceOnlyDefinedForLocalRepo() { + $clientSettings = $this->getDefaultSettings(); + + $clientSettings['repositories'] = [ + '' => [ + 'repoDatabase' => 'foodb', + 'entityNamespaces' => [ 'item' => 303, 'property' => 808 ], + 'baseUri' => 'http://foo.oof/entity/', + 'prefixMapping' => [ '' => '' ], + ], + ]; + + $this->setMwGlobals( 'wgWBClientSettings', $clientSettings ); + $this->setMwGlobals( 'wgHooks', [ + 'WikibaseEntityNamespaces' => [ + function ( &$namespaces ) { + $namespaces['cool'] = 666; + }, + ] + ] ); + + $client = WikibaseClient::getDefaultInstance( 'reset' ); + $repositoryDefinitions = $client->getRepositoryDefinitions(); + + $this->assertEquals( 666, $repositoryDefinitions->getEntityNamespaces()['cool'] ); + $this->assertEquals( [ 'item', 'property', 'cool' ], $repositoryDefinitions->getEntityTypesPerRepository()[''] ); + } + + private function getDefaultSettings() { + return array_merge( + require __DIR__ . '/../../../../lib/config/WikibaseLib.default.php', + require __DIR__ . '/../../../config/WikibaseClient.default.php' + ); + } + +} diff --git a/docs/federation.wiki b/docs/federation.wiki index 240e1f6..decfb0c 100644 --- a/docs/federation.wiki +++ b/docs/federation.wiki @@ -5,7 +5,7 @@ As of March 2017, in order to enable access to entities from federated repositories both Repo and Client components must be enabled. Also as of March 2017, accessing data of foreign entities relies on the shared database access (databases of federated repositories must be in the same database cluster). * Local repository is configured as documented in docs/options.wiki. -* Configuration of foreign repositories is done using the ''foreignRepositories'' setting in $wgWBRepoSettings or $wgWBClientSettings, as documented in the file docs/options.wiki. +* Configuration of foreign repositories is done using the ''foreignRepositories'' setting in $wgWBRepoSettings or ''repositories'' in $wgWBClientSettings, as documented in the file docs/options.wiki. * In order to correctly link entities from foreign repositories, the local wiki must have MediaWiki interwiki prefixes configured for each foreign repository. As of March 2017, the interwiki prefix must be the same as the name used for the foreign repository. If there is no interwiki prefix configured for the wiki containing the foreign repository, it can be added e.g. by adding a row to the <code>interwiki</code> database table, or by using [[Special:Interwiki]] if the Interwiki extension is enabled on the local wiki. Note that as of March 2017 it is only possible for Wikibase to use entities from a single repository, either local or foreign. For instance, it is not possible to use both local and foreign items in statements. diff --git a/docs/options.wiki b/docs/options.wiki index fee5d1e..7ad1e8a 100644 --- a/docs/options.wiki +++ b/docs/options.wiki @@ -8,16 +8,10 @@ === Basic Settings === -;entityNamespaces: Defines which kind of entity is managed in which namespace. It is given as an associative array mapping entity types such as <code>'item'</code> to namespace IDs. Mapping must be done for each type of entity that should be supported. ;changesDatabase: The database that changes are recorded to for processing by clients. This must be set to a symbolic database identifier that MediaWiki's LBFactory class understands; <code>false</code> means that the wiki's own database shall be used. '''Note''' that on the client, this setting should usually be the same as the '''repoDatabase''' setting. ;siteLinkGroups: The site groups to use in sitelinks. Must correspond to a value used to give the site group in the MediaWiki <code>sites</code> table. Default is <code>array( 'wikipedia' )</code>. This defines which groups of sites can be linked to Wikibase items. :'''Note''' that this setting replaces the old ''siteLinkGroup'' setting, which only allowed for a single group. ;specialSiteLinkGroups: This maps one or more site groups into a single "special" group. This is useful if sites from multiple site groups should be shown in a single "special" section on item pages, instead of one section per site group. To show these site-groups you have to add the group "special" to the '''siteLinkGroups''' setting (see above). -;foreignRepositories: An associative array mapping foreign repository names to settings relevant to the particular repository. Each repository's settings are an associative array containing the following keys: -:;'entityNamespaces': A map of entity type identifiers (strings) that the local wiki supports from the foreign repository to namespaces identifiers (numbers) related to pages of entities of the given type on foreign repository's wiki.. -:;'repoDatabase': A symbolic database identifier (string) that MediaWiki's LBFactory class understands. -:;'baseUri': A base URI (string) for concept URIs. It should contain scheme and authority part of the URI. -:;'prefixMapping': A prefix mapping array, see also: docs/foreign-entity-ids.wiki in the DataModel component. === Expert Settings === @@ -36,6 +30,7 @@ === Basic Settings === +;entityNamespaces: Defines which kind of entity is managed in which namespace. It is given as an associative array mapping entity types such as <code>'item'</code> to namespace IDs. Mapping must be done for each type of entity that should be supported. ;dataRightsUrl: URL to link to license for data contents. Defaults to <code>$wgRightsUrl</code> setting. ;dataRightsText: Text for data license link. Defaults to <code>$wgRightsText</code> setting. ;sparqlEndpoint: URL to the service description of the SPARQL end point for the repository. Defaults to null, meaning there is no SPARQL endpoint. @@ -44,6 +39,11 @@ ;conceptBaseUri: Base URI for building concept URIs (for example used in Rdf output). This has to include the protocol and domain, only an entity identifier will be appended. ;preferredGeoDataProperties: List of properties (by ID string), in order of preference, that are considered when finding primary coordinates for the GeoData extension on an entity. Defaults to an empty array. ;localClientDatabases: An array of locally accessible client databases, for use by the <code>dispatchChanges.php</code> script. This setting determines to which wikis changes are pushed directly. It must be given either as an associative array, mapping global site IDs to logical database names, or, of the database names are the same as the site IDs, as a list of databases. The default is an empty array, indicating no local client databases. +;foreignRepositories: An associative array mapping foreign repository names to settings relevant to the particular repository. Each repository's settings are an associative array containing the following keys: +:;'entityNamespaces': A map of entity type identifiers (strings) that the local wiki supports from the foreign repository to namespaces identifiers (numbers) related to pages of entities of the given type on foreign repository's wiki.. +:;'repoDatabase': A symbolic database identifier (string) that MediaWiki's LBFactory class understands. +:;'baseUri': A base URI (string) for concept URIs. It should contain scheme and authority part of the URI. +:;'prefixMapping': A prefix mapping array, see also: docs/foreign-entity-ids.wiki in the DataModel component. === Expert Settings === @@ -79,9 +79,12 @@ ;namespaces: List of namespaces on the client wiki that should have access to repository items. Default: <code>array()</code> (treated as setting is not set, ie. namespaces are enabled). ;excludeNamespaces: List of namespaces on the client wiki to disable wikibase links, etc. for. Default: <code>array()</code>. Example: <code>array( NS_USER_TALK )</code>. +;repositories: An associative array mapping repository names to settings relevant to the particular repository. Local repository is identified using the empty string as its name. Each repository's settings are an associative array containing the following keys: +:;'entityNamespaces': A map of entity type identifiers (strings) that the local wiki supports from the foreign repository to namespaces identifiers (numbers) related to pages of entities of the given type on foreign repository's wiki.. +:;'repoDatabase': A symbolic database identifier (string) that MediaWiki's LBFactory class understands. Note that <code>false</code> would mean "this wiki's database"! +:;'baseUri': A base URI (string) for concept URIs. It should contain scheme and authority part of the URI. +:;'prefixMapping': A prefix mapping array, see also: docs/foreign-entity-ids.wiki in the DataModel component. ;repoUrl: The repository's base URL, including the schema (protocol) and domain; This URL can be protocol-relative. Default is <code>'//wikidata.org'</code>. -:'''Note:''' This may be removed once we can get this information from the sites table. -;repoConceptBaseUri: The base of the repository's concept URIs. Default is <code>'<i>repoUrl</i>/entity/'</code>. :'''Note:''' This may be removed once we can get this information from the sites table. ;repoScriptPath: The repository's script path. Default is $wgScriptPath, assuming that the repo's script path is the same as this wiki's script path. :'''Note:''' This may be removed once we can get this information from the sites table. @@ -93,8 +96,6 @@ ;siteGroup: This site's site group (e.g. <code>'wikipedia'</code> or <code>'wikivoyage'</code>) as used in the sites table. The setting is optional and falls back to site store lookup. For performance reasons, it may be desireable to set this explicitly to avoid lookups. ;repoSiteId: Site ID of connected repository wiki. Default is to assume client and repo, so this setting defaults to siteGlobalID. ;repoSiteName: Site name of the connected repository wiki. Default is to assume client and repo are same wiki, so defaults to global $wgSitename setting. If not the same wiki, defaults to 'Wikidata'. This setting can also be set to an i18n message key and will be handled as a message, if the message key exists so that the repo site name can be translatable. -;repoDatabase: The logical name of the repository database, in a form that LBFactory can understand. If not <code>null</code>, the client wiki will access the repository's database directly, instead of locally caching information received via change notifications. Default: <code>null</code>. Note that <code>false</code> would mean "this wiki's database"! -:'''Note:''' This is currently required to be not <code>null</code>, since local caching is not fully implemented. ;repoNamespaces: An array telling the client wiki which namespaces on the repository are used for which entity type. This is given as an associative array mapping entity type IDs such as Item::ENTITY_TYPE, to namespace names. This information is used when constructing links to entities on the repository. Default (items in main namespace): <poem> array( diff --git a/lib/includes/WikibaseSettings.php b/lib/includes/WikibaseSettings.php index ad5abdc..b5057de 100644 --- a/lib/includes/WikibaseSettings.php +++ b/lib/includes/WikibaseSettings.php @@ -65,7 +65,10 @@ } $settings = self::getSettings( 'wgWBClientSettings' ); - $settings->setSetting( 'entityNamespaces', self::buildEntityNamespaceConfigurations( $settings ) ); + + $entityNamespaces = self::buildEntityNamespaceConfigurations( $settings ); + self::applyEntityNamespacesToSettings( $settings, $entityNamespaces ); + return $settings; } @@ -96,16 +99,46 @@ * @return int[] An array mapping entity type identifiers to namespace numbers. */ private static function buildEntityNamespaceConfigurations( SettingsArray $settings ) { - if ( !$settings->hasSetting( 'entityNamespaces' ) ) { + if ( !$settings->hasSetting( 'repositories' ) && !$settings->hasSetting( 'entityNamespaces' ) ) { throw new MWException( 'Wikibase: Incomplete configuration: ' . 'The \'entityNamespaces\' setting has to be set to an ' . 'array mapping entity types to namespace IDs. ' . 'See Wikibase.example.php for details and examples.' ); } - $namespaces = $settings->getSetting( 'entityNamespaces' ); + $namespaces = $settings->hasSetting( 'entityNamespaces' ) + ? $settings->getSetting( 'entityNamespaces' ) + : self::getEntityNamespacesFromRepositorySettings( $settings->getSetting( 'repositories' ) ); + Hooks::run( 'WikibaseEntityNamespaces', [ &$namespaces ] ); return $namespaces; } + private static function getEntityNamespacesFromRepositorySettings( array $repositorySettings ) { + return array_reduce( + $repositorySettings, + function ( array $result, array $repoSettings ) { + return array_merge( $result, $repoSettings['entityNamespaces'] ); + }, + [] + ); + } + + private static function applyEntityNamespacesToSettings( SettingsArray $settings, array $entityNamespaces ) { + if ( $settings->hasSetting( 'entityNamespaces' ) ) { + $settings->setSetting( 'entityNamespaces', $entityNamespaces ); + return; + } + + $repositorySettings = $settings->getSetting( 'repositories' ); + $namespacesDefinedForRepositories = self::getEntityNamespacesFromRepositorySettings( $repositorySettings ); + + $namespacesInNoRepository = array_diff_key( $entityNamespaces, $namespacesDefinedForRepositories ); + + if ( $namespacesInNoRepository ) { + $repositorySettings['']['entityNamespaces'] += $namespacesInNoRepository; + $settings->setSetting( 'repositories', $repositorySettings ); + } + } + } -- To view, visit https://gerrit.wikimedia.org/r/400415 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I2eee36256260490d7b3ddf6c83389f810239835c Gerrit-PatchSet: 14 Gerrit-Project: mediawiki/extensions/Wikibase Gerrit-Branch: master Gerrit-Owner: Ladsgroup <ladsgr...@gmail.com> Gerrit-Reviewer: WMDE-leszek <leszek.mani...@wikimedia.de> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits