jenkins-bot has submitted this change and it was merged. Change subject: OutputFormatSnakFormatterFactory to construct SnakFormatter based on factory callbacks ......................................................................
OutputFormatSnakFormatterFactory to construct SnakFormatter based on factory callbacks This allows SnakFormatters to be defined dynamically, by registering a constructor callback, just like we do for ValueFormatters. Bug: T112754 Bug: T112755 Change-Id: Iff9f832be681b941093d5cfe1e53f709ac23cdd7 --- M client/includes/WikibaseClient.php M docs/datatypes.wiki M lib/includes/DataTypeDefinitions.php M lib/includes/formatters/OutputFormatSnakFormatterFactory.php M lib/tests/phpunit/DataTypeDefinitionsTest.php M lib/tests/phpunit/formatters/OutputFormatSnakFormatterFactoryTest.php M repo/includes/WikibaseRepo.php 7 files changed, 124 insertions(+), 15 deletions(-) Approvals: Thiemo Mättig (WMDE): Looks good to me, approved jenkins-bot: Verified diff --git a/client/includes/WikibaseClient.php b/client/includes/WikibaseClient.php index 07c9f1b..b92ca27 100644 --- a/client/includes/WikibaseClient.php +++ b/client/includes/WikibaseClient.php @@ -588,6 +588,7 @@ */ private function newSnakFormatterFactory() { $factory = new OutputFormatSnakFormatterFactory( + $this->dataTypeDefinitions->getSnakFormatterFactoryCallbacks(), $this->getValueFormatterFactory(), $this->getPropertyDataTypeLookup(), $this->getDataTypeFactory() diff --git a/docs/datatypes.wiki b/docs/datatypes.wiki index 1a6a152..05064e8 100644 --- a/docs/datatypes.wiki +++ b/docs/datatypes.wiki @@ -41,6 +41,7 @@ * validator-factory-callback (repo only): a callable that acts as a factory for the list of validators that should be used to check any user supplied values of the given data type. The callable will be called without any arguments, and must return a list of ValueValidator objects. * parser-factory-callback (repo only): a callable that acts as a factory for a ValueParser for this data type. * formatter-factory-callback (repo and client): a callable that acts as a factory for ValueFormatters for use with this data type. +* snak-formatter-factory-callback (repo and client): a callable that acts as a factory for SnakFormatters for use with this data type. If not defined, a SnakFormatter is created from the ValueFormatter for the given data type. * rdf-builder-factory-callback (repo only): a callable that acts as a factory for ValueSnakRdfBuilder for use with this data type. Since for each property data type the associated value type is known, this provides a convenient diff --git a/lib/includes/DataTypeDefinitions.php b/lib/includes/DataTypeDefinitions.php index 2f89ce8..aa292fd 100644 --- a/lib/includes/DataTypeDefinitions.php +++ b/lib/includes/DataTypeDefinitions.php @@ -242,6 +242,15 @@ } /** + * @see OutputFormatSnakFormatterFactory + * + * @return callable[] + */ + public function getSnakFormatterFactoryCallbacks() { + return $this->getMapForDefinitionField( 'snak-formatter-factory-callback' ); + } + + /** * @see ValueSnakRdfBuilderFactory * * @param string $mode PREFIXED_MODE to request a callback map with "VT:" and "PT:" prefixes diff --git a/lib/includes/formatters/OutputFormatSnakFormatterFactory.php b/lib/includes/formatters/OutputFormatSnakFormatterFactory.php index bf03a82..e7a5085 100644 --- a/lib/includes/formatters/OutputFormatSnakFormatterFactory.php +++ b/lib/includes/formatters/OutputFormatSnakFormatterFactory.php @@ -10,9 +10,12 @@ use ValueFormatters\ValueFormatter; use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookup; use Wikibase\Lib\Formatters\ErrorHandlingSnakFormatter; +use Wikimedia\Assert\Assert; /** - * Service for obtaining a SnakFormatter for a desired output format. + * Factory service for obtaining a SnakFormatter for a desired output format. + * Implemented based on constructor callbacks and a default SnakFormatter implementation + * that uses TypedValueFormatters. * * @license GPL 2+ * @author Daniel Kinzler @@ -35,18 +38,35 @@ private $propertyDataTypeLookup; /** + * @var callable[] + */ + private $snakFormatterConstructorCallbacks; + + /** + * @param callable[] $snakFormatterConstructorCallbacks An associative array mapping property + * data type IDs to callbacks. The callbacks will be invoked with two parameters: the + * desired output format, and the FormatterOptions. Each callback must return an + * instance of SnakFormatter. * @param OutputFormatValueFormatterFactory $valueFormatterFactory * @param PropertyDataTypeLookup $propertyDataTypeLookup * @param DataTypeFactory $dataTypeFactory */ public function __construct( + array $snakFormatterConstructorCallbacks, OutputFormatValueFormatterFactory $valueFormatterFactory, PropertyDataTypeLookup $propertyDataTypeLookup, DataTypeFactory $dataTypeFactory ) { + Assert::parameterElementType( + 'callable', + $snakFormatterConstructorCallbacks, + '$snakFormatterConstructorCallbacks' + ); + $this->valueFormatterFactory = $valueFormatterFactory; - $this->dataTypeFactory = $dataTypeFactory; $this->propertyDataTypeLookup = $propertyDataTypeLookup; + $this->dataTypeFactory = $dataTypeFactory; + $this->snakFormatterConstructorCallbacks = $snakFormatterConstructorCallbacks; } /** @@ -92,10 +112,10 @@ // for 'value' snaks, rely on $formattersByDataType ); - $formattersByDataType = array( - // TODO: get specialized SnakFormatters from factory functions. - '*' => $valueSnakFormatter - ); + $formattersByDataType = $this->createSnakFormatters( $format, $options ); + + // Register default formatter for the special '*' key. + $formattersByDataType['*'] = $valueSnakFormatter; $snakFormatter = new DispatchingSnakFormatter( $format, @@ -127,4 +147,31 @@ return $msg; } + /** + * Instantiate SnakFormatters based on the constructor callbacks passed to the constructor. + * + * @param string $format + * @param FormatterOptions $options + * + * @return SnakFormatter[] + */ + private function createSnakFormatters( $format, FormatterOptions $options ) { + $formatters = array(); + + foreach ( $this->snakFormatterConstructorCallbacks as $key => $callback ) { + $instance = call_user_func( $callback, $format, $options ); + + Assert::postcondition( + $instance instanceof SnakFormatter, + "Constructor callback did not return a SnakFormatter for $key" + ); + + $formatters[$key] = $instance; + } + + //FIXME: format fallback via escaping, as implemented in OutputFormatValueFormatterFactory! + + return $formatters; + } + } diff --git a/lib/tests/phpunit/DataTypeDefinitionsTest.php b/lib/tests/phpunit/DataTypeDefinitionsTest.php index b952667..569dfb4 100644 --- a/lib/tests/phpunit/DataTypeDefinitionsTest.php +++ b/lib/tests/phpunit/DataTypeDefinitionsTest.php @@ -27,6 +27,7 @@ 'value-type' => 'FOO', 'validator-factory-callback' => 'DataTypeDefinitionsTest::getFooValidators', 'parser-factory-callback' => 'DataTypeDefinitionsTest::getFooParser', + 'snak-formatter-factory-callback' => 'DataTypeDefinitionsTest::getFooSnakFormatter', ), 'PT:bar' => array( 'value-type' => 'BAR', diff --git a/lib/tests/phpunit/formatters/OutputFormatSnakFormatterFactoryTest.php b/lib/tests/phpunit/formatters/OutputFormatSnakFormatterFactoryTest.php index 3613d86..5eee006 100644 --- a/lib/tests/phpunit/formatters/OutputFormatSnakFormatterFactoryTest.php +++ b/lib/tests/phpunit/formatters/OutputFormatSnakFormatterFactoryTest.php @@ -11,6 +11,7 @@ use ValueFormatters\ValueFormatter; use Wikibase\DataModel\Entity\PropertyId; use Wikibase\DataModel\Snak\PropertyValueSnak; +use Wikibase\DataModel\Snak\Snak; use Wikibase\LanguageFallbackChainFactory; use Wikibase\Lib\OutputFormatSnakFormatterFactory; use Wikibase\Lib\OutputFormatValueFormatterFactory; @@ -29,15 +30,22 @@ */ class OutputFormatSnakFormatterFactoryTest extends \PHPUnit_Framework_TestCase { - private function newOutputFormatSnakFormatterFactory() { + private function newOutputFormatSnakFormatterFactory( $dataType = 'string' ) { $self = $this; - $callbacks = array( + + $snakFormatterCallbacks = array( + 'commonsMedia' => function( $format, FormatterOptions $options ) use ( $self ) { + return $self->makeMockSnakFormatter( $format ); + }, + ); + + $valueFormatterCallbacks = array( 'VT:string' => function( $format, FormatterOptions $options ) use ( $self ) { return $self->makeMockValueFormatter( $format ); }, ); $valueFormatterFactory = new OutputFormatValueFormatterFactory( - $callbacks, + $valueFormatterCallbacks, Language::factory( 'en' ), new LanguageFallbackChainFactory() ); @@ -47,12 +55,13 @@ ); $dataTypeLookup->expects( $this->any() ) ->method( 'getDataTypeIdForProperty' ) - ->will( $this->returnValue( 'string' ) ); + ->will( $this->returnValue( $dataType ) ); return new OutputFormatSnakFormatterFactory( + $snakFormatterCallbacks, $valueFormatterFactory, $dataTypeLookup, - new DataTypeFactory( array( 'string' => 'string' ) ) + new DataTypeFactory( array( 'string' => 'string', 'commonsMedia' => 'string' ) ) ); } @@ -70,17 +79,55 @@ return $mock; } + public function makeMockSnakFormatter( $format ) { + $mock = $this->getMock( 'Wikibase\Lib\SnakFormatter' ); + + $mock->expects( $this->any() ) + ->method( 'formatSnak' ) + ->will( $this->returnCallback( + function( Snak $snak ) use ( $format ) { + $s = $snak->getType() . '/' . $snak->getPropertyId(); + + if ( $snak instanceof PropertyValueSnak ) { + $s .= '=' . strval( $snak->getDataValue()->getValue() ); + } + + return $s . ' (' . $format . ')'; + } + ) ); + + $mock->expects( $this->any() ) + ->method( 'getFormat' ) + ->will( $this->returnValue( $format ) ); + + return $mock; + } + public function getSnakFormatterProvider() { return array( - 'plain' => array( + 'plain value' => array( SnakFormatter::FORMAT_PLAIN, + 'string', new StringValue( 'foo' ), 'foo (text/plain)', ), - 'html' => array( + 'html value' => array( SnakFormatter::FORMAT_HTML, + 'string', new StringValue( 'foo' ), 'foo (text/html)', + ), + 'plain snak' => array( + SnakFormatter::FORMAT_PLAIN, + 'commonsMedia', // the mock has a SnakFormatter for commonsMedia + new StringValue( 'foo.jpg' ), + 'value/P5=foo.jpg (text/plain)', + ), + 'html snak' => array( + SnakFormatter::FORMAT_HTML, + 'commonsMedia', // the mock has a SnakFormatter for commonsMedia + new StringValue( 'foo.jpg' ), + 'value/P5=foo.jpg (text/html)', ), ); } @@ -88,8 +135,8 @@ /** * @dataProvider getSnakFormatterProvider */ - public function testGetSnakFormatter( $format, DataValue $value, $expected ) { - $factory = $this->newOutputFormatSnakFormatterFactory(); + public function testGetSnakFormatter( $format, $dataType, DataValue $value, $expected ) { + $factory = $this->newOutputFormatSnakFormatterFactory( $dataType ); $formatter = $factory->getSnakFormatter( $format, new FormatterOptions() ); $this->assertInstanceOf( 'Wikibase\Lib\SnakFormatter', $formatter ); @@ -144,6 +191,7 @@ ); $factory = new OutputFormatSnakFormatterFactory( + array(), $valueFormatterFactory, $this->getMock( 'Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookup' ), new DataTypeFactory( array() ) diff --git a/repo/includes/WikibaseRepo.php b/repo/includes/WikibaseRepo.php index 64ac2bd..84685aa 100644 --- a/repo/includes/WikibaseRepo.php +++ b/repo/includes/WikibaseRepo.php @@ -768,6 +768,7 @@ */ protected function newSnakFormatterFactory() { $factory = new OutputFormatSnakFormatterFactory( + $this->dataTypeDefinitions->getSnakFormatterFactoryCallbacks(), $this->getValueFormatterFactory(), $this->getPropertyDataTypeLookup(), $this->getDataTypeFactory() @@ -883,6 +884,7 @@ // Create a new SnakFormatterFactory based on the specialized ValueFormatterFactory. $snakFormatterFactory = new OutputFormatSnakFormatterFactory( + array(), // XXX: do we want $this->dataTypeDefinitions->getSnakFormatterFactoryCallbacks() $valueFormatterFactory, $this->getPropertyDataTypeLookup(), $this->getDataTypeFactory() -- To view, visit https://gerrit.wikimedia.org/r/253683 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Iff9f832be681b941093d5cfe1e53f709ac23cdd7 Gerrit-PatchSet: 14 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.he...@wikimedia.de> Gerrit-Reviewer: Aude <aude.w...@gmail.com> Gerrit-Reviewer: Daniel Kinzler <daniel.kinz...@wikimedia.de> Gerrit-Reviewer: Jonas Kress (WMDE) <jonas.kr...@wikimedia.de> Gerrit-Reviewer: Thiemo Mättig (WMDE) <thiemo.maet...@wikimedia.de> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits