jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/334749 )
Change subject: New Wikidata Build - 2017-01-28T10:00:02+0000 ...................................................................... New Wikidata Build - 2017-01-28T10:00:02+0000 Change-Id: I38256934302440e4d906f29fa09a05c191a085a1 --- M composer.lock A extensions/Wikibase/CREDITS M extensions/Wikibase/client/WikibaseClient.php M extensions/Wikibase/client/i18n/hu.json M extensions/Wikibase/client/i18n/lzh.json M extensions/Wikibase/client/i18n/my.json M extensions/Wikibase/client/includes/DispatchingServiceFactory.php M extensions/Wikibase/client/includes/Store/RepositoryServiceContainer.php A extensions/Wikibase/client/includes/Store/RepositoryServiceContainerFactory.php M extensions/Wikibase/client/includes/WikibaseClient.php M extensions/Wikibase/client/tests/phpunit/includes/DispatchingServiceFactoryTest.php M extensions/Wikibase/client/tests/phpunit/includes/DispatchingServiceWiringTest.php A extensions/Wikibase/client/tests/phpunit/includes/Store/RepositoryServiceContainerFactoryTest.php M extensions/Wikibase/client/tests/phpunit/includes/Store/RepositoryServiceContainerTest.php M extensions/Wikibase/client/tests/phpunit/includes/Store/Sql/DirectSqlStoreTest.php M extensions/Wikibase/docs/change-op-serializations.wiki M extensions/Wikibase/docs/extending-entities.wiki M extensions/Wikibase/lib/WikibaseLib.php M extensions/Wikibase/lib/includes/Store/CacheAwarePropertyInfoStore.php M extensions/Wikibase/lib/tests/phpunit/MockRepository.php M extensions/Wikibase/lib/tests/phpunit/Store/EntityInfoBuilderTest.php M extensions/Wikibase/lib/tests/phpunit/Store/Sql/SqlEntityInfoBuilderTest.php M extensions/Wikibase/repo/Wikibase.php M extensions/Wikibase/repo/i18n/bn.json M extensions/Wikibase/repo/i18n/de.json M extensions/Wikibase/repo/i18n/es.json M extensions/Wikibase/repo/i18n/ml.json M extensions/Wikibase/repo/i18n/my.json M extensions/Wikibase/repo/includes/Api/ParseValue.php M extensions/Wikibase/repo/includes/Content/EntityContent.php M extensions/Wikibase/repo/includes/Search/Elastic/Fields/LabelCountField.php M extensions/Wikibase/repo/includes/Validators/LabelDescriptionUniquenessValidator.php M extensions/Wikibase/repo/includes/Validators/LabelUniquenessValidator.php M extensions/Wikibase/repo/tests/phpunit/includes/Api/ParseValueTest.php M extensions/Wikibase/repo/tests/phpunit/includes/Api/StatementModificationHelperTest.php M extensions/Wikibase/repo/tests/phpunit/includes/ChangeOp/ChangeOpLabelTest.php M extensions/Wikibase/repo/tests/phpunit/includes/Content/EntityContentTest.php M extensions/Wikibase/repo/tests/phpunit/includes/Specials/SpecialGoToLinkedPageTest.php M extensions/Wikibase/repo/tests/phpunit/includes/Specials/SpecialModifyTermTestCase.php M vendor/composer/autoload_classmap.php M vendor/composer/installed.json 41 files changed, 1,042 insertions(+), 278 deletions(-) Approvals: Aude: Looks good to me, approved jenkins-bot: Verified diff --git a/composer.lock b/composer.lock index 7770ba1..22953e8 100644 --- a/composer.lock +++ b/composer.lock @@ -1606,12 +1606,12 @@ "source": { "type": "git", "url": "https://github.com/wikimedia/mediawiki-extensions-Wikibase.git", - "reference": "429ab38c5ddf34438425a4012b08fcba806fb54b" + "reference": "5c39fd44085adf7797e5084a7754b7631c2f2e1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/429ab38c5ddf34438425a4012b08fcba806fb54b", - "reference": "429ab38c5ddf34438425a4012b08fcba806fb54b", + "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/5c39fd44085adf7797e5084a7754b7631c2f2e1b", + "reference": "5c39fd44085adf7797e5084a7754b7631c2f2e1b", "shasum": "" }, "require": { @@ -1686,7 +1686,7 @@ "wikibaserepo", "wikidata" ], - "time": "2017-01-26 15:15:12" + "time": "2017-01-27 16:09:49" }, { "name": "wikibase/wikimedia-badges", diff --git a/extensions/Wikibase/CREDITS b/extensions/Wikibase/CREDITS new file mode 100644 index 0000000..d9f8505 --- /dev/null +++ b/extensions/Wikibase/CREDITS @@ -0,0 +1,156 @@ +<!-- +Wikibase is a collaborative project released under the +GNU General Public License v2. We would like to recognize +the following names for their contribution to the product. + +The following list can be found parsed under: + * Special:Version/Credits/Wikibase_Repository + * Special:Version/Credits/Wikibase_Client + * Special:Version/Credits/WikibaseLib +--> +== Team members == + +This includes current and previous members. + +* Abraham Taherivand +* addshore +* Adrian Heine +* Aleksey Bekh-Ivanov +* Amir Sarabadani +* Anja Jentzsch +* Bene +* Christopher Johnson +* Daniel Kinzler +* Daniel Werner +* Denny Vrandečić +* H. Snater +* Jakob Warkotsch +* Jan Dittrich +* Jan Zerebecki +* Jens Ohlig +* Jeroen De Dauw +* John Erling Blad +* Jonas Kress +* Katie Filbert +* Leszek Manicki +* Lucie-Aimée Kaffee +* Lydia Pintscher +* Marius Hoch +* Markus Krötzsch +* Nikola Smolenski +* Stanislav Malyshev +* Thiemo Mättig +* Tobias Gritschacher + +== Patch Contributors == +* 1ec5 +* Aaron Schulz +* Aftab +* Alangi Derick +* albe +* Alexander Lehmann +* Alex Monk +* Amir E. Aharoni +* Antoine Musso +* Arkanosis +* atlight +* ayush_garg +* Bartosz Dziewoński +* Beta16 +* blotmandroid +* Brad Jorsch +* ch3nkula +* Chad Horohoe +* dachary +* danmichaelo +* Dan Michael O. Heggø +* Dereckson +* Ebrahim Byagowi +* ecotg +* Erik Bernhardson +* Federico Leva +* feelfreelinux +* Florian Schmidt +* Fomafix +* GEOFBOT +* Geoffrey Mon +* Gergő Tisza +* Gilles Dubuc +* gladoscc +* Granjow +* Hostmaster of the Day +* Jack Phoenix +* JadeMaveric +* Jared Flores +* jcf2000 +* Joan Creus +* Julia Himmel +* julius +* Justin Du +* Jérémie Roquet +* karan +* karan10 +* Kevin Israel +* kghbln +* Kunal Mehta +* kushal124 +* Kushal Khandelwal +* lalexf +* LB-42 +* Leon Liesener +* Liangent +* Loic Dachary +* lokal-profil +* mary-kate +* Matěj Suchánek +* mayankmadan +* mdex192837 +* Michał Łazowik +* Minh Nguyễn +* mjbmr +* mlazowik +* MtDu +* multichill +* Mushroom +* Ori Livneh +* Paladox +* Pavel Selitskas +* plstand +* pragunbhutani +* Purodha +* Raimond Spekking +* Raymond +* raymondde +* Ricordisamoa +* rlot +* Ryan Kaldari +* Sam Reed +* Schnark +* se4598 +* shirayuki +* Siebrand Mazeland +* Simon A. Eugster +* Sn1per +* Southparkfan +* S Page +* subins2000 +* Subin Siby +* tholam +* Timo Tijhof +* Tim Starling +* Tom Arrow +* Tony Thomas +* Tpt +* TTO +* Umherirrender +* Urbanecm +* vikassy +* vldandrew +* wizardist +* Yuki Shira +* [[mw:User:GZWDer]] +* Željko Filipin + +== Translators == + +* [https://translatewiki.net/wiki/Translating:MediaWiki/Credits Translators on translatewiki.net and others] diff --git a/extensions/Wikibase/client/WikibaseClient.php b/extensions/Wikibase/client/WikibaseClient.php index 6a95bfe..07df902 100644 --- a/extensions/Wikibase/client/WikibaseClient.php +++ b/extensions/Wikibase/client/WikibaseClient.php @@ -78,7 +78,7 @@ 'name' => 'Wikibase Client', 'version' => WBC_VERSION, 'author' => array( - 'The Wikidata team', // TODO: link? + 'The Wikidata team', ), 'url' => 'https://www.mediawiki.org/wiki/Extension:Wikibase_Client', 'descriptionmsg' => 'wikibase-client-desc', diff --git a/extensions/Wikibase/client/i18n/hu.json b/extensions/Wikibase/client/i18n/hu.json index 163c29a..d5fcce2 100644 --- a/extensions/Wikibase/client/i18n/hu.json +++ b/extensions/Wikibase/client/i18n/hu.json @@ -81,5 +81,7 @@ "notification-header-page-connection": "A(z) <strong>$3</strong> {{GENDER:$2|össze lett kapcsolva}} egy {{WBREPONAME}}-elemmel", "notification-bundle-header-page-connection": "<strong>$3</strong> és {{PLURAL:$4|még egy|$4 másik|100=99+ másik}} lap {{GENDER:$2|össze lett kapcsolva}} {{WBREPONAME}}-elemekkel.", "notification-link-text-view-item": "Elem {{GENDER:$1|megtekintése}}", - "notification-subject-page-connection": "A(z) {{SITENAME}} wikin {{GENDER:$3|létrehozott}} oldaladat {{GENDER:$2|összekapcsolták}} egy {{WBREPONAME}}-elemmel" + "notification-subject-page-connection": "A(z) {{SITENAME}} wikin {{GENDER:$3|létrehozott}} oldaladat {{GENDER:$2|összekapcsolták}} egy {{WBREPONAME}}-elemmel", + "unresolved-property-category": "Lapok feloldhatatlan tulajdonságokkal", + "unresolved-property-category-desc": "Ez a kategória azokat a lapokat listázza, amik olyan {{WBREPONAME}}-tulajdonságokat próbálnak lekérdezni, amiket sem az azonosítójuk, sem a címkéjük alapján nem sikerült megtalálni." } diff --git a/extensions/Wikibase/client/i18n/lzh.json b/extensions/Wikibase/client/i18n/lzh.json index fbf8b4c..418ed0f 100644 --- a/extensions/Wikibase/client/i18n/lzh.json +++ b/extensions/Wikibase/client/i18n/lzh.json @@ -7,6 +7,7 @@ "SolidBlock" ] }, + "wikibase-after-page-move": "斯頁自有相繫者,在於{{WBREPONAME}}。君既改其題,亦宜改其[$1 相繫之頁]。然後諸語之間,方能不斷連結。", "wikibase-comment-update": "{{WBREPONAME}}項變", "wikibase-editlinks": "纂鏈", "wikibase-editlinkstitle": "修跨語鏈", diff --git a/extensions/Wikibase/client/i18n/my.json b/extensions/Wikibase/client/i18n/my.json index 237b1c6..841dfc9 100644 --- a/extensions/Wikibase/client/i18n/my.json +++ b/extensions/Wikibase/client/i18n/my.json @@ -5,6 +5,7 @@ "9.sinistra" ] }, + "wikibase-comment-update": "{{WBREPONAME}} item ပြောင်းလဲခဲ့သည်", "wikibase-dataitem": "{{WBREPONAME}} item", "wikibase-editlinks": "လင့်ခ်များကို တည်းဖြတ်ရန်", "wikibase-editlinkstitle": "ဘာသာစကားလင့်ခ်များကို တည်းဖြတ်ရန်", diff --git a/extensions/Wikibase/client/includes/DispatchingServiceFactory.php b/extensions/Wikibase/client/includes/DispatchingServiceFactory.php index 28ca917..546b00d 100644 --- a/extensions/Wikibase/client/includes/DispatchingServiceFactory.php +++ b/extensions/Wikibase/client/includes/DispatchingServiceFactory.php @@ -4,23 +4,36 @@ use MediaWiki\Services\ServiceContainer; use Wikibase\Client\Store\RepositoryServiceContainer; -use Wikibase\DataModel\Services\EntityId\PrefixMappingEntityIdParserFactory; +use Wikibase\Client\Store\RepositoryServiceContainerFactory; +use Wikibase\DataModel\Services\Lookup\UnknownForeignRepositoryException; +use Wikibase\DataModel\Entity\EntityId; +use Wikibase\DataModel\Entity\EntityRedirect; use Wikibase\DataModel\Services\Term\TermBuffer; -use Wikibase\Lib\Serialization\RepositorySpecificDataValueDeserializerFactory; +use Wikibase\EntityRevision; use Wikibase\Lib\Store\EntityRevisionLookup; +use Wikibase\Lib\Store\EntityStoreWatcher; use Wikibase\Lib\Store\PropertyInfoLookup; -use Wikibase\SettingsArray; /** * A factory/locator of services dispatching the action to services configured for the * particular input, based on the repository the particular input entity belongs to. * Dispatching services provide a way of using entities from multiple repositories. * - * Services are defined by loading a wiring array(s), or by using defineService method. + * Services are defined by loading wiring arrays, or by using defineService method. * * @license GPL-2.0+ */ -class DispatchingServiceFactory extends ServiceContainer implements EntityDataRetrievalServiceFactory { +class DispatchingServiceFactory extends ServiceContainer implements EntityDataRetrievalServiceFactory, EntityStoreWatcher { + + /** + * @var string[] + */ + private $repositoryNames; + + /** + * @var RepositoryServiceContainerFactory + */ + private $repositoryServiceContainerFactory; /** * @var RepositoryServiceContainer[] @@ -28,83 +41,17 @@ private $repositoryServiceContainers = []; /** - * FIXME: injecting of the top-level factory (WikibaseClient) here is only a temporary solution. - * This class uses top-level factory to access settings and several services provided by the top-level - * factory. Also, the instance of the top-level factory is being passed to instantiators of services - * stored in the RepositoryServiceContainer in order to get service they depend on. - * - * This approach is not clean, the class should not depend on the top-level factory. - * This should be changed after some refactoring: this factory should be able to instantiate - * services it now gets from the client. Config should be also passed in properly, without - * a need to inject WikibaseClient instance to access relevant settings. Instantiators - * in RepositoryServiceWiring should rather be getting some other service container, not the - * whole top-level factory. - * - * @param WikibaseClient $client + * @param RepositoryServiceContainerFactory $repositoryServiceContainerFactory + * @param string[] $repositoryNames */ - public function __construct( WikibaseClient $client ) { + public function __construct( + RepositoryServiceContainerFactory $repositoryServiceContainerFactory, + array $repositoryNames + ) { parent::__construct(); - $this->initRepositoryServiceContainers( $client ); - } - - private function initRepositoryServiceContainers( WikibaseClient $client ) { - $repositoryNames = array_merge( - [ '' ], - array_keys( $client->getSettings()->getSetting( 'foreignRepositories' ) ) - ); - - $idParserFactory = new PrefixMappingEntityIdParserFactory( - $client->getEntityIdParser(), // TODO: this should be moved to this class; see T153427 - $this->getIdPrefixMaps( $client->getSettings()->getSetting( 'foreignRepositories' ) ) - ); - $dataValueDeserializerFactory = new RepositorySpecificDataValueDeserializerFactory( $idParserFactory ); - - foreach ( $repositoryNames as $repositoryName ) { - $container = new RepositoryServiceContainer( - $this->getRepositoryDatabaseName( $repositoryName, $client->getSettings() ), - $repositoryName, - $idParserFactory->getIdParser( $repositoryName ), - $dataValueDeserializerFactory->getDeserializer( $repositoryName ), - $client - ); - $container->loadWiringFiles( $client->getSettings()->getSetting( 'repositoryServiceWiringFiles' ) ); - - $this->repositoryServiceContainers[$repositoryName] = $container; - } - } - - /** - * Returns a map of id prefix mappings defined for configured foreign repositories. - * - * @param array[] $settings Repository definitions mapping repository names to settings - * - * @return array[] Associative array mapping repository names to repository-specific prefix - * mapping. - */ - private function getIdPrefixMaps( array $settings ) { - $mappings = []; - foreach ( $settings as $repositoryName => $repositorySettings ) { - if ( array_key_exists( 'prefixMapping', $repositorySettings ) ) { - $mappings[$repositoryName] = $repositorySettings['prefixMapping']; - } - } - return $mappings; - } - - /** - * @param string $repositoryName - * @param SettingsArray $settings - * - * @return string|false - */ - private function getRepositoryDatabaseName( $repositoryName, SettingsArray $settings ) { - if ( $repositoryName === '' ) { - return $settings->getSetting( 'repoDatabase' ); - } - - $foreignRepoSettings = $settings->getSetting( 'foreignRepositories' ); - return $foreignRepoSettings[$repositoryName]['repoDatabase']; + $this->repositoryServiceContainerFactory = $repositoryServiceContainerFactory; + $this->repositoryNames = $repositoryNames; } /** @@ -113,13 +60,78 @@ */ public function getServiceMap( $service ) { $serviceMap = []; - foreach ( $this->repositoryServiceContainers as $repositoryName => $container ) { + foreach ( $this->repositoryNames as $repositoryName ) { + $container = $this->getContainerForRepository( $repositoryName ); + if ( $container !== null ) { $serviceMap[$repositoryName] = $container->getService( $service ); + } } return $serviceMap; } /** + * @param string $repositoryName + * + * @return RepositoryServiceContainer|null + */ + private function getContainerForRepository( $repositoryName ) { + if ( !array_key_exists( $repositoryName, $this->repositoryServiceContainers ) ) { + try { + $this->repositoryServiceContainers[$repositoryName] = + $this->repositoryServiceContainerFactory->newContainer( $repositoryName ); + } catch ( UnknownForeignRepositoryException $exception ) { + $this->repositoryServiceContainers[$repositoryName] = null; + } + } + + return $this->repositoryServiceContainers[$repositoryName]; + } + + /** + * @see EntityStoreWatcher::entityUpdated + * + * @param EntityRevision $entityRevision + */ + public function entityUpdated( EntityRevision $entityRevision ) { + $container = $this->getContainerForRepository( + $entityRevision->getEntity()->getId()->getRepositoryName() + ); + + if ( $container !== null ) { + $container->entityUpdated( $entityRevision ); + } + } + + /** + * @see EntityStoreWatcher::entityDeleted + * + * @param EntityId $entityId + */ + public function entityDeleted( EntityId $entityId ) { + $container = $this->getContainerForRepository( $entityId->getRepositoryName() ); + + if ( $container !== null ) { + $container->entityDeleted( $entityId ); + } + } + + /** + * @see EntityStoreWatcher::redirectUpdated + * + * @param EntityRedirect $entityRedirect + * @param int $revisionId + */ + public function redirectUpdated( EntityRedirect $entityRedirect, $revisionId ) { + $container = $this->getContainerForRepository( + $entityRedirect->getEntityId()->getRepositoryName() + ); + + if ( $container !== null ) { + $container->redirectUpdated( $entityRedirect, $revisionId ); + } + } + + /** * @return EntityRevisionLookup */ public function getEntityRevisionLookup() { diff --git a/extensions/Wikibase/client/includes/Store/RepositoryServiceContainer.php b/extensions/Wikibase/client/includes/Store/RepositoryServiceContainer.php index 36c7b5b..74c8799 100644 --- a/extensions/Wikibase/client/includes/Store/RepositoryServiceContainer.php +++ b/extensions/Wikibase/client/includes/Store/RepositoryServiceContainer.php @@ -8,8 +8,12 @@ use MediaWiki\Services\ServiceContainer; use Wikibase\Client\WikibaseClient; use Wikibase\DataModel\DeserializerFactory; +use Wikibase\DataModel\Entity\EntityId; use Wikibase\DataModel\Entity\EntityIdParser; +use Wikibase\DataModel\Entity\EntityRedirect; +use Wikibase\EntityRevision; use Wikibase\InternalSerialization\DeserializerFactory as InternalDeserializerFactory; +use Wikibase\Lib\Store\EntityStoreWatcher; /** * A service locator for services configured for a particular repository. @@ -17,7 +21,7 @@ * * @license GPL-2.0+ */ -class RepositoryServiceContainer extends ServiceContainer { +class RepositoryServiceContainer extends ServiceContainer implements EntityStoreWatcher { /** * @var string|false @@ -121,4 +125,47 @@ return $internalDeserializerFactory->newEntityDeserializer(); } + /** + * @see EntityStoreWatcher::entityUpdated + * + * @param EntityRevision $entityRevision + */ + public function entityUpdated( EntityRevision $entityRevision ) { + foreach ( $this->getServiceNames() as $serviceName ) { + $service = $this->peekService( $serviceName ); + if ( $service instanceof EntityStoreWatcher ) { + $service->entityUpdated( $entityRevision ); + } + } + } + + /** + * @see EntityStoreWatcher::entityDeleted + * + * @param EntityId $entityId + */ + public function entityDeleted( EntityId $entityId ) { + foreach ( $this->getServiceNames() as $serviceName ) { + $service = $this->peekService( $serviceName ); + if ( $service instanceof EntityStoreWatcher ) { + $service->entityDeleted( $entityId ); + } + } + } + + /** + * @see EntityStoreWatcher::redirectUpdated + * + * @param EntityRedirect $entityRedirect + * @param int $revisionId + */ + public function redirectUpdated( EntityRedirect $entityRedirect, $revisionId ) { + foreach ( $this->getServiceNames() as $serviceName ) { + $service = $this->peekService( $serviceName ); + if ( $service instanceof EntityStoreWatcher ) { + $service->redirectUpdated( $entityRedirect, $revisionId ); + } + } + } + } diff --git a/extensions/Wikibase/client/includes/Store/RepositoryServiceContainerFactory.php b/extensions/Wikibase/client/includes/Store/RepositoryServiceContainerFactory.php new file mode 100644 index 0000000..128f367 --- /dev/null +++ b/extensions/Wikibase/client/includes/Store/RepositoryServiceContainerFactory.php @@ -0,0 +1,98 @@ +<?php + +namespace Wikibase\Client\Store; + +use Wikibase\Client\WikibaseClient; +use Wikibase\DataModel\Services\EntityId\PrefixMappingEntityIdParserFactory; +use Wikibase\DataModel\Services\Lookup\UnknownForeignRepositoryException; +use Wikibase\Lib\Serialization\RepositorySpecificDataValueDeserializerFactory; + +/** + * A factory providing RepositoryServiceContainer objects configured for given repository. + * RepositoryServiceContainers are initialized using wiring files provided in the constructor. + * + * @license GPL-2.0+ + */ +class RepositoryServiceContainerFactory { + + /** + * @var PrefixMappingEntityIdParserFactory + */ + private $idParserFactory; + + /** + * @var RepositorySpecificDataValueDeserializerFactory + */ + private $dataValueDeserializerFactory; + + /** + * Associative array mapping repository names to database names (string or false) + * + * @var array + */ + private $databaseNames; + + /** + * @var string[] + */ + private $wiringFiles; + + /** + * @var WikibaseClient + */ + private $client; + + /** + * FIXME: injecting of the top-level factory (WikibaseClient) here is only a temporary solution. + * The instance of the top-level factory is being passed to instantiators of services + * stored in the RepositoryServiceContainer so they can get the service they depend on. + * + * This approach is not clean, the class should not depend on the top-level factory. + * This should be changed after some refactoring: Instantiators in RepositoryServiceWiring should + * rather be getting some other service container, not the whole top-level factory. + * + * @param PrefixMappingEntityIdParserFactory $idParserFactory + * @param RepositorySpecificDataValueDeserializerFactory $dataValueDeserializerFactory + * @param array $repositoryDatabaseNames + * @param string[] $wiringFiles + * @param WikibaseClient $client + */ + public function __construct( + PrefixMappingEntityIdParserFactory $idParserFactory, + RepositorySpecificDataValueDeserializerFactory $dataValueDeserializerFactory, + array $repositoryDatabaseNames, + array $wiringFiles, + WikibaseClient $client + ) { + $this->idParserFactory = $idParserFactory; + $this->dataValueDeserializerFactory = $dataValueDeserializerFactory; + $this->databaseNames = $repositoryDatabaseNames; + $this->wiringFiles = $wiringFiles; + $this->client = $client; + } + + /** + * @param string $repositoryName + * + * @return RepositoryServiceContainer + * + * @throws UnknownForeignRepositoryException + */ + public function newContainer( $repositoryName ) { + if ( !array_key_exists( $repositoryName, $this->databaseNames ) ) { + throw new UnknownForeignRepositoryException( $repositoryName ); + } + + $container = new RepositoryServiceContainer( + $this->databaseNames[$repositoryName], + $repositoryName, + $this->idParserFactory->getIdParser( $repositoryName ), + $this->dataValueDeserializerFactory->getDeserializer( $repositoryName ), + $this->client + ); + $container->loadWiringFiles( $this->wiringFiles ); + + return $container; + } + +} diff --git a/extensions/Wikibase/client/includes/WikibaseClient.php b/extensions/Wikibase/client/includes/WikibaseClient.php index 2f07c6b..ef8f447 100644 --- a/extensions/Wikibase/client/includes/WikibaseClient.php +++ b/extensions/Wikibase/client/includes/WikibaseClient.php @@ -40,8 +40,10 @@ use Wikibase\Client\ParserOutput\ClientParserOutputDataUpdater; use Wikibase\Client\RecentChanges\RecentChangeFactory; use Wikibase\Client\Serializer\ForbiddenSerializer; +use Wikibase\Client\Store\RepositoryServiceContainerFactory; use Wikibase\DataModel\Entity\EntityIdValue; use Wikibase\DataModel\SerializerFactory; +use Wikibase\DataModel\Services\EntityId\PrefixMappingEntityIdParserFactory; use Wikibase\DataModel\Services\Lookup\RestrictedEntityLookup; use Wikibase\Client\DataAccess\SnaksFinder; use Wikibase\Client\Hooks\LanguageLinkBadgeDisplay; @@ -72,6 +74,7 @@ use Wikibase\Lib\EntityIdComposer; use Wikibase\Lib\EntityTypeDefinitions; use Wikibase\Lib\FormatterLabelDescriptionLookupFactory; +use Wikibase\Lib\Serialization\RepositorySpecificDataValueDeserializerFactory; use Wikibase\Lib\Store\LanguageFallbackLabelDescriptionLookupFactory; use Wikibase\Lib\LanguageNameLookup; use Wikibase\Lib\MediaWikiContentLanguages; @@ -374,7 +377,14 @@ */ private function getEntityDataRetrievalServiceFactory() { if ( $this->entityDataRetrievalServiceFactory === null ) { - $factory = new DispatchingServiceFactory( $this ); + $factory = new DispatchingServiceFactory( + $this->getRepositoryServiceContainerFactory(), + // FIXME: array_merge trick will no longer be needed once repositry settings are unified, see: T153767. + array_merge( + [ '' ], + array_keys( $this->getSettings()->getSetting( 'foreignRepositories' ) ) + ) + ); $factory->loadWiringFiles( $this->settings->getSetting( 'dispatchingServiceWiringFiles' ) ); $this->entityDataRetrievalServiceFactory = $factory; @@ -383,6 +393,59 @@ return $this->entityDataRetrievalServiceFactory; } + private function getRepositoryServiceContainerFactory() { + $idParserFactory = new PrefixMappingEntityIdParserFactory( + $this->getEntityIdParser(), + $this->getIdPrefixMaps() + ); + + return new RepositoryServiceContainerFactory( + $idParserFactory, + new RepositorySpecificDataValueDeserializerFactory( $idParserFactory ), + $this->getRepositoryDatabaseNames(), + $this->getSettings()->getSetting( 'repositoryServiceWiringFiles' ), + $this + ); + } + + /** + * Returns an associative array mapping names of configured repositories to respective database names + * (either strings or false for local wiki's database). + * Returned map contains an empty string key for a local repository. + * + * @return array + */ + private function getRepositoryDatabaseNames() { + // FIXME: t no longer be needed to check different settings (repoDatabase vs foreignRepositories + // once repositry settings are unified, see: T153767. + $databaseNames = [ '' => $this->getSettings()->getSetting( 'repoDatabase' ) ]; + + foreach ( $this->getSettings()->getSetting( 'foreignRepositories' ) + as $repositoryName => $repositorySettings + ) { + $databaseNames[$repositoryName] = $repositorySettings['repoDatabase']; + } + + return $databaseNames; + } + + /** + * Returns a map of id prefix mappings defined for configured foreign repositories. + * + * @return array[] Associative array mapping repository names to repository-specific prefix mapping. + */ + private function getIdPrefixMaps() { + $mappings = []; + foreach ( $this->getSettings()->getSetting( 'foreignRepositories' ) + as $repositoryName => $repositorySettings + ) { + if ( array_key_exists( 'prefixMapping', $repositorySettings ) ) { + $mappings[$repositoryName] = $repositorySettings['prefixMapping']; + } + } + return $mappings; + } + /** * @return EntityLookup */ diff --git a/extensions/Wikibase/client/tests/phpunit/includes/DispatchingServiceFactoryTest.php b/extensions/Wikibase/client/tests/phpunit/includes/DispatchingServiceFactoryTest.php index f55acf9..3e49b22 100644 --- a/extensions/Wikibase/client/tests/phpunit/includes/DispatchingServiceFactoryTest.php +++ b/extensions/Wikibase/client/tests/phpunit/includes/DispatchingServiceFactoryTest.php @@ -2,8 +2,16 @@ namespace Wikibase\Client\Tests; +use DataValues\Deserializers\DataValueDeserializer; use Wikibase\Client\DispatchingServiceFactory; +use Wikibase\Client\Store\RepositoryServiceContainer; +use Wikibase\Client\Store\RepositoryServiceContainerFactory; use Wikibase\Client\WikibaseClient; +use Wikibase\DataModel\Entity\BasicEntityIdParser; +use Wikibase\DataModel\Entity\EntityRedirect; +use Wikibase\DataModel\Entity\Item; +use Wikibase\DataModel\Entity\ItemId; +use Wikibase\EntityRevision; use Wikibase\Lib\Store\EntityRevisionLookup; /** @@ -17,14 +25,43 @@ class DispatchingServiceFactoryTest extends \PHPUnit_Framework_TestCase { /** + * @return RepositoryServiceContainerFactory + */ + private function getRepositoryServiceContainerFactory() { + $entityRevisionLookup = $this->getMock( EntityRevisionLookup::class ); + + $container = $this->getMockBuilder( RepositoryServiceContainer::class ) + ->disableOriginalConstructor() + ->getMock(); + $container->expects( $this->any() ) + ->method( 'getService' ) + ->will( + $this->returnCallback( function ( $service ) use ( $entityRevisionLookup ) { + return $service === 'EntityRevisionLookup' ? $entityRevisionLookup : null; + } ) + ); + + $containerFactory = $this->getMockBuilder( RepositoryServiceContainerFactory::class ) + ->disableOriginalConstructor() + ->getMock(); + $containerFactory->expects( $this->any() ) + ->method( 'newContainer' ) + ->will( $this->returnValue( $container ) ); + + return $containerFactory; + } + + /** + * @param RepositoryServiceContainerFactory $containerFactory + * * @return DispatchingServiceFactory */ - private function getDispatchingServiceFactory() { + private function getDispatchingServiceFactory( RepositoryServiceContainerFactory $containerFactory ) { $client = WikibaseClient::getDefaultInstance(); $settings = $client->getSettings(); $settings->setSetting( 'foreignRepositories', [ 'foo' => [ 'repoDatabase' => 'foowiki' ] ] ); - $factory = new DispatchingServiceFactory( $client ); + $factory = new DispatchingServiceFactory( $containerFactory, [ '', 'foo' ] ); $factory->defineService( 'EntityRevisionLookup', function() { return $this->getMock( EntityRevisionLookup::class ); @@ -34,7 +71,7 @@ } public function testGetServiceNames() { - $factory = $this->getDispatchingServiceFactory(); + $factory = $this->getDispatchingServiceFactory( $this->getRepositoryServiceContainerFactory() ); $this->assertEquals( [ 'EntityRevisionLookup' ], @@ -43,7 +80,7 @@ } public function testGetServiceMap() { - $factory = $this->getDispatchingServiceFactory(); + $factory = $this->getDispatchingServiceFactory( $this->getRepositoryServiceContainerFactory() ); $serviceMap = $factory->getServiceMap( 'EntityRevisionLookup' ); @@ -55,7 +92,7 @@ } public function testGetService() { - $factory = $this->getDispatchingServiceFactory(); + $factory = $this->getDispatchingServiceFactory( $this->getRepositoryServiceContainerFactory() ); $serviceOne = $factory->getService( 'EntityRevisionLookup' ); $serviceTwo = $factory->getService( 'EntityRevisionLookup' ); @@ -65,4 +102,75 @@ $this->assertSame( $serviceOne, $serviceTwo ); } + /** + * @param string|false $dbName + * @param string $repositoryName + * + * @return RepositoryServiceContainer + */ + private function getRepositoryServiceContainer( $dbName, $repositoryName ) { + return new RepositoryServiceContainer( + $dbName, + $repositoryName, + new BasicEntityIdParser(), + new DataValueDeserializer( [] ), + WikibaseClient::getDefaultInstance() + ); + } + + /** + * @param string $event + * + * @return RepositoryServiceContainerFactory + */ + private function getRepositoryServiceContainerFactoryForEventTest( $event ) { + $localServiceContainer = $this->getMockBuilder( RepositoryServiceContainer::class ) + ->disableOriginalConstructor() + ->getMock(); + $localServiceContainer->expects( $this->never() )->method( $event ); + + $fooServiceContainer = $this->getMockBuilder( RepositoryServiceContainer::class ) + ->disableOriginalConstructor() + ->getMock(); + $fooServiceContainer->expects( $this->atLeastOnce() )->method( $event ); + + $containerFactory = $this->getMockBuilder( RepositoryServiceContainerFactory::class ) + ->disableOriginalConstructor() + ->getMock(); + + $containerFactory->expects( $this->any() ) + ->method( 'newContainer' ) + ->will( + $this->returnCallback( function ( $container ) use ( $localServiceContainer, $fooServiceContainer ) { + return $container === '' ? $localServiceContainer : $fooServiceContainer; + } ) + ); + + return $containerFactory; + } + + public function testEntityUpdatedDelegatesEventToContainerOfRelevantRepository() { + $factory = $this->getDispatchingServiceFactory( + $this->getRepositoryServiceContainerFactoryForEventTest( 'entityUpdated' ) + ); + + $factory->entityUpdated( new EntityRevision( new Item( new ItemId( 'foo:Q123' ) ) ) ); + } + + public function testEntityDeletedDelegatesEventToContainerOfRelevantRepository() { + $factory = $this->getDispatchingServiceFactory( + $this->getRepositoryServiceContainerFactoryForEventTest( 'entityDeleted' ) + ); + + $factory->entityDeleted( new ItemId( 'foo:Q123' ) ); + } + + public function testRedirectUpdatedDelegatesEventToContainerOfRelevantRepository() { + $factory = $this->getDispatchingServiceFactory( + $this->getRepositoryServiceContainerFactoryForEventTest( 'redirectUpdated' ) + ); + + $factory->redirectUpdated( new EntityRedirect( new ItemId( 'foo:Q123' ), new ItemId( 'foo:Q321' ) ), 100 ); + } + } diff --git a/extensions/Wikibase/client/tests/phpunit/includes/DispatchingServiceWiringTest.php b/extensions/Wikibase/client/tests/phpunit/includes/DispatchingServiceWiringTest.php index eb61f06..8433c4e 100644 --- a/extensions/Wikibase/client/tests/phpunit/includes/DispatchingServiceWiringTest.php +++ b/extensions/Wikibase/client/tests/phpunit/includes/DispatchingServiceWiringTest.php @@ -3,8 +3,12 @@ namespace Wikibase\Client\Tests; use Wikibase\Client\DispatchingServiceFactory; +use Wikibase\Client\Store\RepositoryServiceContainerFactory; use Wikibase\Client\WikibaseClient; +use Wikibase\DataModel\Entity\BasicEntityIdParser; +use Wikibase\DataModel\Services\EntityId\PrefixMappingEntityIdParserFactory; use Wikibase\DataModel\Services\Term\TermBuffer; +use Wikibase\Lib\Serialization\RepositorySpecificDataValueDeserializerFactory; use Wikibase\Lib\Store\EntityRevisionLookup; use Wikibase\Lib\Store\PropertyInfoLookup; @@ -17,10 +21,27 @@ class DispatchingServiceWiringTest extends \PHPUnit_Framework_TestCase { /** + * @return RepositoryServiceContainerFactory + */ + private function getRepositoryServiceContainerFactory() { + $idParser = new PrefixMappingEntityIdParserFactory( + new BasicEntityIdParser(), [] + ); + + return new RepositoryServiceContainerFactory( + $idParser, + new RepositorySpecificDataValueDeserializerFactory( $idParser ), + [ '' => false ], + [ __DIR__ . '/../../../includes/Store/RepositoryServiceWiring.php' ], + WikibaseClient::getDefaultInstance() + ); + } + + /** * @return DispatchingServiceFactory */ private function getDispatchingServiceFactory() { - $factory = new DispatchingServiceFactory( WikibaseClient::getDefaultInstance() ); + $factory = new DispatchingServiceFactory( $this->getRepositoryServiceContainerFactory(), [ '' ] ); $factory->loadWiringFiles( [ __DIR__ . '/../../../includes/DispatchingServiceWiring.php' ] ); return $factory; } diff --git a/extensions/Wikibase/client/tests/phpunit/includes/Store/RepositoryServiceContainerFactoryTest.php b/extensions/Wikibase/client/tests/phpunit/includes/Store/RepositoryServiceContainerFactoryTest.php new file mode 100644 index 0000000..5aec4f6 --- /dev/null +++ b/extensions/Wikibase/client/tests/phpunit/includes/Store/RepositoryServiceContainerFactoryTest.php @@ -0,0 +1,63 @@ +<?php + +namespace Wikibase\Client\Tests\Store; + +use Wikibase\Client\Store\RepositoryServiceContainer; +use Wikibase\Client\Store\RepositoryServiceContainerFactory; +use Wikibase\Client\WikibaseClient; +use Wikibase\DataModel\Entity\ItemIdParser; +use Wikibase\DataModel\Services\EntityId\PrefixMappingEntityIdParserFactory; +use Wikibase\DataModel\Services\Lookup\UnknownForeignRepositoryException; +use Wikibase\Lib\Serialization\RepositorySpecificDataValueDeserializerFactory; + +/** + * @covers Wikibase\Client\Store\RepositoryServiceContainerFactory + * + * @group Wikibase + * @group WikibaseClient + * + * @license GPL-2.0+ + */ +class RepositoryServiceContainerFactoryTest extends \PHPUnit_Framework_TestCase { + + private function getRepositoryServiceContainerFactory() { + $idParserFactory = new PrefixMappingEntityIdParserFactory( + new ItemIdParser(), [] + ); + + return new RepositoryServiceContainerFactory( + $idParserFactory, + new RepositorySpecificDataValueDeserializerFactory( $idParserFactory ), + [ '' => false ], + [], + WikibaseClient::getDefaultInstance() + ); + } + + public function testGivenKnownRepository_newContainerReturnsContainerForThisRepository() { + $factory = $this->getRepositoryServiceContainerFactory(); + + $container = $factory->newContainer( '' ); + + $this->assertInstanceOf( RepositoryServiceContainer::class, $container ); + $this->assertSame( '', $container->getRepositoryName() ); + } + + public function testGivenUnknownRepository_newContainerThrowsException() { + $factory = $this->getRepositoryServiceContainerFactory(); + + $this->setExpectedException( UnknownForeignRepositoryException::class ); + + $factory->newContainer( 'foo' ); + } + + public function testNewContainerReturnsAFreshInstanceOnEachCall() { + $factory = $this->getRepositoryServiceContainerFactory(); + + $containerOne = $factory->newContainer( '' ); + $containerTwo = $factory->newContainer( '' ); + + $this->assertNotSame( $containerOne, $containerTwo ); + } + +} diff --git a/extensions/Wikibase/client/tests/phpunit/includes/Store/RepositoryServiceContainerTest.php b/extensions/Wikibase/client/tests/phpunit/includes/Store/RepositoryServiceContainerTest.php index 2673d1a..3f17bb2 100644 --- a/extensions/Wikibase/client/tests/phpunit/includes/Store/RepositoryServiceContainerTest.php +++ b/extensions/Wikibase/client/tests/phpunit/includes/Store/RepositoryServiceContainerTest.php @@ -5,13 +5,19 @@ use DataValues\Deserializers\DataValueDeserializer; use HashSiteStore; use Language; +use stdClass; use Wikibase\Client\Store\RepositoryServiceContainer; use Wikibase\Client\WikibaseClient; use Wikibase\DataModel\Entity\EntityIdParser; +use Wikibase\DataModel\Entity\EntityRedirect; +use Wikibase\DataModel\Entity\Item; +use Wikibase\DataModel\Entity\ItemId; use Wikibase\DataModel\Services\EntityId\PrefixMappingEntityIdParser; +use Wikibase\EntityRevision; use Wikibase\Lib\DataTypeDefinitions; use Wikibase\Lib\EntityTypeDefinitions; use Wikibase\Lib\Store\EntityRevisionLookup; +use Wikibase\Lib\Store\EntityStoreWatcher; use Wikibase\SettingsArray; /** @@ -45,23 +51,30 @@ /** * @return RepositoryServiceContainer */ - private function getRepositoryServiceContainer() { + private function newRepositoryServiceContainer() { /** @var EntityIdParser $idParser */ $idParser = $this->getMock( EntityIdParser::class ); - $services = new RepositoryServiceContainer( + return new RepositoryServiceContainer( 'foowiki', 'foo', new PrefixMappingEntityIdParser( [ '' => 'foo' ], $idParser ), new DataValueDeserializer( [] ), $this->getWikibaseClient() ); + } - $services->defineService( 'EntityRevisionLookup', function() { + /** + * @return RepositoryServiceContainer + */ + private function getRepositoryServiceContainer() { + $container = $this->newRepositoryServiceContainer(); + + $container->defineService( 'EntityRevisionLookup', function() { return $this->getMock( EntityRevisionLookup::class ); } ); - return $services; + return $container; } public function testGetService() { @@ -97,4 +110,69 @@ $this->assertEquals( 'foowiki', $repositoryServiceContainer->getDatabaseName() ); } + /** + * @param $event + * + * Returns a RepositoryServiceContainer with the following services defined: + * - 'watcherService' - dummy service implementing EntityStoreWatcher interface, + * - 'anotherWatcherService' - dummy service implementing EntityStoreWatcher interface, + * - 'unusedWatcherService' - dummy service implementing EntityStoreWatcher interface, + * - 'nonWatcherService' - dummy service not implementing EntityStoreWatcher interface, + * All services but 'unusedWatcherService' are initialized by default. + * This methods provides a set up for testing that RepositoryServiceContainer propagates entity change + * event to all of its watcher services but not to those that have not been used yet (in which case + * it makes no sense to pass the event to them). + * + * @return RepositoryServiceContainer + */ + private function getRepositoryServiceContainerForEventTest( $event ) { + $watcherService = $this->getMock( EntityStoreWatcher::class ); + $watcherService->expects( $this->atLeastOnce() )->method( $event ); + + $unusedWatcherService = $this->getMock( EntityStoreWatcher::class ); + $unusedWatcherService->expects( $this->never() )->method( $event ); + + $nonWatcherService = $this->getMock( stdClass::class ); + $nonWatcherService->expects( $this->never() )->method( $event ); + + $container = $this->newRepositoryServiceContainer(); + $container->defineService( 'watcherService', function () use ( $watcherService ) { + return $watcherService; + } ); + $container->defineService( 'anotherWatcherService', function () use ( $watcherService ) { + return $watcherService; + } ); + $container->defineService( 'unusedWatcherService', function () use ( $unusedWatcherService ) { + return $unusedWatcherService; + } ); + $container->defineService( 'nonWatcherService', function () use ( $nonWatcherService ) { + return $nonWatcherService; + } ); + + // Instantiate services relevant for the check + $container->getService( 'watcherService' ); + $container->getService( 'anotherWatcherService' ); + $container->getService( 'nonWatcherService' ); + + return $container; + } + + public function testEntityUpdatedDelegatesEventToAllWatchersThatHaveAlreadyBeenUsed() { + $container = $this->getRepositoryServiceContainerForEventTest( 'entityUpdated' ); + + $container->entityUpdated( new EntityRevision( new Item( new ItemId( 'foo:Q123' ) ) ) ); + } + + public function testEntityDeletedDelegatesEventToAllWatchersThatHaveAlreadyBeenUsed() { + $container = $this->getRepositoryServiceContainerForEventTest( 'entityDeleted' ); + + $container->entityDeleted( new ItemId( 'foo:Q123' ) ); + } + + public function testRedirectUpdatedDelegatesEventToAllWatchersThatHaveAlreadyBeenUsed() { + $container = $this->getRepositoryServiceContainerForEventTest( 'redirectUpdated' ); + + $container->redirectUpdated( new EntityRedirect( new ItemId( 'foo:Q123' ), new ItemId( 'foo:Q321' ) ), 100 ); + } + } diff --git a/extensions/Wikibase/client/tests/phpunit/includes/Store/Sql/DirectSqlStoreTest.php b/extensions/Wikibase/client/tests/phpunit/includes/Store/Sql/DirectSqlStoreTest.php index ef146e5..ec0b5a5 100644 --- a/extensions/Wikibase/client/tests/phpunit/includes/Store/Sql/DirectSqlStoreTest.php +++ b/extensions/Wikibase/client/tests/phpunit/includes/Store/Sql/DirectSqlStoreTest.php @@ -4,6 +4,7 @@ use Wikibase\Client\DispatchingServiceFactory; use Wikibase\Client\RecentChanges\RecentChangesDuplicateDetector; +use Wikibase\Client\Store\RepositoryServiceContainerFactory; use Wikibase\Client\Usage\SubscriptionManager; use Wikibase\Client\Usage\UsageLookup; use Wikibase\Client\Usage\UsageTracker; @@ -43,7 +44,13 @@ $client = WikibaseClient::getDefaultInstance(); - $dispatchingServiceFactory = new DispatchingServiceFactory( $client ); + /** @var RepositoryServiceContainerFactory $containerFactory */ + $containerFactory = $this->getMockBuilder( RepositoryServiceContainerFactory::class ) + ->disableOriginalConstructor() + ->getMock(); + + $dispatchingServiceFactory = new DispatchingServiceFactory( $containerFactory, [] ); + $dispatchingServiceFactory->defineService( 'EntityRevisionLookup', function() { return $this->getMock( EntityRevisionLookup::class ); } ); diff --git a/extensions/Wikibase/docs/change-op-serializations.wiki b/extensions/Wikibase/docs/change-op-serializations.wiki index 63d83a5..93d5205 100644 --- a/extensions/Wikibase/docs/change-op-serializations.wiki +++ b/extensions/Wikibase/docs/change-op-serializations.wiki @@ -36,19 +36,19 @@ ==== "labels" and "descriptions" ==== * To add or edit a label or description, simply provide it's "language" and "value". * There are two ways to remove a label or description: -** You can add the key "remove", e.g. <code>{ "language": "en", "remove": 1 }</code>. The content of the "remove" element can be whatever you want, typically 1. +** You can add the key "remove", e.g. <code>{ "language": "en", "remove": "" }</code>. The content of the "remove" element can be whatever you want, typically an empty string. ** You can set the "value" to an empty string, e.g. <code>{ "language": "en", "value": "" }</code>. ==== "aliases" ==== * You can either add or remove aliases individually, or send the full set of aliases for a language. -* To remove an alias, provide the old "language" and "value" of the alias you want to remove, as well as the key "remove", e.g. <code>{ "language": "en", "value": "…", "remove": 1 }</code>. The content of the "remove" element can be whatever you want, typically 1. -* To add an alias without touching the existing ones, provide a single alias and add the key "add", e.g. <code>{ "language": "en", "value": "…", "add": 1 }</code>. The content of the "add" element can be whatever you want, typically 1. +* To remove an alias, provide the old "language" and "value" of the alias you want to remove, as well as the key "remove", e.g. <code>{ "language": "en", "value": "…", "remove": "" }</code>. The content of the "remove" element can be whatever you want, typically an empty string. +* To add an alias without touching the existing ones, provide a single alias and add the key "add", e.g. <code>{ "language": "en", "value": "…", "add": "" }</code>. The content of the "add" element can be whatever you want, typically an empty string. === Statements ("claims") === Statements must be provided via the element key "claims". This is for compatibility with older versions of the Wikibase software. * To add a statement, provide a full statement serialization as supported by the StatementDeserializer in the [//github.com/wmde/WikibaseDataModelSerialization Wikibase DataModel Serialization component]. See docs/json.wiki. * To edit an existing statement, do as above and make sure to include the "id" of the existing statement. -* To remove a statement, you must provide it's "id" and the key "remove". The content of the "remove" element can be whatever you want, typically 1. +* To remove a statement, you must provide it's "id" and the key "remove". The content of the "remove" element can be whatever you want, typically an empty string. == Property specific elements == The only element specific for properties, their data type, can not be edited. @@ -60,7 +60,7 @@ * Editing the "site" ID of an existing sitelink is not possible. You must remove the old sitelink and add the new sitelink instead. * To edit the page name of an existing sitelink, provide the "site" ID with the new "title", e.g. <code>{ "site": "enwiki", "title": "…" }</code>. * There are three ways to remove a sitelink: -** You can add the key "remove". The "title" is optional in this case. The content of the "remove" element can be whatever you want, typically 1. +** You can add the key "remove". The "title" is optional in this case. The content of the "remove" element can be whatever you want, typically an empty string. ** You can provide a sitelink with no title and no badges, e.g. <code>{ "site": "enwiki" }</code>. ** You can set the "title" to an empty string, e.g. <code>{ "site": "enwiki", "title": "" }</code>. diff --git a/extensions/Wikibase/docs/extending-entities.wiki b/extensions/Wikibase/docs/extending-entities.wiki index 369e0bc..71b04fa 100644 --- a/extensions/Wikibase/docs/extending-entities.wiki +++ b/extensions/Wikibase/docs/extending-entities.wiki @@ -1,4 +1,5 @@ This is a checklist of things that need doing when adding a new field to an existing entity type. +For example if you want to add "NewThingy" part to entity type called "Foo": * Add a provider interface, such as NewThingyProvider, for the new field. * Add to entity as an attribute and add getter and setter (implement the provider interface) @@ -11,13 +12,14 @@ * Add support to FooPatcher * Add support to FooDiffer * Add support in FooView (extends EntityView) +* Add a ChangeOp for the new field, e.g. NewThingyChangeOp +* Add support in FooValidatorFactory +* Add support in FooChangeOpDeserializer -CAVEAT (as of November 2016): For the below parts of Wikibase, there are no extension +CAVEAT (as of January 2017): For the below parts of Wikibase, there are no extension interfaces yet for handling additional fields of entities. Fields of entity types known to Wikibase itself can be hardcoded here, but for supporting entity types defined in other extensions, plug-in interfaces still need to be added. * Add to RDF mapping (not currently pluggable!) -* Add Validator (not currently pluggable) -* Add ChangeOp for updating (not currently pluggable) (must work with wbeditentity) * Add handling (or suppression) to EntityChangeFactory (not currently pluggable) diff --git a/extensions/Wikibase/lib/WikibaseLib.php b/extensions/Wikibase/lib/WikibaseLib.php index 69853b9..7d00f27 100644 --- a/extensions/Wikibase/lib/WikibaseLib.php +++ b/extensions/Wikibase/lib/WikibaseLib.php @@ -61,7 +61,7 @@ 'name' => 'WikibaseLib', 'version' => WBL_VERSION, 'author' => array( - 'The Wikidata team', // TODO: link? + 'The Wikidata team', ), 'url' => 'https://www.mediawiki.org/wiki/Extension:WikibaseLib', 'descriptionmsg' => 'wikibase-lib-desc', diff --git a/extensions/Wikibase/lib/includes/Store/CacheAwarePropertyInfoStore.php b/extensions/Wikibase/lib/includes/Store/CacheAwarePropertyInfoStore.php index 7808d70..fbb946b 100644 --- a/extensions/Wikibase/lib/includes/Store/CacheAwarePropertyInfoStore.php +++ b/extensions/Wikibase/lib/includes/Store/CacheAwarePropertyInfoStore.php @@ -83,17 +83,10 @@ // update primary store $this->store->setPropertyInfo( $propertyId, $info ); - // NOTE: Even if we don't have the propertyInfo locally, we still need to - // fully load it to update memcached. - - // Get local cached version. - // NOTE: this may be stale at this point, if it was already loaded $propertyInfo = $this->cache->get( $this->cacheKey ); $id = $propertyId->getSerialization(); - // update local cache $propertyInfo[$id] = $info; - $this->propertyInfo = $propertyInfo; // update external cache wfDebugLog( __CLASS__, __FUNCTION__ . ': updating cache after updating property ' . $id ); @@ -118,14 +111,8 @@ return false; } - // NOTE: Even if we don't have the propertyInfo locally, we still need to - // fully load it to update memcached. - - // Get local cached version. - // NOTE: this may be stale at this point, if it was already loaded $propertyInfo = $this->cache->get( $this->cacheKey ); - // update local cache unset( $propertyInfo[$id] ); // update external cache diff --git a/extensions/Wikibase/lib/tests/phpunit/MockRepository.php b/extensions/Wikibase/lib/tests/phpunit/MockRepository.php index 94aefaf..09b4c22 100644 --- a/extensions/Wikibase/lib/tests/phpunit/MockRepository.php +++ b/extensions/Wikibase/lib/tests/phpunit/MockRepository.php @@ -20,7 +20,7 @@ use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookup; use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookupException; use Wikibase\DataModel\SiteLink; -use Wikibase\DataModel\Term\FingerprintProvider; +use Wikibase\DataModel\Term\LabelsProvider; use Wikibase\EntityRevision; use Wikibase\Lib\Store\EntityInfoBuilderFactory; use Wikibase\Lib\Store\EntityRevisionLookup; @@ -413,11 +413,11 @@ $property = $this->getEntity( $propertyId ); - if ( !( $property instanceof FingerprintProvider ) ) { + if ( !( $property instanceof LabelsProvider ) ) { continue; } - $labels = $property->getFingerprint()->getLabels(); + $labels = $property->getLabels(); if ( $labels->hasTermForLanguage( $languageCode ) && $labels->getByLanguage( $languageCode )->getText() === $propertyLabel diff --git a/extensions/Wikibase/lib/tests/phpunit/Store/EntityInfoBuilderTest.php b/extensions/Wikibase/lib/tests/phpunit/Store/EntityInfoBuilderTest.php index 9e3c5ad..ab77c08 100644 --- a/extensions/Wikibase/lib/tests/phpunit/Store/EntityInfoBuilderTest.php +++ b/extensions/Wikibase/lib/tests/phpunit/Store/EntityInfoBuilderTest.php @@ -2,7 +2,6 @@ namespace Wikibase\Lib\Tests\Store; -use Wikibase\DataModel\Entity\EntityDocument; use Wikibase\DataModel\Entity\EntityId; use Wikibase\DataModel\Entity\Item; use Wikibase\DataModel\Entity\ItemId; @@ -31,7 +30,7 @@ } /** - * @return EntityDocument[] + * @return Item[]|Property[] */ protected function getKnownEntities() { $q1 = new Item( new ItemId( 'Q1' ) ); diff --git a/extensions/Wikibase/lib/tests/phpunit/Store/Sql/SqlEntityInfoBuilderTest.php b/extensions/Wikibase/lib/tests/phpunit/Store/Sql/SqlEntityInfoBuilderTest.php index 58bbf0b..d2ce9ea 100644 --- a/extensions/Wikibase/lib/tests/phpunit/Store/Sql/SqlEntityInfoBuilderTest.php +++ b/extensions/Wikibase/lib/tests/phpunit/Store/Sql/SqlEntityInfoBuilderTest.php @@ -35,59 +35,68 @@ $this->tablesUsed[] = 'wb_terms'; $this->tablesUsed[] = 'wb_entity_per_page'; - $termRows = array(); - $infoRows = array(); - $eppRows = array(); + $termRows = []; + $infoRows = []; + $eppRows = []; $pageId = 1000; foreach ( $this->getKnownEntities() as $entity ) { - $eppRows[] = array( + $id = $entity->getId(); + + $eppRows[] = [ $entity->getType(), - $entity->getId()->getNumericId(), + $id->getNumericId(), $pageId++, null - ); + ]; - $labels = $entity->getFingerprint()->getLabels()->toTextArray(); - $descriptions = $entity->getFingerprint()->getDescriptions()->toTextArray(); - $aliases = $entity->getFingerprint()->getAliasGroups()->toTextArray(); + $labels = $entity->getLabels()->toTextArray(); + $descriptions = $entity->getDescriptions()->toTextArray(); + $aliases = $entity->getAliasGroups()->toTextArray(); - $termRows = array_merge( $termRows, $this->getTermRows( $entity->getId(), 'label', $labels ) ); - $termRows = array_merge( $termRows, $this->getTermRows( $entity->getId(), 'description', $descriptions ) ); - $termRows = array_merge( $termRows, $this->getTermRows( $entity->getId(), 'alias', $aliases ) ); + $termRows = array_merge( $termRows, $this->getTermRows( $id, 'label', $labels ) ); + $termRows = array_merge( $termRows, $this->getTermRows( $id, 'description', $descriptions ) ); + $termRows = array_merge( $termRows, $this->getTermRows( $id, 'alias', $aliases ) ); if ( $entity instanceof Property ) { - $infoRows[] = array( - $entity->getId()->getNumericId(), + $infoRows[] = [ + $id->getNumericId(), $entity->getDataTypeId(), '{"type":"' . $entity->getDataTypeId() . '"}' - ); + ]; } } foreach ( $this->getKnownRedirects() as $from => $toId ) { $fromId = new ItemId( $from ); - $eppRows[] = array( + $eppRows[] = [ $fromId->getEntityType(), $fromId->getNumericId(), $pageId++, $toId->getSerialization() - ); + ]; } $this->insertRows( 'wb_terms', - array( 'term_entity_type', 'term_entity_id', 'term_type', 'term_language', 'term_text', 'term_search_key' ), + [ + 'term_entity_type', + 'term_entity_id', + 'term_type', + 'term_language', + 'term_text', + 'term_search_key' + ], $termRows ); $this->insertRows( 'wb_property_info', - array( 'pi_property_id', 'pi_type', 'pi_info' ), + [ 'pi_property_id', 'pi_type', 'pi_info' ], $infoRows ); - $eppColumns = array( 'epp_entity_type', 'epp_entity_id', 'epp_page_id', 'epp_redirect_target' ); + $eppColumns = [ 'epp_entity_type', 'epp_entity_id', 'epp_page_id', 'epp_redirect_target' ]; $this->insertRows( 'wb_entity_per_page', @@ -96,19 +105,20 @@ } private function getTermRows( EntityId $id, $termType, $terms ) { - $rows = array(); + $rows = []; foreach ( $terms as $lang => $langTerms ) { $langTerms = (array)$langTerms; foreach ( $langTerms as $term ) { - $rows[] = array( + $rows[] = [ $id->getEntityType(), $id->getNumericId(), $termType, $lang, $term, - $term ); + $term + ]; } } @@ -128,7 +138,7 @@ // Just ignore insertation errors... if similar data already is in the DB // it's probably good enough for the tests (as this is only testing for UNIQUE // fields anyway). - array( 'IGNORE' ) + [ 'IGNORE' ] ); } } diff --git a/extensions/Wikibase/repo/Wikibase.php b/extensions/Wikibase/repo/Wikibase.php index 4c42317..08c4182 100644 --- a/extensions/Wikibase/repo/Wikibase.php +++ b/extensions/Wikibase/repo/Wikibase.php @@ -239,7 +239,24 @@ $wgAPIModules['wbsetqualifier'] = Wikibase\Repo\Api\SetQualifier::class; $wgAPIModules['wbmergeitems'] = Wikibase\Repo\Api\MergeItems::class; $wgAPIModules['wbformatvalue'] = Wikibase\Repo\Api\FormatSnakValue::class; - $wgAPIModules['wbparsevalue'] = Wikibase\Repo\Api\ParseValue::class; + $wgAPIModules['wbparsevalue'] = [ + 'class' => Wikibase\Repo\Api\ParseValue::class, + 'factory' => function( ApiMain $mainModule, $moduleName ) { + $wikibaseRepo = Wikibase\Repo\WikibaseRepo::getDefaultInstance(); + $apiHelperFactory = $wikibaseRepo->getApiHelperFactory( $mainModule->getContext() ); + + return new Wikibase\Repo\Api\ParseValue( + $mainModule, + $moduleName, + $wikibaseRepo->getDataTypeFactory(), + $wikibaseRepo->getValueParserFactory(), + $wikibaseRepo->getDataTypeValidatorFactory(), + $wikibaseRepo->getExceptionLocalizer(), + $wikibaseRepo->getValidatorErrorLocalizer(), + $apiHelperFactory->getErrorReporter( $mainModule ) + ); + } + ]; $wgAPIModules['wbavailablebadges'] = Wikibase\Repo\Api\AvailableBadges::class; $wgAPIModules['wbcreateredirect'] = [ 'class' => Wikibase\Repo\Api\CreateRedirect::class, diff --git a/extensions/Wikibase/repo/i18n/bn.json b/extensions/Wikibase/repo/i18n/bn.json index 4b2f148..5de27b1 100644 --- a/extensions/Wikibase/repo/i18n/bn.json +++ b/extensions/Wikibase/repo/i18n/bn.json @@ -5,7 +5,8 @@ "Bellayet", "Leemon2010", "Aftabuzzaman", - "Nasir8891" + "Nasir8891", + "Elias Ahmmad" ] }, "wikibase-desc": "কাঠামোবদ্ধ তথ্য ভান্ডার", @@ -243,6 +244,7 @@ "wikibase-entitydata-bad-id": "অবৈধ আইডি: $1।", "wikibase-entitydata-storage-error": "$1 সত্তা লোড করতে ব্যর্থ।", "wikibase-entitydata-title": "সত্তার উপাত্ত", + "special-entitypage": "সত্তা পাতা", "special-redirectentity": "একটি সত্তা পুনঃনির্দেশ করুন", "wikibase-redirectentity-success": "$1 $2-এর দিকে পুনঃনির্দেশিত হয়েছে।", "wikibase-redirectentity-submit": "পুনঃনির্দেশ", diff --git a/extensions/Wikibase/repo/i18n/de.json b/extensions/Wikibase/repo/i18n/de.json index 2d3a288..e7b227c 100644 --- a/extensions/Wikibase/repo/i18n/de.json +++ b/extensions/Wikibase/repo/i18n/de.json @@ -307,6 +307,7 @@ "wikibase-entitydata-storage-error": "Das Objekt $1 konnte nicht geladen werden.", "wikibase-entitydata-title": "Objektdaten", "wikibase-entitydata-text": "Diese Seite liefert eine verlinkte Datenschnittstelle zu Objektwerten. Bitte gib die Objektkennung in der URL an, indem du Unterseitensyntax verwendest.\n* Inhaltsvereinbarungsanfragen basierend auf deinem Client-Accept-Header. Das bedeutet, dass die Objektdaten im Format angegeben wird, das von deinem Client bevorzugt wird. Für einen Webbrowser wird dies HTML sein, was bewirkt, dass dein Browser zur normalen Objektseite weiterleitet.\n* Du kannst ein spezielles Datenformat ausdrücklich durch das Hinzufügen der passenden Dateierweiterung zur Objektkennung anfordern: Q23.json gibt Daten im JSON-Format zurück, Q23.ttl gibt RDF/Turtle zurück und so weiter.", + "special-entitypage": "Objektseite", "wikibase-entitypage-title": "Objektseite", "wikibase-entitypage-text": "Diese Seite leitet auf die Objektseite auf dem Repositorium weiter, zu der sie gehört. Bitte gib mithilfe der Unterseitensyntax die Objektkennung in der URL an.", "wikibase-entitypage-bad-id": "Ungültige Kennung: $1.", diff --git a/extensions/Wikibase/repo/i18n/es.json b/extensions/Wikibase/repo/i18n/es.json index b5b4b84..c8b36b8 100644 --- a/extensions/Wikibase/repo/i18n/es.json +++ b/extensions/Wikibase/repo/i18n/es.json @@ -393,6 +393,7 @@ "apihelp-wbformatvalue-param-datatype": "El tipo de dato del valor. Esto es distinto del tipo del valor", "apihelp-wbformatvalue-param-property": "ID de la propiedad el valor de los datos pertenece, debe ser usado en lugar del tipo de datos del parámetro.", "apihelp-wbgetentities-description": "Obtiene los datos de múltiples entidades de Wikibase.", + "apihelp-wbgetentities-param-ids": "Los identificadores de las entidades de las que obtener los datos", "apihelp-wbgetentities-param-languages": "Por defecto, los valores internacionalizados se devuelven en todos los idiomas disponibles. Este parámetro permite filtrarlos a uno o más idiomas. Para ello, hay que introducir los códigos de idioma correspondientes.", "apihelp-wbgetentities-param-languagefallback": "Aplicar idioma de reserva para los idiomas definidos en el parámetro <var>languages</var>, en el contexto actual de la llamada a la API.", "apihelp-wbgetentities-param-normalize": "Tratar de normalizar el título de la página en función del sitio en el que se encuentra.\nEsto solo funciona si se proporciona exactamente un sitio y una página.", @@ -423,10 +424,18 @@ "apihelp-wbparsevalue-param-values": "Los valores que analizar", "apihelp-wbparsevalue-param-options": "Opciones que el analizador debe usar. Se proporciona como un objeto JSON.", "apihelp-wbparsevalue-example-1": "Analizar una cadena sin formato en un objeto StringValue.", + "apihelp-wbremoveclaims-param-baserevid": "El identificador numérico de la revisión en la que basar la modificación.\nEste dato se utiliza para detectar conflictos al guardar.", + "apihelp-wbremoveclaims-param-bot": "Marca esta edición como realizada por un bot. Esta marca de URL solo se respetará si el usuario pertenece al grupo \"bot\".", "apihelp-wbremovequalifiers-description": "Elimina un calificador de una reclamación.", + "apihelp-wbremovequalifiers-param-baserevid": "El identificador numérico de la revisión en la que basar la modificación.\nEste dato se utiliza para detectar conflictos al guardar.", + "apihelp-wbremovequalifiers-param-bot": "Marca esta edición como realizada por un bot. Esta marca de URL solo se respetará si el usuario pertenece al grupo \"bot\".", + "apihelp-wbremovereferences-param-baserevid": "El identificador numérico de la revisión en la que basar la modificación.\nEste dato se utiliza para detectar conflictos al guardar.", + "apihelp-wbremovereferences-param-bot": "Marca esta edición como realizada por un bot. Esta marca de URL solo se respetará si el usuario pertenece al grupo \"bot\".", + "apihelp-wbremovereferences-param-summary": "Resumen de la edición.\nSerá precedido por un comentario generado automáticamente. La longitud máxima del autocomentario junto con el resumen es de 260 caracteres. Ten en cuenta que todo lo que sobrepase el límite se cortará.", "apihelp-wbsearchentities-description": "Busca entidades que usen etiquetas y alias.\nDevuelve una etiqueta y una descripción de la entidad en el idioma del usuario, si es posible.\nDevuelve detalles del término coincidente.\nEl texto del término coincidente también está presente en la clave de alias si es diferente de la etiqueta de visualización.", "apihelp-wbsearchentities-param-search": "Buscar este texto.", "apihelp-wbsearchentities-param-language": "Buscar en este idioma.", + "apihelp-wbsearchentities-param-strictlanguage": "Indica si se deshabilita el idioma de reserva.", "apihelp-wbsearchentities-param-type": "Buscar este tipo de entidad.", "apihelp-wbsearchentities-param-limit": "Número máximo de resultados", "apihelp-wbsearchentities-param-continue": "Desplazamiento desde donde continuar una búsqueda", @@ -436,6 +445,7 @@ "apihelp-query+wbsearch-description": "Busca entidades que usan etiquetas y alias.\nEsto se puede utilizar como generador de otras consultas.\nDevuelve el término encontrado que debe mostrarse.", "apihelp-query+wbsearch-param-search": "Buscar este texto.", "apihelp-query+wbsearch-param-language": "Buscar en este idioma.", + "apihelp-query+wbsearch-param-strictlanguage": "Indica si se deshabilita el idioma de reserva.", "apihelp-query+wbsearch-param-type": "Buscar este tipo de entidad.", "apihelp-query+wbsearch-param-limit": "Número máximo de resultados", "apihelp-query+wbsearch-example-2": "Buscar \"abc\" en el idioma inglés con un límite de 50", @@ -445,6 +455,8 @@ "apihelp-query+wbsubscribers-param-limit": "Número máximo de resultados", "apihelp-wbsetaliases-description": "Establece los alias de una entidad de Wikibase.", "apihelp-wbsetaliases-param-new": "Si se establece, se creará una entidad nueva.\nEstablece esto al tipo de entidad que quieres crear.", + "apihelp-wbsetaliases-param-baserevid": "El identificador numérico de la revisión en la que basar la modificación.\nEste dato se utiliza para detectar conflictos al guardar.", + "apihelp-wbsetaliases-param-summary": "Resumen de la edición.\nSerá precedido por un comentario generado automáticamente. La longitud máxima del autocomentario junto con el resumen es de 260 caracteres. Ten en cuenta que todo lo que sobrepase el límite se cortará.", "apihelp-wbsetaliases-param-bot": "Marcar esta edición como hecha por un robot. Este parámetro funcionará solo si el usuario pertenece al grupo «bot».", "apihelp-wbsetaliases-param-add": "Lista de alias que añadir (se puede combinar con <var>remove</var>)", "apihelp-wbsetaliases-param-remove": "Lista de alias que eliminar (se puede combinar con <var>add</var>)", @@ -455,21 +467,35 @@ "apihelp-wbsetaliases-example-3": "Eliminar Foo y Bar de la lista de alias en inglés para la entidad con el identificador Q1", "apihelp-wbsetaliases-example-4": "Eliminar Foo de la lista de alias en inglés para la entidad con el identificador Q1, y añadirle Bar", "apihelp-wbsetclaim-description": "Crea o actualiza toda una Declaración o Reclamación.", + "apihelp-wbsetclaim-param-summary": "Resumen de la edición.\nSerá precedido por un comentario generado automáticamente. La longitud máxima del autocomentario junto con el resumen es de 260 caracteres. Ten en cuenta que todo lo que sobrepase el límite se cortará.", + "apihelp-wbsetclaim-param-baserevid": "El identificador numérico de la revisión en la que basar la modificación.\nEste dato se utiliza para detectar conflictos al guardar.", "apihelp-wbsetclaim-param-bot": "Marcar esta edición como hecha por un robot. Este parámetro funcionará solo si el usuario pertenece al grupo «bot».", + "apihelp-wbsetclaimvalue-param-summary": "Resumen de la edición.\nSerá precedido por un comentario generado automáticamente. La longitud máxima del autocomentario junto con el resumen es de 260 caracteres. Ten en cuenta que todo lo que sobrepase el límite se cortará.", + "apihelp-wbsetclaimvalue-param-baserevid": "El identificador numérico de la revisión en la que basar la modificación.\nEste dato se utiliza para detectar conflictos al guardar.", "apihelp-wbsetclaimvalue-param-bot": "Marcar esta edición como hecha por un robot. Este parámetro funcionará solo si el usuario pertenece al grupo «bot».", "apihelp-wbsetdescription-param-new": "Si se establece, se creará una entidad nueva.\nEstablece esto al tipo de entidad que quieres crear.", + "apihelp-wbsetdescription-param-baserevid": "El identificador numérico de la revisión en la que basar la modificación.\nEste dato se utiliza para detectar conflictos al guardar.", + "apihelp-wbsetdescription-param-summary": "Resumen de la edición.\nSerá precedido por un comentario generado automáticamente. La longitud máxima del autocomentario junto con el resumen es de 260 caracteres. Ten en cuenta que todo lo que sobrepase el límite se cortará.", "apihelp-wbsetdescription-param-bot": "Marcar esta edición como hecha por un robot. Este parámetro funcionará solo si el usuario pertenece al grupo «bot».", "apihelp-wbsetdescription-param-language": "Idioma de la descripción", "apihelp-wbsetdescription-param-value": "El valor que establecer como descripción", "apihelp-wbsetlabel-param-new": "Si se establece, se creará una entidad nueva.\nEstablece esto al tipo de entidad que quieres crear.", + "apihelp-wbsetlabel-param-baserevid": "El identificador numérico de la revisión en la que basar la modificación.\nEste dato se utiliza para detectar conflictos al guardar.", + "apihelp-wbsetlabel-param-summary": "Resumen de la edición.\nSerá precedido por un comentario generado automáticamente. La longitud máxima del autocomentario junto con el resumen es de 260 caracteres. Ten en cuenta que todo lo que sobrepase el límite se cortará.", "apihelp-wbsetlabel-param-bot": "Marcar esta edición como hecha por un robot. Este parámetro funcionará solo si el usuario pertenece al grupo «bot».", "apihelp-wbsetlabel-param-language": "Idioma de la etiqueta", "apihelp-wbsetlabel-param-value": "El valor de la etiqueta", + "apihelp-wbsetqualifier-param-summary": "Resumen de la edición.\nSerá precedido por un comentario generado automáticamente. La longitud máxima del autocomentario junto con el resumen es de 260 caracteres. Ten en cuenta que todo lo que sobrepase el límite se cortará.", + "apihelp-wbsetqualifier-param-baserevid": "El identificador numérico de la revisión en la que basar la modificación.\nEste dato se utiliza para detectar conflictos al guardar.", "apihelp-wbsetqualifier-param-bot": "Marcar esta edición como hecha por un robot. Este parámetro funcionará solo si el usuario pertenece al grupo «bot».", "apihelp-wbsetreference-description": "Crea una referencia o establece el valor de una referencia existente.", "apihelp-wbsetreference-param-statement": "Un GUID que identifica la declaración para la cual se está estableciendo una referencia", + "apihelp-wbsetreference-param-summary": "Resumen de la edición.\nSerá precedido por un comentario generado automáticamente. La longitud máxima del autocomentario junto con el resumen es de 260 caracteres. Ten en cuenta que todo lo que sobrepase el límite se cortará.", + "apihelp-wbsetreference-param-baserevid": "El identificador numérico de la revisión en la que basar la modificación.\nEste dato se utiliza para detectar conflictos al guardar.", "apihelp-wbsetreference-param-bot": "Marcar esta edición como hecha por un robot. Este parámetro funcionará solo si el usuario pertenece al grupo «bot».", "apihelp-wbsetsitelink-param-new": "Si se establece, se creará una entidad nueva.\nEstablece esto al tipo de entidad que quieres crear.", + "apihelp-wbsetsitelink-param-baserevid": "El identificador numérico de la revisión en la que basar la modificación.\nEste dato se utiliza para detectar conflictos al guardar.", + "apihelp-wbsetsitelink-param-summary": "Resumen de la edición.\nSerá precedido por un comentario generado automáticamente. La longitud máxima del autocomentario junto con el resumen es de 260 caracteres. Ten en cuenta que todo lo que sobrepase el límite se cortará.", "apihelp-wbsetsitelink-param-bot": "Marcar esta edición como hecha por un robot. Este parámetro funcionará solo si el usuario pertenece al grupo «bot».", "apihelp-wbsetsitelink-param-linktitle": "El título del artículo que se enlazará. Si este parámetro es una cadena vacía o no se establecen ni el título del enlace ni las insignias , el enlace se eliminará.", "apihelp-wbsetsitelink-param-badges": "Los identificadores de los elementos que se establecerán como insignias. Reemplazarán a los actuales. Si este parámetro no está definido, las insignias no se cambiarán", diff --git a/extensions/Wikibase/repo/i18n/ml.json b/extensions/Wikibase/repo/i18n/ml.json index 199e2fa..fe13cb2 100644 --- a/extensions/Wikibase/repo/i18n/ml.json +++ b/extensions/Wikibase/repo/i18n/ml.json @@ -6,7 +6,8 @@ "Praveenp", "Santhosh.thottingal", "Vssun", - "Macofe" + "Macofe", + "Jameela P." ] }, "wikibase-desc": "വിന്യസിത ഡേറ്റാ റെപ്പോസിറ്ററി", @@ -33,6 +34,7 @@ "wikibase-description-empty": "വിവരണമൊന്നും നിർവചിച്ചിട്ടില്ല", "wikibase-description-edit-placeholder": "വിവരണം നൽകുക", "wikibase-description-edit-placeholder-language-aware": "$1 ഭാഷയിൽ വിവരണം നൽകുക", + "wikibase-content-language-edit-label": "ഭാഷ:", "wikibase-diffview-reference": "അവലംബം", "wikibase-diffview-rank": "റാങ്ക്", "wikibase-diffview-rank-preferred": "ഉദ്ദേശിക്കുന്ന റാങ്ക്", @@ -43,6 +45,7 @@ "wikibase-diffview-alias": "അപരനാമങ്ങൾ", "wikibase-diffview-description": "വിവരണം", "wikibase-diffview-link": "കണ്ണികൾ", + "wikibase-diffview-link-name": "പേര്", "wikibase-sitelink-site-edit-placeholder": "സൈറ്റ്", "wikibase-sitelink-page-edit-placeholder": "താൾ", "wikibase-alias-edit-placeholder": "ഒരു അപരനാമം നൽകുക", @@ -69,7 +72,6 @@ "wikibase-disambiguation-title": "\"$1\" എന്നതിനുള്ള വിവക്ഷകൾ", "wb-special-newitem-new-item-notification": "പുതിയ ഇനം $1 സൃഷ്ടിക്കപ്പെട്ടു, അതിന്റെ താളിലേയ്ക്ക് തിരിച്ചുവിടപ്പെട്ടു. $2 എന്നതിലേക്ക് മടങ്ങുക.", "wikibase-aliases-input-help-message": "ഈ ഡേറ്റാ ഗണം ഒന്നിലധികം പേരുകളിൽ അറിയപ്പെടുന്നുണ്ടെങ്കിൽ, താങ്കൾക്കവ ഇവിടെ പര്യായങ്ങളായോ അപരനാമങ്ങളായോ ചേർക്കാവുന്നതാണ്, അങ്ങനെ ചെയ്യുമ്പോൾ അവയുടെ ഇതരനാമങ്ങൾ ഉപയോഗിച്ചും അവ കണ്ടെത്താനാവും.", - "wikibase-aliases-empty": "അപരനാമങ്ങളൊന്നും കണ്ടെത്താനായില്ല.", "wikibase-propertypage-datatype": "ഡേറ്റാ തരം", "wikibase-statementview-rank-normal": "സാധാരണ റാങ്ക്", "wikibase-statementview-references-counter": "$1{{PLURAL:$2|0=|$3+$2$4}} {{PLURAL:$1|സ്രോതസ്സ്|സ്രോതസ്സുകൾ}}", @@ -139,6 +141,7 @@ "wikibase-entitieswithoutlabel-label-alltypes": "എല്ലാം", "wikibase-entitieswithoutlabel-submit": "കണ്ടെത്തുക", "wikibase-entitieswithoutlabel-invalid-language": "\"$1\" എന്നത് സാധുവായ ഭാഷാ കോഡ് അല്ല.", + "wikibase-entitypage-bad-id": "അസാധുവായ ഉപയോക്തൃനാമം: $1", "wikibase-restoreold": "പുനഃസ്ഥാപിക്കുക", "wikibase-no-direct-editing": "$1 എന്ന നാമമേഖലയിൽ നേരിട്ടുള്ള തിരുത്ത് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു", "wikibase-noentity-createone": "ഒപ്പം താങ്കൾക്ക് [[$1|പുതിയൊരെണ്ണം സൃഷ്ടിക്കാവുന്നതുമാണ്]].", diff --git a/extensions/Wikibase/repo/i18n/my.json b/extensions/Wikibase/repo/i18n/my.json index 0b5885a..136d0d9 100644 --- a/extensions/Wikibase/repo/i18n/my.json +++ b/extensions/Wikibase/repo/i18n/my.json @@ -7,6 +7,7 @@ }, "wikibase-edit": "တည်းဖြတ်", "wikibase-add": "ပေါင်းထည့်", + "wikibase-label-empty": "နာမည်ညွှန်း မပေးထားပါ", "wikibase-description-empty": "ဖော်ပြချက် ပေးမထားပါ", "wikibase-sitelink-page-edit-placeholder": "စာမျက်နှာ", "wikibase-sitelinks-special": "အခြား ဆိုဒ်များ", diff --git a/extensions/Wikibase/repo/includes/Api/ParseValue.php b/extensions/Wikibase/repo/includes/Api/ParseValue.php index 8524e92..37fea83 100644 --- a/extensions/Wikibase/repo/includes/Api/ParseValue.php +++ b/extensions/Wikibase/repo/includes/Api/ParseValue.php @@ -65,29 +65,20 @@ private $errorReporter; /** + * @see ApiBase::__construct + * * @param ApiMain $mainModule * @param string $moduleName - * @param string $modulePrefix - * - * @see ApiBase::__construct + * @param DataTypeFactory $dataTypeFactory + * @param ValueParserFactory $valueParserFactory + * @param DataTypeValidatorFactory $dataTypeValidatorFactory + * @param ExceptionLocalizer $exceptionLocalizer + * @param ValidatorErrorLocalizer $validatorErrorLocalizer + * @param ApiErrorReporter $errorReporter */ - public function __construct( ApiMain $mainModule, $moduleName, $modulePrefix = '' ) { - parent::__construct( $mainModule, $moduleName, $modulePrefix ); - - $wikibaseRepo = WikibaseRepo::getDefaultInstance(); - $apiHelperFactory = $wikibaseRepo->getApiHelperFactory( $this->getContext() ); - - $this->setServices( - $wikibaseRepo->getDataTypeFactory(), - $wikibaseRepo->getValueParserFactory(), - $wikibaseRepo->getDataTypeValidatorFactory(), - $wikibaseRepo->getExceptionLocalizer(), - $wikibaseRepo->getValidatorErrorLocalizer(), - $apiHelperFactory->getErrorReporter( $this ) - ); - } - - public function setServices( + public function __construct( + ApiMain $mainModule, + $moduleName, DataTypeFactory $dataTypeFactory, ValueParserFactory $valueParserFactory, DataTypeValidatorFactory $dataTypeValidatorFactory, @@ -95,6 +86,7 @@ ValidatorErrorLocalizer $validatorErrorLocalizer, ApiErrorReporter $errorReporter ) { + parent::__construct( $mainModule, $moduleName ); $this->dataTypeFactory = $dataTypeFactory; $this->valueParserFactory = $valueParserFactory; $this->dataTypeValidatorFactory = $dataTypeValidatorFactory; diff --git a/extensions/Wikibase/repo/includes/Content/EntityContent.php b/extensions/Wikibase/repo/includes/Content/EntityContent.php index 7dd54b1..4df825b 100644 --- a/extensions/Wikibase/repo/includes/Content/EntityContent.php +++ b/extensions/Wikibase/repo/includes/Content/EntityContent.php @@ -26,6 +26,7 @@ use Wikibase\DataModel\Entity\EntityDocument; use Wikibase\DataModel\Entity\EntityId; use Wikibase\DataModel\Entity\EntityRedirect; +use Wikibase\DataModel\Term\DescriptionsProvider; use Wikibase\DataModel\Term\FingerprintProvider; use Wikibase\Repo\Content\EntityContentDiff; use Wikibase\Repo\Content\EntityHandler; @@ -412,13 +413,12 @@ global $wgLang; $entity = $this->getEntity(); - // TODO use DescriptionProvider - if ( $entity instanceof FingerprintProvider ) { - $fingerprint = $entity->getFingerprint(); + if ( $entity instanceof DescriptionsProvider ) { + $descriptions = $entity->getDescriptions(); $languageCode = $wgLang->getCode(); - if ( $fingerprint->hasDescription( $languageCode ) ) { - $description = $fingerprint->getDescription( $languageCode )->getText(); + if ( $descriptions->hasTermForLanguage( $languageCode ) ) { + $description = $descriptions->getByLanguage( $languageCode )->getText(); return substr( $description, 0, $maxLength ); } } diff --git a/extensions/Wikibase/repo/includes/Search/Elastic/Fields/LabelCountField.php b/extensions/Wikibase/repo/includes/Search/Elastic/Fields/LabelCountField.php index 3ad28b3..12f8879 100644 --- a/extensions/Wikibase/repo/includes/Search/Elastic/Fields/LabelCountField.php +++ b/extensions/Wikibase/repo/includes/Search/Elastic/Fields/LabelCountField.php @@ -3,7 +3,7 @@ namespace Wikibase\Repo\Search\Elastic\Fields; use Wikibase\DataModel\Entity\EntityDocument; -use Wikibase\DataModel\Term\FingerprintProvider; +use Wikibase\DataModel\Term\LabelsProvider; /** * @license GPL-2.0+ @@ -30,8 +30,8 @@ * @return int */ public function getFieldData( EntityDocument $entity ) { - if ( $entity instanceof FingerprintProvider ) { - return $entity->getFingerprint()->getLabels()->count(); + if ( $entity instanceof LabelsProvider ) { + return $entity->getLabels()->count(); } return 0; diff --git a/extensions/Wikibase/repo/includes/Validators/LabelDescriptionUniquenessValidator.php b/extensions/Wikibase/repo/includes/Validators/LabelDescriptionUniquenessValidator.php index 3907974..2c930ef 100644 --- a/extensions/Wikibase/repo/includes/Validators/LabelDescriptionUniquenessValidator.php +++ b/extensions/Wikibase/repo/includes/Validators/LabelDescriptionUniquenessValidator.php @@ -5,8 +5,9 @@ use ValueValidators\Result; use Wikibase\DataModel\Entity\EntityDocument; use Wikibase\DataModel\Entity\EntityId; +use Wikibase\DataModel\Term\DescriptionsProvider; use Wikibase\DataModel\Term\Fingerprint; -use Wikibase\DataModel\Term\FingerprintProvider; +use Wikibase\DataModel\Term\LabelsProvider; use Wikibase\LabelDescriptionDuplicateDetector; /** @@ -39,11 +40,11 @@ * @return Result */ public function validateEntity( EntityDocument $entity ) { - if ( $entity instanceof FingerprintProvider ) { + if ( $entity instanceof LabelsProvider && $entity instanceof DescriptionsProvider ) { return $this->duplicateDetector->detectLabelDescriptionConflicts( $entity->getType(), - $entity->getFingerprint()->getLabels()->toTextArray(), - $entity->getFingerprint()->getDescriptions()->toTextArray(), + $entity->getLabels()->toTextArray(), + $entity->getDescriptions()->toTextArray(), $entity->getId() ); } diff --git a/extensions/Wikibase/repo/includes/Validators/LabelUniquenessValidator.php b/extensions/Wikibase/repo/includes/Validators/LabelUniquenessValidator.php index 437bed3..8bb2ffc 100644 --- a/extensions/Wikibase/repo/includes/Validators/LabelUniquenessValidator.php +++ b/extensions/Wikibase/repo/includes/Validators/LabelUniquenessValidator.php @@ -6,7 +6,7 @@ use Wikibase\DataModel\Entity\EntityDocument; use Wikibase\DataModel\Entity\EntityId; use Wikibase\DataModel\Term\Fingerprint; -use Wikibase\DataModel\Term\FingerprintProvider; +use Wikibase\DataModel\Term\LabelsProvider; use Wikibase\LabelDescriptionDuplicateDetector; /** @@ -38,10 +38,10 @@ * @return Result */ public function validateEntity( EntityDocument $entity ) { - if ( $entity instanceof FingerprintProvider ) { + if ( $entity instanceof LabelsProvider ) { return $this->duplicateDetector->detectLabelConflicts( $entity->getType(), - $entity->getFingerprint()->getLabels()->toTextArray(), + $entity->getLabels()->toTextArray(), // insert again when T104393 is resolved null, //$entity->getFingerprint()->getAliasGroups()->toTextArray(), $entity->getId() diff --git a/extensions/Wikibase/repo/tests/phpunit/includes/Api/ParseValueTest.php b/extensions/Wikibase/repo/tests/phpunit/includes/Api/ParseValueTest.php index 8b97373..ce7b3cb 100644 --- a/extensions/Wikibase/repo/tests/phpunit/includes/Api/ParseValueTest.php +++ b/extensions/Wikibase/repo/tests/phpunit/includes/Api/ParseValueTest.php @@ -40,14 +40,12 @@ $request = new FauxRequest( $params, true ); $main = new ApiMain( $request ); - $module = new ParseValue( $main, 'wbparsevalue' ); - $wikibaseRepo = WikibaseRepo::getDefaultInstance(); $exceptionLocalizer = $wikibaseRepo->getExceptionLocalizer(); $validatorErrorLocalizer = $wikibaseRepo->getValidatorErrorLocalizer(); $errorReporter = new ApiErrorReporter( - $module, + $main, $exceptionLocalizer, Language::factory( 'qqq' ) ); @@ -70,7 +68,9 @@ 'url' => array( $this, 'newArrayWithStringValidator' ), ) ); - $module->setServices( + return new ParseValue( + $main, + 'wbparsevalue', $dataTypeFactory, $valueParserFactory, $validatorFactory, @@ -78,8 +78,6 @@ $validatorErrorLocalizer, $errorReporter ); - - return $module; } public function newArrayWithStringValidator() { diff --git a/extensions/Wikibase/repo/tests/phpunit/includes/Api/StatementModificationHelperTest.php b/extensions/Wikibase/repo/tests/phpunit/includes/Api/StatementModificationHelperTest.php index fa3f268..088ace9 100644 --- a/extensions/Wikibase/repo/tests/phpunit/includes/Api/StatementModificationHelperTest.php +++ b/extensions/Wikibase/repo/tests/phpunit/includes/Api/StatementModificationHelperTest.php @@ -50,6 +50,7 @@ try { $helper->getEntityIdFromString( $invalidEntityIdString ); + $this->fail( 'Expected exception was not thrown' ); } catch ( ApiUsageException $ex ) { $this->assertMessage( 'invalid-entity-id', $ex ); } @@ -96,6 +97,7 @@ try { $helper->getStatementFromEntity( 'foo', $entity ); + $this->fail( 'Expected exception was not thrown' ); } catch ( ApiUsageException $ex ) { $this->assertMessage( 'no-such-claim', $ex ); } @@ -108,6 +110,7 @@ try { $helper->getStatementFromEntity( 'unknown', $entity ); + $this->fail( 'Expected exception was not thrown' ); } catch ( ApiUsageException $ex ) { $this->assertMessage( 'no-such-claim', $ex ); } @@ -141,6 +144,7 @@ try { $helper->applyChangeOp( $changeOp, new Item() ); + $this->fail( 'Expected exception was not thrown' ); } catch ( ApiUsageException $ex ) { $this->assertMessage( 'modification-failed', $ex ); } @@ -160,6 +164,7 @@ try { $helper->applyChangeOp( $changeOp, new Item() ); + $this->fail( 'Expected exception was not thrown' ); } catch ( ApiUsageException $ex ) { $this->assertMessage( 'modification-failed', $ex ); } diff --git a/extensions/Wikibase/repo/tests/phpunit/includes/ChangeOp/ChangeOpLabelTest.php b/extensions/Wikibase/repo/tests/phpunit/includes/ChangeOp/ChangeOpLabelTest.php index 263a3d3..1a007ad 100644 --- a/extensions/Wikibase/repo/tests/phpunit/includes/ChangeOp/ChangeOpLabelTest.php +++ b/extensions/Wikibase/repo/tests/phpunit/includes/ChangeOp/ChangeOpLabelTest.php @@ -8,7 +8,6 @@ use Wikibase\DataModel\Entity\EntityDocument; use Wikibase\DataModel\Entity\Item; use Wikibase\DataModel\Entity\ItemId; -use Wikibase\DataModel\Term\FingerprintProvider; use Wikibase\Summary; /** @@ -102,7 +101,7 @@ } /** - * @return FingerprintProvider|EntityDocument + * @return Item */ private function provideNewEntity() { $item = new Item( new ItemId( 'Q23' ) ); diff --git a/extensions/Wikibase/repo/tests/phpunit/includes/Content/EntityContentTest.php b/extensions/Wikibase/repo/tests/phpunit/includes/Content/EntityContentTest.php index 1f5d0b3..1666268 100644 --- a/extensions/Wikibase/repo/tests/phpunit/includes/Content/EntityContentTest.php +++ b/extensions/Wikibase/repo/tests/phpunit/includes/Content/EntityContentTest.php @@ -5,13 +5,14 @@ use Diff\DiffOp\Diff\Diff; use Diff\DiffOp\DiffOpChange; use Diff\Patcher\PatcherException; +use InvalidArgumentException; use ParserOutput; use Title; use Wikibase\DataModel\Entity\EntityDocument; use Wikibase\DataModel\Entity\EntityId; use Wikibase\DataModel\Entity\EntityRedirect; use Wikibase\DataModel\Services\Diff\EntityDiff; -use Wikibase\DataModel\Term\FingerprintProvider; +use Wikibase\DataModel\Term\LabelsProvider; use Wikibase\EntityContent; use Wikibase\Lib\Store\EntityStore; use Wikibase\Repo\Content\EntityContentDiff; @@ -86,12 +87,12 @@ $this->assertSame( $expected, $entityContent->getTextForSearchIndex() ); } - private function setLabel( EntityDocument $entity, $lang, $text ) { - if ( $entity instanceof FingerprintProvider ) { - $entity->getFingerprint()->setLabel( $lang, $text ); - } else { - throw new \InvalidArgumentException( 'FingerprintProvider expected!' ); + private function setLabel( EntityDocument $entity, $languageCode, $text ) { + if ( !( $entity instanceof LabelsProvider ) ) { + throw new InvalidArgumentException( '$entity must be a LabelsProvider' ); } + + $entity->getLabels()->setTextForLanguage( $languageCode, $text ); } public function getTextForSearchIndexProvider() { diff --git a/extensions/Wikibase/repo/tests/phpunit/includes/Specials/SpecialGoToLinkedPageTest.php b/extensions/Wikibase/repo/tests/phpunit/includes/Specials/SpecialGoToLinkedPageTest.php index 8f9fed1..e012819 100644 --- a/extensions/Wikibase/repo/tests/phpunit/includes/Specials/SpecialGoToLinkedPageTest.php +++ b/extensions/Wikibase/repo/tests/phpunit/includes/Specials/SpecialGoToLinkedPageTest.php @@ -29,6 +29,11 @@ */ class SpecialGoToLinkedPageTest extends SpecialPageTestBase { + use HtmlAssertionHelpers; + + /** @see \LanguageQqx */ + const DUMMY_LANGUAGE = 'qqx'; + /** * @return SiteLinkLookup */ @@ -147,32 +152,13 @@ */ public function testExecuteWithoutRedirect( $sub, $target, $site, $item, $error ) { /* @var FauxResponse $response */ - list( $output, $response ) = $this->executeSpecialPage( $sub, null, 'qqx' ); + list( $output, $response ) = $this->executeSpecialPage( $sub, null, self::DUMMY_LANGUAGE ); $this->assertEquals( $target, $response->getheader( 'Location' ), 'Redirect' ); - $matchers = array(); - $matchers['site'] = array( - 'tag' => 'input', - 'attributes' => array( - 'name' => 'site', - 'value' => $site - ) ); - $matchers['itemid'] = array( - 'tag' => 'input', - 'attributes' => array( - 'name' => 'itemid', - 'value' => $item - ) ); - $matchers['submit'] = array( - 'tag' => 'button', - 'attributes' => array( - 'type' => 'submit', - ) - ); - foreach ( $matchers as $key => $matcher ) { - $this->assertTag( $matcher, $output, "Failed to match html output for: " . $key ); - } + $this->assertHtmlContainsInputWithNameAndValue( $output, 'site', $site ); + $this->assertHtmlContainsInputWithNameAndValue( $output, 'itemid', $item ); + $this->assertHtmlContainsSubmitControl( $output ); if ( !empty( $error ) ) { $this->assertContains( '<p class="error">' . $error . '</p>', $output, diff --git a/extensions/Wikibase/repo/tests/phpunit/includes/Specials/SpecialModifyTermTestCase.php b/extensions/Wikibase/repo/tests/phpunit/includes/Specials/SpecialModifyTermTestCase.php index fe165a3..a992462 100644 --- a/extensions/Wikibase/repo/tests/phpunit/includes/Specials/SpecialModifyTermTestCase.php +++ b/extensions/Wikibase/repo/tests/phpunit/includes/Specials/SpecialModifyTermTestCase.php @@ -16,17 +16,29 @@ */ abstract class SpecialModifyTermTestCase extends SpecialPageTestBase { + const USER_LANGUAGE = 'en'; + + protected function setUp() { + + parent::setUp(); + + $this->setMwGlobals( 'wgGroupPermissions', [ '*' => [ 'edit' => true, 'item-term' => true ] ] ); + } + /** * Creates a new item and returns its id. * + * @param string $language + * @param string $termValue * @return string */ - private function createNewItem() { + private function createNewItemWithTerms( $language, $termValue ) { + $item = new Item(); // add data and check if it is shown in the form - $item->setLabel( 'de', 'foo' ); - $item->setDescription( 'de', 'foo' ); - $item->setAliases( 'de', array( 'foo' ) ); + $item->setLabel( $language, $termValue ); + $item->setDescription( $language, $termValue ); + $item->setAliases( $language, [ $termValue ] ); // save the item $store = WikibaseRepo::getDefaultInstance()->getEntityStore(); @@ -36,102 +48,165 @@ return $item->getId()->getSerialization(); } - public function testExecute() { - $id = $this->createNewItem(); - - $this->setMwGlobals( 'wgGroupPermissions', array( '*' => array( 'edit' => true, 'item-term' => true ) ) ); - + public function testRenderWithoutSubPage_AllInputFieldsPresent() { $page = $this->newSpecialPage(); - $matchers['id'] = array( + $matchers['id'] = [ 'tag' => 'input', - 'attributes' => array( + 'attributes' => [ 'id' => 'wb-modifyentity-id', 'class' => 'wb-input', 'name' => 'id', - ) ); - $matchers['language'] = array( + ] ]; + $matchers['language'] = [ 'tag' => 'input', - 'attributes' => array( + 'attributes' => [ 'id' => 'wb-modifyterm-language', 'class' => 'wb-input', 'name' => 'language', - 'value' => 'en', - ) ); - $matchers['value'] = array( + 'value' => self::USER_LANGUAGE, + ] ]; + $matchers['value'] = [ 'tag' => 'input', - 'attributes' => array( + 'attributes' => [ 'id' => 'wb-modifyterm-value', 'class' => 'wb-input', 'name' => 'value', - ) ); - $matchers['submit'] = array( + ] ]; + $matchers['submit'] = [ 'tag' => 'input', - 'attributes' => array( + 'attributes' => [ 'id' => 'wb-' . strtolower( $page->getName() ) . '-submit', 'class' => 'wb-button', 'type' => 'submit', 'name' => 'wikibase-' . strtolower( $page->getName() ) . '-submit', - ) ); + ] ]; // execute with no subpage value - list( $output, ) = $this->executeSpecialPage( '', null, 'en' ); + list( $output, ) = $this->executeSpecialPage( '', null, self::USER_LANGUAGE ); foreach ( $matchers as $key => $matcher ) { $this->assertTag( $matcher, $output, "Failed to match html output with tag '{$key}'" ); } + } - // execute with one subpage value - list( $output, ) = $this->executeSpecialPage( $id, null, 'en' ); - $matchers['id']['attributes'] = array( + public function testRenderWithOneSubpageValue_TreatsValueAsItemIdAndShowsOnlyTermInputField() { + $notUserLanguage = 'de'; + $id = $this->createNewItemWithTerms( $notUserLanguage, 'some-term-value' ); + + $page = $this->newSpecialPage(); + + $matchers['id'] = [ + 'tag' => 'input', + 'attributes' => [ 'type' => 'hidden', 'name' => 'id', 'value' => $id, - ); - $matchers['language']['attributes'] = array( - 'type' => 'hidden', - 'name' => 'language', - 'value' => 'en', - ); - $matchers['remove'] = array( + ] ]; + $matchers['language'] = [ 'tag' => 'input', - 'attributes' => array( + 'attributes' => [ + 'name' => 'language', + 'value' => self::USER_LANGUAGE, + 'type' => 'hidden', + ] ]; + $matchers['value'] = [ + 'tag' => 'input', + 'attributes' => [ + 'id' => 'wb-modifyterm-value', + 'class' => 'wb-input', + 'name' => 'value', + ] ]; + $matchers['submit'] = [ + 'tag' => 'input', + 'attributes' => [ + 'id' => 'wb-' . strtolower( $page->getName() ) . '-submit', + 'class' => 'wb-button', + 'type' => 'submit', + 'name' => 'wikibase-' . strtolower( $page->getName() ) . '-submit', + ] ]; + $matchers['remove'] = [ + 'tag' => 'input', + 'attributes' => [ 'type' => 'hidden', 'name' => 'remove', 'value' => 'remove', - ) ); + ] ]; + + // execute with one subpage value + list( $output, ) = $this->executeSpecialPage( $id, null, self::USER_LANGUAGE ); foreach ( $matchers as $key => $matcher ) { $this->assertTag( $matcher, $output, "Failed to match html output with tag '{$key}' passing one subpage value" ); } + } + + public function testRenderWithTwoSubpageValues_TreatsSecondValueAsLanguageAndShowsOnlyTermInputField() { + $id = $this->createNewItemWithTerms( $itemTermLanguage = 'de', $termValue = 'foo' ); + + $page = $this->newSpecialPage(); + + $matchers['id'] = [ + 'tag' => 'input', + 'attributes' => [ + 'type' => 'hidden', + 'name' => 'id', + 'value' => $id, + ] ]; + $matchers['language'] = [ + 'tag' => 'input', + 'attributes' => [ + 'name' => 'language', + 'value' => $itemTermLanguage, + 'type' => 'hidden', + ] ]; + $matchers['value'] = [ + 'tag' => 'input', + 'attributes' => [ + 'id' => 'wb-modifyterm-value', + 'class' => 'wb-input', + 'name' => 'value', + 'value' => $termValue + ] ]; + $matchers['submit'] = [ + 'tag' => 'input', + 'attributes' => [ + 'id' => 'wb-' . strtolower( $page->getName() ) . '-submit', + 'class' => 'wb-button', + 'type' => 'submit', + 'name' => 'wikibase-' . strtolower( $page->getName() ) . '-submit', + ] ]; + $matchers['remove'] = [ + 'tag' => 'input', + 'attributes' => [ + 'type' => 'hidden', + 'name' => 'remove', + 'value' => 'remove', + ] ]; // execute with two subpage values - list( $output, ) = $this->executeSpecialPage( $id . '/de', null, 'en' ); - $matchers['language']['attributes']['value'] = 'de'; - $matchers['value']['attributes']['value'] = 'foo'; + list( $output, ) = $this->executeSpecialPage( $id . '/' . $itemTermLanguage, null, self::USER_LANGUAGE ); foreach ( $matchers as $key => $matcher ) { - $this->assertTag( $matcher, $output, "Failed to match html output with tag '{$key}' passing two subpage values" ); + $this->assertTag( $matcher, $output, "Failed to match html output with tag '{$key}' passing two subpage values" . PHP_EOL . $output ); } } public function testValuePreservesWhenNothingEntered() { - $id = $this->createNewItem(); + $id = $this->createNewItemWithTerms( $language = 'de', $termValue = 'foo' ); - $this->setMwGlobals( 'wgGroupPermissions', array( '*' => array( 'edit' => true, 'item-term' => true ) ) ); - - $request = new FauxRequest( array( 'id' => $id, 'language' => 'de', 'value' => '' ), true ); + $request = new FauxRequest( [ 'id' => $id, 'language' => $language, 'value' => '' ], true ); list( $output, ) = $this->executeSpecialPage( '', $request ); - $this->assertTag( array( + $this->assertTag( [ 'tag' => 'input', - 'attributes' => array( + 'attributes' => [ 'id' => 'wb-modifyterm-value', 'class' => 'wb-input', 'name' => 'value', - 'value' => 'foo', - ) - ), $output, 'Value still preserves when no value was entered in the big form' ); + 'value' => $termValue, + ] + ], $output, 'Value still preserves when no value was entered in the big form' ); } } diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 5dcc9d8..e346a27 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -466,6 +466,7 @@ 'Wikibase\\Client\\Specials\\SpecialUnconnectedPages' => $baseDir . '/extensions/Wikibase/client/includes/Specials/SpecialUnconnectedPages.php', 'Wikibase\\Client\\Store\\AddUsagesForPageJob' => $baseDir . '/extensions/Wikibase/client/includes/Store/AddUsagesForPageJob.php', 'Wikibase\\Client\\Store\\RepositoryServiceContainer' => $baseDir . '/extensions/Wikibase/client/includes/Store/RepositoryServiceContainer.php', + 'Wikibase\\Client\\Store\\RepositoryServiceContainerFactory' => $baseDir . '/extensions/Wikibase/client/includes/Store/RepositoryServiceContainerFactory.php', 'Wikibase\\Client\\Store\\Sql\\BulkSubscriptionUpdater' => $baseDir . '/extensions/Wikibase/client/includes/Store/Sql/BulkSubscriptionUpdater.php', 'Wikibase\\Client\\Store\\Sql\\PagePropsEntityIdLookup' => $baseDir . '/extensions/Wikibase/client/includes/Store/Sql/PagePropsEntityIdLookup.php', 'Wikibase\\Client\\Store\\TitleFactory' => $baseDir . '/extensions/Wikibase/client/includes/Store/TitleFactory.php', @@ -551,6 +552,7 @@ 'Wikibase\\Client\\Tests\\Specials\\SpecialPagesWithBadgesTest' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/Specials/SpecialPagesWithBadgesTest.php', 'Wikibase\\Client\\Tests\\Specials\\SpecialUnconnectedPagesTest' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/Specials/SpecialUnconnectedPagesTest.php', 'Wikibase\\Client\\Tests\\Store\\AddUsagesForPageJobTest' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/Store/AddUsagesForPageJobTest.php', + 'Wikibase\\Client\\Tests\\Store\\RepositoryServiceContainerFactoryTest' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/Store/RepositoryServiceContainerFactoryTest.php', 'Wikibase\\Client\\Tests\\Store\\RepositoryServiceContainerTest' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/Store/RepositoryServiceContainerTest.php', 'Wikibase\\Client\\Tests\\Store\\RepositoryServiceWiringTest' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/Store/RepositoryServiceWiringTest.php', 'Wikibase\\Client\\Tests\\Store\\Sql\\BulkSubscriptionUpdaterTest' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/Store/Sql/BulkSubscriptionUpdaterTest.php', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index deef418..68d14a0 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1409,12 +1409,12 @@ "source": { "type": "git", "url": "https://github.com/wikimedia/mediawiki-extensions-Wikibase.git", - "reference": "429ab38c5ddf34438425a4012b08fcba806fb54b" + "reference": "5c39fd44085adf7797e5084a7754b7631c2f2e1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/429ab38c5ddf34438425a4012b08fcba806fb54b", - "reference": "429ab38c5ddf34438425a4012b08fcba806fb54b", + "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/5c39fd44085adf7797e5084a7754b7631c2f2e1b", + "reference": "5c39fd44085adf7797e5084a7754b7631c2f2e1b", "shasum": "" }, "require": { @@ -1447,7 +1447,7 @@ "jakub-onderka/php-parallel-lint": "0.9.2", "mediawiki/mediawiki-codesniffer": "0.4.0|0.5.0" }, - "time": "2017-01-26 15:15:12", + "time": "2017-01-27 16:09:49", "type": "mediawiki-extension", "installation-source": "dist", "autoload": { -- To view, visit https://gerrit.wikimedia.org/r/334749 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I38256934302440e4d906f29fa09a05c191a085a1 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Wikidata Gerrit-Branch: master Gerrit-Owner: WikidataBuilder <wikidata-servi...@wikimedia.de> Gerrit-Reviewer: Aude <aude.w...@gmail.com> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits