Thiemo Mättig (WMDE) has submitted this change and it was merged. Change subject: (bug 64308) Localize error parameters. ......................................................................
(bug 64308) Localize error parameters. This patch generalizes the localization of parameters found in Error objects. This releves the code that generates the error from worrying about how to format/localize the parameters. See the change to SiteLinkUniquenessValidator in particular. Change-Id: I2240d6e0ced47fc2ab1eb5795073c185e6ad336f --- M lib/includes/Validators/ValidatorErrorLocalizer.php M lib/includes/formatters/FormattingException.php A lib/includes/i18n/MessageParameterFormatter.php M lib/includes/i18n/WikibaseExceptionLocalizer.php M lib/includes/store/EntityTitleLookup.php M lib/tests/phpunit/Validators/ValidatorErrorLocalizerTest.php A lib/tests/phpunit/i18n/MessageParameterFormatterTest.php M lib/tests/phpunit/i18n/WikibaseExceptionLocalizerTest.php M repo/Wikibase.hooks.php M repo/i18n/en.json M repo/i18n/qqq.json M repo/includes/LabelDescriptionDuplicateDetector.php M repo/includes/WikibaseRepo.php M repo/includes/content/SiteLinkUniquenessValidator.php M repo/tests/phpunit/includes/LabelDescriptionDuplicateDetectorTest.php M repo/tests/phpunit/includes/PreSaveChecksTest.php M repo/tests/phpunit/includes/api/ClaimModificationHelperTest.php M repo/tests/phpunit/includes/content/SiteLinkUniquenessValidatorTest.php 18 files changed, 504 insertions(+), 116 deletions(-) Approvals: WikidataJenkins: Verified Siebrand: Looks good to me, but someone else must approve Thiemo Mättig (WMDE): Looks good to me, approved jenkins-bot: Checked diff --git a/lib/includes/Validators/ValidatorErrorLocalizer.php b/lib/includes/Validators/ValidatorErrorLocalizer.php index bd1587f..b278dc8 100644 --- a/lib/includes/Validators/ValidatorErrorLocalizer.php +++ b/lib/includes/Validators/ValidatorErrorLocalizer.php @@ -4,6 +4,8 @@ use Message; use Status; +use ValueFormatters\FormattingException; +use ValueFormatters\ValueFormatter; use ValueValidators\Error; use ValueValidators\Result; @@ -14,6 +16,20 @@ * @author Daniel Kinzler */ class ValidatorErrorLocalizer { + + /** + * @var ValueFormatter Formatter for generating wikitext for message parameters. + */ + protected $paramFormatter; + + /** + * @param ValueFormatter $paramFormatter A formatter for formatting message parameters. + * MUST return wikitext. This is typically some kind of dispatcher. If not provided, + * naive formatting will be used, which will fail on non-primitive parameters. + */ + function __construct( ValueFormatter $paramFormatter = null ) { + $this->paramFormatter = $paramFormatter; + } /** * Returns a Status representing the given validation result. @@ -53,8 +69,30 @@ $key = 'wikibase-validator-' . $error->getCode(); $params = $error->getParameters(); - //TODO: look for non-string in $params and run them through an appropriate formatter + foreach ( $params as &$param ) { + if ( !is_string( $param ) ) { + $param = $this->paramToString( $param ); + } + } - return wfMessage( $key, $params ); + return wfMessage( $key )->params( $params ); + } + + /** + * @param mixed $param + * + * @return string wikitext + */ + private function paramToString( $param ) { + if ( $this->paramFormatter ) { + try { + return $this->paramFormatter->format( $param ); + } catch ( FormattingException $e ) { + // ok, never mind, use naive version below. + wfWarn( __METHOD__ . ': Formatting of message parameter fialed: ' . $e->getMessage() ); + } + } + + return wfEscapeWikiText( strval( $param ) ); } } \ No newline at end of file diff --git a/lib/includes/formatters/FormattingException.php b/lib/includes/formatters/FormattingException.php index a1641cb..69c5b7e 100644 --- a/lib/includes/formatters/FormattingException.php +++ b/lib/includes/formatters/FormattingException.php @@ -1,13 +1,14 @@ <?php namespace Wikibase\Lib; -use RuntimeException; /** * FormattingException * + * @deprecated use \ValueFormatters\FormattingException + * * @license GPL 2+ * @author Daniel Kinzler */ -class FormattingException extends RuntimeException { +class FormattingException extends \ValueFormatters\FormattingException { } \ No newline at end of file diff --git a/lib/includes/i18n/MessageParameterFormatter.php b/lib/includes/i18n/MessageParameterFormatter.php new file mode 100644 index 0000000..bdff3df --- /dev/null +++ b/lib/includes/i18n/MessageParameterFormatter.php @@ -0,0 +1,155 @@ +<?php + +namespace Wikibase\i18n; + +use DataValues\DataValue; +use Language; +use SiteStore; +use ValueFormatters\FormattingException; +use ValueFormatters\Localizer; +use ValueFormatters\ValueFormatter; +use Wikibase\DataModel\Entity\EntityId; +use Wikibase\DataModel\SiteLink; +use Wikibase\EntityTitleLookup; +use Wikibase\Lib\MediaWikiNumberLocalizer; + +/** + * ValueFormatter for formatting objects that may be encountered in + * parameters of ValueValidators\Error objects as wikitext. + * + * @license GPL 2+ + * @author Daniel Kinzler + */ +class MessageParameterFormatter implements ValueFormatter { + + /** + * @var ValueFormatter + */ + private $dataValueFormatter; + + /** + * @var EntityTitleLookup + */ + private $entityTitleLookup; + + /** + * @var SiteStore + */ + private $sites; + + /** + * @var Language + */ + private $language; + + /** + * @var Localizer + */ + private $valueLocalizer; + + /** + * @param ValueFormatter $dataValueFormatter A formatter for turning DataValues into wikitext. + * @param EntityTitleLookup $entityTitleLookup + * @param SiteStore $sites + * @param Language $language + */ + function __construct( + ValueFormatter $dataValueFormatter, + EntityTitleLookup $entityTitleLookup, + SiteStore $sites, + Language $language + ) { + $this->dataValueFormatter = $dataValueFormatter; + $this->entityTitleLookup = $entityTitleLookup; + $this->sites = $sites; + $this->language = $language; + + $this->valueLocalizer = new MediaWikiNumberLocalizer( $language ); + } + + /** + * Formats a value. + * + * @since 0.1 + * + * @param mixed $value The value to format + * + * @return string The formatted value (as wikitext). + * @throws FormattingException + */ + public function format( $value ) { + if ( is_int( $value ) || is_float( $value ) ) { + return $this->valueLocalizer->localizeNumber( $value ); + } elseif ( $value instanceof DataValue ) { + return $this->dataValueFormatter->format( $value ); + } elseif ( is_object( $value ) ) { + return $this->formatObject( $value ); + } elseif ( is_array( $value ) ) { + return $this->formatValueList( $value ); + } + + return wfEscapeWikiText( strval( $value ) ); + } + + /** + * @param array $values + * + * @return string[] + */ + private function formatValueList( $values ) { + $formatted = array(); + + foreach ( $values as $key => $value ) { + $formatted[$key] = $this->format( $value ); + } + + //XXX: commaList should really be in the Localizer interface. + return $this->language->commaList( $formatted ); + } + + /** + * @param object $value + * + * @return string The formatted value (as wikitext). + */ + private function formatObject( $value ) { + if ( $value instanceof EntityId ) { + return $this->formatEntityId( $value ); + } elseif ( $value instanceof SiteLink ) { + return $this->formatSiteLink( $value ); + } + + // hope we can interpolate, and just fail if we can't + return wfEscapeWikiText( strval( $value ) ); + } + + /** + * @param EntityId $entityId + * + * @return string The formatted ID (as a wikitext link). + */ + private function formatEntityId( EntityId $entityId ) { + // @todo: this should use TitleValue + MediaWikiPageLinkRenderer! + $title = $this->entityTitleLookup->getTitleForId( $entityId ); + + $target = $title->getFullText(); + $text = wfEscapeWikiText( $entityId->getSerialization() ); + + return "[[$target|$text]]"; + } + + /** + * @param SiteLink $link + * + * @return string The formatted link (as a wikitext link). + */ + private function formatSiteLink( SiteLink $link ) { + $siteId = $link->getSiteId(); + $page = $link->getPageName(); + + $site = $this->sites->getSite( $link->getSiteId() ); + $url = $site->getPageUrl( $link->getPageName() ); + + return "[$url $siteId:$page]"; + } +} diff --git a/lib/includes/i18n/WikibaseExceptionLocalizer.php b/lib/includes/i18n/WikibaseExceptionLocalizer.php index 412dd42..b55944e 100644 --- a/lib/includes/i18n/WikibaseExceptionLocalizer.php +++ b/lib/includes/i18n/WikibaseExceptionLocalizer.php @@ -5,6 +5,7 @@ use Exception; use Message; use MessageException; +use ValueFormatters\ValueFormatter; use ValueParsers\ParseException; use Wikibase\ChangeOp\ChangeOpValidationException; use Wikibase\Validators\ValidatorErrorLocalizer; @@ -29,8 +30,12 @@ */ protected $validatorErrorLocalizer; - public function __construct() { - $this->validatorErrorLocalizer = new ValidatorErrorLocalizer(); + /** + * @param ValueFormatter $paramFormatter A formatter for formatting message parameters + * as wikitext. Typically some kind of dispatcher. + */ + public function __construct( ValueFormatter $paramFormatter ) { + $this->validatorErrorLocalizer = new ValidatorErrorLocalizer( $paramFormatter ); } /** diff --git a/lib/includes/store/EntityTitleLookup.php b/lib/includes/store/EntityTitleLookup.php index bdfd0d3..9991531 100644 --- a/lib/includes/store/EntityTitleLookup.php +++ b/lib/includes/store/EntityTitleLookup.php @@ -22,6 +22,8 @@ * If the entity does not exist, this method will return either null, * or a Title object referring to a page that does not exist. * + * @todo change this to return a TitleValue + * * @since 0.4 * * @param EntityId $id diff --git a/lib/tests/phpunit/Validators/ValidatorErrorLocalizerTest.php b/lib/tests/phpunit/Validators/ValidatorErrorLocalizerTest.php index fb0ad32..0b817d6 100644 --- a/lib/tests/phpunit/Validators/ValidatorErrorLocalizerTest.php +++ b/lib/tests/phpunit/Validators/ValidatorErrorLocalizerTest.php @@ -3,6 +3,7 @@ namespace Wikibase\Test\Validators; use Status; +use ValueFormatters\ValueFormatter; use ValueValidators\Error; use ValueValidators\Result; use Wikibase\Validators\ValidatorErrorLocalizer; @@ -20,22 +21,56 @@ */ class ValidatorErrorLocalizerTest extends \PHPUnit_Framework_TestCase { + /** + * @return ValueFormatter + */ + private function getMockFormatter() { + $mock = $this->getMock( 'ValueFormatters\ValueFormatter' ); + $mock->expects( $this->any() ) + ->method( 'format' ) + ->will( $this->returnCallback( + function ( $param ) { + if ( is_array( $param ) ) { + $param = implode( '|', $param ); + } else { + $param = "$param"; + } + + return $param; + } + ) ); + + return $mock; + } + public static function provideGetErrorMessage() { return array( - array( Error::newError( 'Bla bla' ) ), - array( Error::newError( 'Bla bla', null, 'test', array( 'thingy' ) ) ), + 'simple' => array( + Error::newError( 'Bla bla' ), + array() + ), + 'with params' => array( + Error::newError( + 'Bla bla', + null, + 'test', + array( 'thingy', array( 'a', 'b', 'c' ) ) + ), + array( 'thingy', 'a|b|c' ) + ), ); } /** * @dataProvider provideGetErrorMessage() */ - public function testGetErrorMessage( $error ) { - $localizer = new ValidatorErrorLocalizer(); + public function testGetErrorMessage( $error, $params ) { + $localizer = new ValidatorErrorLocalizer( $this->getMockFormatter() ); $message = $localizer->getErrorMessage( $error ); //TODO: check that messages for actual error codes exist $this->assertInstanceOf( 'Message', $message ); + $this->assertEquals( $params, $message->getParams() ); } public static function provideGetResultStatus() { @@ -54,7 +89,7 @@ * @dataProvider provideGetResultStatus() */ public function testGetResultStatus( Result $result ) { - $localizer = new ValidatorErrorLocalizer(); + $localizer = new ValidatorErrorLocalizer( $this->getMockFormatter() ); $status = $localizer->getResultStatus( $result ); $this->assertInstanceOf( 'Status', $status ); diff --git a/lib/tests/phpunit/i18n/MessageParameterFormatterTest.php b/lib/tests/phpunit/i18n/MessageParameterFormatterTest.php new file mode 100644 index 0000000..e783338 --- /dev/null +++ b/lib/tests/phpunit/i18n/MessageParameterFormatterTest.php @@ -0,0 +1,114 @@ +<?php + +namespace Wikibase\Test; +use DataValues\DataValue; +use DataValues\DecimalValue; +use Language; +use Site; +use SiteStore; +use Title; +use ValueFormatters\ValueFormatter; +use Wikibase\DataModel\Entity\ItemId; +use Wikibase\DataModel\SiteLink; +use Wikibase\EntityId; +use Wikibase\EntityTitleLookup; +use Wikibase\i18n\MessageParameterFormatter; + +/** + * @property mixed getMockValueFormatter + * @covers Wikibase\i18n\MessageParameterFormatter + * + * @group Wikibase + * @group WikibaseLib + * + * @licence GNU GPL v2+ + * @author Daniel Kinzler + */ +class MessageParameterFormatterTest extends \PHPUnit_Framework_TestCase { + + public function formatProvider() { + $decimal = new DecimalValue( '+123.456' ); + $entityId = new ItemId( 'Q123' ); + $siteLink = new SiteLink( 'acme', 'Foo' ); + + return array( + 'string' => array( 'Hello', 'en', 'Hello' ), + 'int' => array( 456, 'en', '456' ), + 'float en' => array( 123.456, 'en', '123.456' ), + 'float de' => array( 123.456, 'de', '123,456' ), + 'DecimalValue en' => array( $decimal, 'en', 'DataValues\DecimalValue:+123.456' ), + 'EntityId' => array( $entityId, 'en', '[[Q123|Q123]]' ), + 'SiteLink' => array( $siteLink, 'en', '[http://acme.com/Foo acme:Foo]' ), + 'list of floats' => array( array( 1.2, 0.5 ), 'en', '1.2, 0.5' ), + ); + } + + /** + * @dataProvider formatProvider + */ + public function testFormat( $param, $lang, $expected ) { + $formatter = new MessageParameterFormatter( + $this->getMockValueFormatter(), + $this->getMockTitleLookup(), + $this->getMockSitesTable(), + Language::factory( $lang ) + ); + + $actual = $formatter->format( $param ); + $this->assertEquals( $expected, $actual ); + } + + /** + * @return ValueFormatter + */ + private function getMockValueFormatter() { + $mock = $this->getMock( 'ValueFormatters\ValueFormatter' ); + $mock->expects( $this->any() ) + ->method( 'format' ) + ->will( $this->returnCallback( + function ( DataValue $param ) { + $class = get_class( $param ); + $value = $param->getArrayValue(); + + return "$class:$value"; + } + ) ); + + return $mock; + } + + /** + * @return EntityTitleLookup + */ + private function getMockTitleLookup() { + $mock = $this->getMock( 'Wikibase\EntityTitleLookup' ); + $mock->expects( $this->any() ) + ->method( 'getTitleForId' ) + ->will( $this->returnCallback( + function ( EntityId $id ) { + return Title::makeTitle( NS_MAIN, $id->getSerialization() ); + } + ) ); + + return $mock; + } + + /** + * @return SiteStore + */ + private function getMockSitesTable() { + $mock = $this->getMock( 'SiteStore' ); + $mock->expects( $this->any() ) + ->method( 'getSite' ) + ->will( $this->returnCallback( + function ( $siteId ) { + $site = new Site(); + $site->setGlobalId( $siteId ); + $site->setLinkPath( "http://$siteId.com/$1" ); + return $site; + } + ) ); + + return $mock; + } +} diff --git a/lib/tests/phpunit/i18n/WikibaseExceptionLocalizerTest.php b/lib/tests/phpunit/i18n/WikibaseExceptionLocalizerTest.php index 560bf4c..46d455d 100644 --- a/lib/tests/phpunit/i18n/WikibaseExceptionLocalizerTest.php +++ b/lib/tests/phpunit/i18n/WikibaseExceptionLocalizerTest.php @@ -3,10 +3,12 @@ namespace Wikibase\Test; use Exception; use RuntimeException; +use ValueFormatters\ValueFormatter; use ValueParsers\ParseException; use ValueValidators\Error; use ValueValidators\Result; use Wikibase\ChangeOp\ChangeOpValidationException; +use Wikibase\DataModel\SiteLink; use Wikibase\i18n\WikibaseExceptionLocalizer; /** @@ -26,8 +28,8 @@ Error::newError( 'Eeek!', null, 'too-long', array( 8 ) ), ) ); $result2 = Result::newError( array( - Error::newError( 'Eeek!', null, 'too-long', array( 8 ) ), - Error::newError( 'Foo!', null, 'too-short', array( 8 ) ), + Error::newError( 'Eeek!', null, 'too-long', array( array( 'eekwiki', 'Eek' ) ) ), + Error::newError( 'Foo!', null, 'too-short', array( array( 'foowiki', 'Foo' ) ) ), ) ); return array( @@ -35,16 +37,38 @@ 'ParseException' => array( new ParseException( 'Blarg!' ), 'wikibase-parse-error', array() ), 'ChangeOpValidationException(0)' => array( new ChangeOpValidationException( $result0 ), 'wikibase-validator-invalid', array() ), - 'ChangeOpValidationException(1)' => array( new ChangeOpValidationException( $result1 ), 'wikibase-validator-too-long', array( 8 ) ), - 'ChangeOpValidationException(2)' => array( new ChangeOpValidationException( $result2 ), 'wikibase-validator-too-long', array( 8 ) ), + 'ChangeOpValidationException(1)' => array( new ChangeOpValidationException( $result1 ), 'wikibase-validator-too-long', array( '8' ) ), + 'ChangeOpValidationException(2)' => array( new ChangeOpValidationException( $result2 ), 'wikibase-validator-too-long', array( 'eekwiki|Eek' ) ), ); + } + + /** + * @return ValueFormatter + */ + private function getMockFormatter() { + $mock = $this->getMock( 'ValueFormatters\ValueFormatter' ); + $mock->expects( $this->any() ) + ->method( 'format' ) + ->will( $this->returnCallback( + function ( $param ) { + if ( is_array( $param ) ) { + $param = implode( '|', $param ); + } else { + $param = "$param"; + } + + return $param; + } + ) ); + + return $mock; } /** * @dataProvider provideGetExceptionMessage */ public function testGetExceptionMessage( Exception $ex, $expectedKey, $expectedParams ) { - $localizer = new WikibaseExceptionLocalizer(); + $localizer = new WikibaseExceptionLocalizer( $this->getMockFormatter() ); $this->assertTrue( $localizer->hasExceptionMessage( $ex ) ); diff --git a/repo/Wikibase.hooks.php b/repo/Wikibase.hooks.php index 220490a..ce4b1cd 100644 --- a/repo/Wikibase.hooks.php +++ b/repo/Wikibase.hooks.php @@ -1256,9 +1256,7 @@ // So, check the item's site links, but don't check label/description uniqueness. $validators = array( new SiteLinkUniquenessValidator( - $repo->getEntityTitleLookup(), - $repo->getStore()->newSiteLinkCache(), - SiteSQLStore::newInstance() + $repo->getStore()->newSiteLinkCache() ) ); diff --git a/repo/i18n/en.json b/repo/i18n/en.json index d39f184..420f89e 100644 --- a/repo/i18n/en.json +++ b/repo/i18n/en.json @@ -96,9 +96,9 @@ "wikibase-error-constraint-violation-label": "There {{PLURAL:$1|is a constraint violation|are constraint violations}} for the {{PLURAL:$1|label|labels}} \"$3\" in {{PLURAL:$1|language code|language codes}} \"$2\".", "wikibase-error-constraint-violation-description": "There is {{PLURAL:$1|a constraint|constraints}} violation for {{PLURAL:$1|description|descriptions}} \"$3\" for {{PLURAL:$1|language code|language codes}} \"$2\".", "wikibase-error-constraint-violation-aliases": "There is {{PLURAL:$1|a constraint|constraints}} violation for {{PLURAL:$1|alias|aliases}} \"$3\" for {{PLURAL:$1|language code|language codes}} \"$2\".", - "wikibase-validator-sitelink-already-used": "Site link [$1 $2] is already included in another item, [[$3]].", - "wikibase-validator-label-conflict": "Another property ($3) already has label \"$1\" associated with language code $2.", - "wikibase-validator-label-with-description-conflict": "Another item ($3) already has label \"$1\" and description \"$4\" associated with language code $2.", + "wikibase-validator-sitelink-conflict": "Site link $1 is already used by item $2.", + "wikibase-validator-label-conflict": "Property $3 already has label \"$1\" associated with language code $2.", + "wikibase-validator-label-with-description-conflict": "Item $3 already has label \"$1\" associated with language code $2, using the same description text.", "wikibase-validator-label-no-entityid": "The label must not be a valid entity id.", "wikibase-itemlink": "$1 $2", "wikibase-itemlink-id-wrapper": "($1)", diff --git a/repo/i18n/qqq.json b/repo/i18n/qqq.json index 8e8f77d..0d50319 100644 --- a/repo/i18n/qqq.json +++ b/repo/i18n/qqq.json @@ -115,7 +115,7 @@ "wikibase-warning-constraint-violation-length": "A warning message that a length constraint is triggered. This will usually come together with a fatal error message.\n\nParameters:\n* $1 - the language code", "wikibase-error-constraint-violation-label": "Error message that is shown when a user tries to save a multilanguage label that has some constraint violation, typically a string length violation.\n* $1 is the count of violating languages\n* $2 is the violating languages\n* $3 is the violating string on a shortened form, but this is usually not very useful as the message is usually given in an edit window", "wikibase-error-constraint-violation-description": "Error message that is shown when a user tries to save a multilanguage description that has some constraint violation, typically a string length violation.\n* $1 - the count of violating languages\n* $2 - the violating languages\n* $3 - the violating string on a shortened form, but this is usually not very useful as the message is usually given in an edit window","wikibase-error-constraint-violation-aliases": "Error message that is shown when a user tries to save an alias that has some constraint violation, typically a string length violation.\n* $1 - the count of violating languages\n* $2 - the violating languages\n* $3 - the violating string on a shortened form, but this is usually not very useful as the message is usually given in an edit window", - "wikibase-validator-sitelink-already-used": "Error message shown when an item can't be saved because it contains a site link already used by another item.\n\nParameters:\n* $1 - the URL to the remote client page\n* $2 - the title on the remote client site\n* $3 - the item (e.g. Q60) on the repo with the conflicting site link", + "wikibase-validator-sitelink-conflict": "Error message shown when an item contains a site link already used by another item.\n\nParameters:\n* $1 - an external wiki link to the sitelink's target\n* $2 - a local wiki link to the conflicting item.", "wikibase-validator-label-conflict": "Error message shown when a user tries to save a property that has a non-unique label.\n* $1 is label text\n* $2 is the labels language code\n* $3 is the id of the property that already has the label", "wikibase-validator-label-with-description-conflict": "Error message shown when a user tries to save an item that has a non-unique label+description pair. Parameters:\n* $1 is label text\n* $2 is the labels language code\n* $3 is the id of the query that already has the label\n* $4 is description text", "wikibase-validator-label-no-entityid": "Error message shown when a user tries to save an item that has a valid entity id as label. Parameters:\n* $1 is the label.", diff --git a/repo/includes/LabelDescriptionDuplicateDetector.php b/repo/includes/LabelDescriptionDuplicateDetector.php index 371dad1..e2f7dd8 100644 --- a/repo/includes/LabelDescriptionDuplicateDetector.php +++ b/repo/includes/LabelDescriptionDuplicateDetector.php @@ -229,10 +229,9 @@ $term->getType(), $errorCode, array( - $term->getType(), - $term->getLanguage(), $term->getText(), - $term->getEntityId()->getSerialization() + $term->getLanguage(), + $term->getEntityId() ) ); } diff --git a/repo/includes/WikibaseRepo.php b/repo/includes/WikibaseRepo.php index e03a699..927121a 100644 --- a/repo/includes/WikibaseRepo.php +++ b/repo/includes/WikibaseRepo.php @@ -4,7 +4,9 @@ use DataTypes\DataTypeFactory; use DataValues\DataValueFactory; +use SiteSQLStore; use ValueFormatters\FormatterOptions; +use ValueFormatters\ValueFormatter; use Wikibase\ChangeOp\ChangeOpFactory; use Wikibase\DataModel\Claim\ClaimGuidParser; use Wikibase\DataModel\Entity\BasicEntityIdParser; @@ -13,10 +15,12 @@ use Wikibase\EntityContentFactory; use Wikibase\EntityLookup; use Wikibase\i18n\ExceptionLocalizer; +use Wikibase\i18n\MessageParameterFormatter; use Wikibase\i18n\WikibaseExceptionLocalizer; use Wikibase\LanguageFallbackChainFactory; use Wikibase\Lib\ClaimGuidGenerator; use Wikibase\Lib\ClaimGuidValidator; +use Wikibase\Lib\DispatchingValueFormatter; use Wikibase\Lib\EntityIdLinkFormatter; use Wikibase\Lib\EntityRetrievingDataTypeLookup; use Wikibase\Lib\OutputFormatSnakFormatterFactory; @@ -426,19 +430,24 @@ } /** - * @return OutputFormatSnakFormatterFactory + * @return WikibaseValueFormatterBuilders */ - protected function newSnakFormatterFactory() { + protected function getValueFormatterBuilders() { global $wgContLang; - $valueFormatterBuilders = new WikibaseValueFormatterBuilders( + return new WikibaseValueFormatterBuilders( $this->getEntityLookup(), $wgContLang, $this->getEntityTitleLookup() ); + } + /** + * @return OutputFormatSnakFormatterFactory + */ + protected function newSnakFormatterFactory() { $builders = new WikibaseSnakFormatterBuilders( - $valueFormatterBuilders, + $this->getValueFormatterBuilders(), $this->getPropertyDataTypeLookup() ); @@ -464,13 +473,7 @@ * @return OutputFormatValueFormatterFactory */ protected function newValueFormatterFactory() { - global $wgContLang; - - $builders = new WikibaseValueFormatterBuilders( - $this->getEntityLookup(), - $wgContLang, - $this->getEntityTitleLookup() - ); + $builders = $this->getValueFormatterBuilders(); $factory = new OutputFormatValueFormatterFactory( $builders->getValueFormatterBuildersForFormats() ); return $factory; @@ -481,7 +484,9 @@ */ public function getExceptionLocalizer() { if ( !$this->exceptionLocalizer ) { - $this->exceptionLocalizer = new WikibaseExceptionLocalizer(); + $this->exceptionLocalizer = new WikibaseExceptionLocalizer( + $this->getMessageParameterFormatter() + ); } return $this->exceptionLocalizer; @@ -509,11 +514,7 @@ $options = new FormatterOptions(); $idFormatter = new EntityIdLinkFormatter( $options, $this->getEntityContentFactory() ); - $valueFormatterBuilders = new WikibaseValueFormatterBuilders( - $this->getEntityLookup(), - $wgContLang, - $this->getEntityTitleLookup() - ); + $valueFormatterBuilders = $this->getValueFormatterBuilders(); $snakFormatterBuilders = new WikibaseSnakFormatterBuilders( $valueFormatterBuilders, @@ -601,7 +602,7 @@ * @return ValidatorErrorLocalizer */ public function getValidatorErrorLocalizer() { - return new ValidatorErrorLocalizer(); + return new ValidatorErrorLocalizer( $this->getMessageParameterFormatter() ); } /** @@ -610,4 +611,33 @@ public function getLabelDescriptionDuplicateDetector() { return new LabelDescriptionDuplicateDetector( $this->getStore()->getTermIndex() ); } + + /** + * @return SiteSQLStore + */ + protected function getSitesTable() { + return SiteSQLStore::newInstance(); + } + + /** + * Returns a ValueFormatter suitable for converting message parameters to wikitext. + * The formatter is most likely implemented to dispatch to different formatters internally, + * based on the type of the parameter. + * + * @return ValueFormatter + */ + protected function getMessageParameterFormatter() { + global $wgLang; + + $formatterOptions = new FormatterOptions(); + $valueFormatteBuilders = $this->getValueFormatterBuilders(); + $valueFormatters = $valueFormatteBuilders->getWikiTextFormatters( $formatterOptions ); + + return new MessageParameterFormatter( + new DispatchingValueFormatter( $valueFormatters ), + $this->getEntityTitleLookup(), + $this->getSitesTable(), + $wgLang + ); + } } diff --git a/repo/includes/content/SiteLinkUniquenessValidator.php b/repo/includes/content/SiteLinkUniquenessValidator.php index 80a65e1..684c52d 100644 --- a/repo/includes/content/SiteLinkUniquenessValidator.php +++ b/repo/includes/content/SiteLinkUniquenessValidator.php @@ -2,14 +2,11 @@ namespace Wikibase\content; -use Message; -use SiteStore; -use Status; use ValueValidators\Error; use ValueValidators\Result; use Wikibase\DataModel\Entity\Entity; use Wikibase\DataModel\Entity\ItemId; -use Wikibase\EntityTitleLookup; +use Wikibase\DataModel\SiteLink; use Wikibase\SiteLinkLookup; /** @@ -23,29 +20,15 @@ class SiteLinkUniquenessValidator implements EntityValidator { /** - * @var SiteStore - */ - protected $siteStore; - - /** * @var SiteLinkLookup */ - protected $siteLinkLookup; + private $siteLinkLookup; /** - * @var EntityTitleLookup - */ - protected $entityTitleLookup; - - /** - * @param EntityTitleLookup $entityTitleLookup * @param SiteLinkLookup $siteLinkLookup - * @param SiteStore $siteStore */ - function __construct( EntityTitleLookup $entityTitleLookup, SiteLinkLookup $siteLinkLookup, SiteStore $siteStore ) { - $this->entityTitleLookup = $entityTitleLookup; + function __construct( SiteLinkLookup $siteLinkLookup ) { $this->siteLinkLookup = $siteLinkLookup; - $this->siteStore = $siteStore; } /** @@ -84,20 +67,14 @@ */ protected function getConflictError( array $conflict ) { $entityId = ItemId::newFromNumber( $conflict['itemId'] ); - $conflictingTitle = $this->entityTitleLookup->getTitleForId( $entityId ); - - $site = $this->siteStore->getSite( $conflict['siteId'] ); - $pageUrl = $site->getPageUrl( $conflict['sitePage'] ); return Error::newError( 'SiteLink conflict', 'sitelink', - 'sitelink-already-used', + 'sitelink-conflict', array( - $pageUrl, - $conflict['sitePage'], - $conflictingTitle->getFullText(), - $conflict['siteId'], + new SiteLink( $conflict['siteId'], $conflict['sitePage'] ), + $entityId, ) ); } diff --git a/repo/tests/phpunit/includes/LabelDescriptionDuplicateDetectorTest.php b/repo/tests/phpunit/includes/LabelDescriptionDuplicateDetectorTest.php index a9f0130..35b0d3f 100644 --- a/repo/tests/phpunit/includes/LabelDescriptionDuplicateDetectorTest.php +++ b/repo/tests/phpunit/includes/LabelDescriptionDuplicateDetectorTest.php @@ -68,10 +68,9 @@ 'label', 'label-conflict', array( - 'label', - 'en', 'item label', - 'Q42' + 'en', + new ItemId( 'Q42' ) ) ); @@ -175,10 +174,9 @@ 'label', 'label-with-description-conflict', array( - 'label', - 'en', 'item label', - 'Q42' + 'en', + new ItemId( 'Q42' ) ) ); diff --git a/repo/tests/phpunit/includes/PreSaveChecksTest.php b/repo/tests/phpunit/includes/PreSaveChecksTest.php index a93f1a3..f5e0cbb 100644 --- a/repo/tests/phpunit/includes/PreSaveChecksTest.php +++ b/repo/tests/phpunit/includes/PreSaveChecksTest.php @@ -3,6 +3,7 @@ namespace Wikibase\Test; use Status; +use ValueFormatters\ValueFormatter; use ValueValidators\Result; use Wikibase\DataModel\Entity\BasicEntityIdParser; use Wikibase\DataModel\Entity\Entity; @@ -137,6 +138,26 @@ } /** + * @return ValueFormatter + */ + private function getMockFormatter() { + $mock = $this->getMock( 'ValueFormatters\ValueFormatter' ); + $mock->expects( $this->any() ) + ->method( 'format' ) + ->will( $this->returnCallback( + function ( $param ) { + if ( is_object( $param ) ) { + $param = get_class( $param ); + } + + return wfEscapeWikiText( strval( $param ) ); + } + ) ); + + return $mock; + } + + /** * @dataProvider providePreSaveChecks * * @param array $oldData @@ -152,7 +173,7 @@ $languages = array( 'en', 'de' ); $validatorFactory = new TermValidatorFactory( $maxLength, $languages, $idParser, $dupeDetector ); - $errorLocalizer = new ValidatorErrorLocalizer(); + $errorLocalizer = new ValidatorErrorLocalizer( $this->getMockFormatter() ); $checks = new PreSaveChecks( $validatorFactory, diff --git a/repo/tests/phpunit/includes/api/ClaimModificationHelperTest.php b/repo/tests/phpunit/includes/api/ClaimModificationHelperTest.php index b93a6da..e6a100c 100644 --- a/repo/tests/phpunit/includes/api/ClaimModificationHelperTest.php +++ b/repo/tests/phpunit/includes/api/ClaimModificationHelperTest.php @@ -4,6 +4,7 @@ use DataValues\StringValue; use UsageException; +use ValueFormatters\ValueFormatter; use Wikibase\Api\CreateClaim; use ApiMain; use Wikibase\Api\ClaimModificationHelper; @@ -13,7 +14,6 @@ use Wikibase\DataModel\Snak\PropertyValueSnak; use Wikibase\i18n\WikibaseExceptionLocalizer; use Wikibase\Repo\WikibaseRepo; -use Wikibase\Validators\ValidatorErrorLocalizer; /** * @covers Wikibase\Api\ClaimModificationHelper @@ -82,12 +82,34 @@ $claimModificationHelper->getClaimFromEntity( 'q42$D8404CDA-25E4-4334-AF13-A3290BCD9C0N', $entity ); } + /** + * @return ValueFormatter + */ + private function getMockFormatter() { + $mock = $this->getMock( 'ValueFormatters\ValueFormatter' ); + $mock->expects( $this->any() ) + ->method( 'format' ) + ->will( $this->returnCallback( + function ( $param ) { + if ( is_object( $param ) ) { + $param = get_class( $param ); + } else { + $param = "$param"; + } + + return $param; + } + ) ); + + return $mock; + } + private function getNewInstance() { $api = new ApiMain(); $errorReporter = new ApiErrorReporter( $api, - new WikibaseExceptionLocalizer(), + new WikibaseExceptionLocalizer( $this->getMockFormatter() ), $api->getLanguage() ); diff --git a/repo/tests/phpunit/includes/content/SiteLinkUniquenessValidatorTest.php b/repo/tests/phpunit/includes/content/SiteLinkUniquenessValidatorTest.php index aba13c7..ffb05fb 100644 --- a/repo/tests/phpunit/includes/content/SiteLinkUniquenessValidatorTest.php +++ b/repo/tests/phpunit/includes/content/SiteLinkUniquenessValidatorTest.php @@ -10,7 +10,6 @@ use Wikibase\DataModel\Entity\Item; use Wikibase\DataModel\Entity\ItemId; use Wikibase\DataModel\SiteLink; -use Wikibase\EntityTitleLookup; use Wikibase\SiteLinkLookup; /** @@ -54,19 +53,6 @@ } /** - * @return EntityTitleLookup - */ - private function getMockTitleLookup() { - $termIndex = $this->getMock( 'Wikibase\EntityTitleLookup' ); - - $termIndex->expects( $this->any() ) - ->method( 'getTitleForId' ) - ->will( $this->returnCallback( array( $this, 'getTitleForId' ) ) ); - - return $termIndex; - } - - /** * @return SiteLinkLookup */ private function getMockSiteLinkLookup() { @@ -75,19 +61,6 @@ $termIndex->expects( $this->any() ) ->method( 'getConflictsForItem' ) ->will( $this->returnCallback( array( $this, 'getConflictsForItem' ) ) ); - - return $termIndex; - } - - /** - * @return SiteLinkLookup - */ - private function getMockSiteStore() { - $termIndex = $this->getMock( '\SiteStore' ); - - $termIndex->expects( $this->any() ) - ->method( 'getSite' ) - ->will( $this->returnCallback( array( $this, 'getSite' ) ) ); return $termIndex; } @@ -108,7 +81,7 @@ $badEntity->addSiteLink( new SiteLink( 'testwiki', 'DUPE' ) ); return array( - array( $badEntity, 'sitelink-already-used' ), + array( $badEntity, 'sitelink-conflict' ), ); } @@ -118,11 +91,9 @@ * @param Entity $entity */ public function testValidateEntity( Entity $entity ) { - $titleLookup = $this->getMockTitleLookup(); $siteLinkLookup = $this->getMockSiteLinkLookup(); - $siteStore = $this->getMockSiteStore(); - $validator = new SiteLinkUniquenessValidator( $titleLookup, $siteLinkLookup, $siteStore ); + $validator = new SiteLinkUniquenessValidator( $siteLinkLookup ); $result = $validator->validateEntity( $entity ); @@ -136,11 +107,9 @@ * @param string $error */ public function testValidateEntity_failure( Entity $entity, $error ) { - $titleLookup = $this->getMockTitleLookup(); $siteLinkLookup = $this->getMockSiteLinkLookup(); - $siteStore = $this->getMockSiteStore(); - $validator = new SiteLinkUniquenessValidator( $titleLookup, $siteLinkLookup, $siteStore ); + $validator = new SiteLinkUniquenessValidator( $siteLinkLookup ); $result = $validator->validateEntity( $entity ); -- To view, visit https://gerrit.wikimedia.org/r/128938 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I2240d6e0ced47fc2ab1eb5795073c185e6ad336f Gerrit-PatchSet: 7 Gerrit-Project: mediawiki/extensions/Wikibase Gerrit-Branch: master Gerrit-Owner: Daniel Kinzler <daniel.kinz...@wikimedia.de> Gerrit-Reviewer: Addshore <addshorew...@gmail.com> Gerrit-Reviewer: Adrian Lang <adrian.l...@wikimedia.de> Gerrit-Reviewer: Aude <aude.w...@gmail.com> Gerrit-Reviewer: Daniel Kinzler <daniel.kinz...@wikimedia.de> Gerrit-Reviewer: Hoo man <h...@online.de> Gerrit-Reviewer: Jeroen De Dauw <jeroended...@gmail.com> Gerrit-Reviewer: Siebrand <siebr...@kitano.nl> Gerrit-Reviewer: Thiemo Mättig (WMDE) <thiemo.maet...@wikimedia.de> Gerrit-Reviewer: WikidataJenkins <wikidata-servi...@wikimedia.de> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits