jenkins-bot has submitted this change and it was merged. Change subject: Introduce SnakRdfBuilder. ......................................................................
Introduce SnakRdfBuilder. Factor common code out of FullStatementRdfBuilder and TruthyStatementRdfBuilder. Introduce DataValueRdfBuilder interface to replace SnakValueRdfBuilder. This is done in preparation for introducing a registry for DataValueRdfBuilders for different data types, instead of hardcoding handling for all known types directly. Change-Id: I946f4593895c49c937bad0c0c66e1cf0e932ad2a --- M repo/includes/rdf/ComplexValueRdfBuilder.php A repo/includes/rdf/DataValueRdfBuilder.php M repo/includes/rdf/FullStatementRdfBuilder.php M repo/includes/rdf/RdfBuilder.php M repo/includes/rdf/SimpleValueRdfBuilder.php A repo/includes/rdf/SnakRdfBuilder.php D repo/includes/rdf/SnakValueRdfBuilder.php M repo/includes/rdf/TruthyStatementRdfBuilder.php M repo/tests/phpunit/includes/rdf/ComplexValueRdfBuilderTest.php M repo/tests/phpunit/includes/rdf/FullStatementsRdfBuilderTest.php M repo/tests/phpunit/includes/rdf/SimpleValueRdfBuilderTest.php A repo/tests/phpunit/includes/rdf/SnakRdfBuilderTest.php M repo/tests/phpunit/includes/rdf/TruthyStatementsRdfBuilderTest.php 13 files changed, 472 insertions(+), 207 deletions(-) Approvals: Hoo man: Looks good to me, approved jenkins-bot: Verified diff --git a/repo/includes/rdf/ComplexValueRdfBuilder.php b/repo/includes/rdf/ComplexValueRdfBuilder.php index e929fde..4f71190 100644 --- a/repo/includes/rdf/ComplexValueRdfBuilder.php +++ b/repo/includes/rdf/ComplexValueRdfBuilder.php @@ -63,8 +63,8 @@ * @param string $dataType Property data type * @param DataValue $value */ - protected function addValueForDataType( RdfWriter $writer, $propertyValueNamespace, $propertyValueLName, $dataType, $value ) { - parent::addValueForDataType( $writer, $propertyValueNamespace, $propertyValueLName, $dataType, $value ); + public function addValue( RdfWriter $writer, $propertyValueNamespace, $propertyValueLName, $dataType, $value ) { + parent::addValue( $writer, $propertyValueNamespace, $propertyValueLName, $dataType, $value ); switch ( $value->getType() ) { case 'time': diff --git a/repo/includes/rdf/DataValueRdfBuilder.php b/repo/includes/rdf/DataValueRdfBuilder.php new file mode 100644 index 0000000..a442d83 --- /dev/null +++ b/repo/includes/rdf/DataValueRdfBuilder.php @@ -0,0 +1,36 @@ +<?php + +namespace Wikibase\Rdf; + +use DataValues\DataValue; +use Wikimedia\Purtle\RdfWriter; + +/** + * Interface for RDF mapping for wikibase data values. + * + * @since 0.5 + * + * @licence GNU GPL v2+ + * @author Daniel Kinzler + * @author Stas Malyshev + */ +interface DataValueRdfBuilder { + + /** + * Adds specific value + * + * @param RdfWriter $writer + * @param string $propertyValueNamespace Property value relation namespace + * @param string $propertyValueLName Property value relation name + * @param string $dataType Property data type + * @param DataValue $value + */ + public function addValue( + RdfWriter $writer, + $propertyValueNamespace, + $propertyValueLName, + $dataType, + $value + ); + +} diff --git a/repo/includes/rdf/FullStatementRdfBuilder.php b/repo/includes/rdf/FullStatementRdfBuilder.php index cd6dd25..625376d 100644 --- a/repo/includes/rdf/FullStatementRdfBuilder.php +++ b/repo/includes/rdf/FullStatementRdfBuilder.php @@ -2,12 +2,9 @@ namespace Wikibase\Rdf; -use InvalidArgumentException; use Wikibase\DataModel\Entity\EntityDocument; use Wikibase\DataModel\Entity\EntityId; use Wikibase\DataModel\Reference; -use Wikibase\DataModel\Snak\PropertyValueSnak; -use Wikibase\DataModel\Snak\Snak; use Wikibase\DataModel\Statement\Statement; use Wikibase\DataModel\Statement\StatementList; use Wikibase\DataModel\Statement\StatementListProvider; @@ -29,11 +26,6 @@ * @author Stas Malyshev */ class FullStatementRdfBuilder implements EntityRdfBuilder { - - /** - * @var EntityMentionListener - */ - private $mentionedEntityTracker; /** * @var DedupeBag @@ -66,16 +58,16 @@ private $referenceWriter; /** - * @var SnakValueRdfBuilder + * @var SnakRdfBuilder */ - private $valueBuilder; + private $snakBuilder; /** * @param RdfVocabulary $vocabulary * @param RdfWriter $writer - * @param SnakValueRdfBuilder $valueBuilder + * @param SnakRdfBuilder $snakBuilder */ - public function __construct( RdfVocabulary $vocabulary, RdfWriter $writer, SnakValueRdfBuilder $valueBuilder ) { + public function __construct( RdfVocabulary $vocabulary, RdfWriter $writer, SnakRdfBuilder $snakBuilder ) { $this->vocabulary = $vocabulary; // Note: since we process references as nested structures, they need a separate @@ -83,24 +75,9 @@ $this->statementWriter = $writer; $this->referenceWriter = $writer->sub(); - $this->valueBuilder = $valueBuilder; + $this->snakBuilder = $snakBuilder; - $this->mentionedEntityTracker = new NullEntityMentionListener(); $this->dedupeBag = new NullDedupeBag(); - } - - /** - * @return EntityMentionListener - */ - public function getEntityMentionListener() { - return $this->mentionedEntityTracker; - } - - /** - * @param EntityMentionListener $mentionedEntityTracker - */ - public function setEntityMentionListener( $mentionedEntityTracker ) { - $this->mentionedEntityTracker = $mentionedEntityTracker; } /** @@ -182,7 +159,7 @@ if ( $this->produceQualifiers ) { // this assumes statement was added by addMainSnak foreach ( $statement->getQualifiers() as $q ) { - $this->addSnak( $this->statementWriter, $q, RdfVocabulary::NSP_QUALIFIER ); + $this->snakBuilder->addSnak( $this->statementWriter, $q, RdfVocabulary::NSP_QUALIFIER ); } } @@ -203,7 +180,7 @@ ->a( RdfVocabulary::NS_ONTOLOGY, 'Reference' ); foreach ( $reference->getSnaks() as $refSnak ) { - $this->addSnak( $this->referenceWriter, $refSnak, RdfVocabulary::NSP_REFERENCE ); + $this->snakBuilder->addSnak( $this->referenceWriter, $refSnak, RdfVocabulary::NSP_REFERENCE ); } } } @@ -240,42 +217,7 @@ wfLogWarning( "Unknown rank $rank encountered for $entityId:{$statement->getGuid()}" ); } - $this->addSnak( $this->statementWriter, $snak, RdfVocabulary::NSP_CLAIM_STATEMENT ); - $this->mentionedEntityTracker->propertyMentioned( $snak->getPropertyId() ); - - } - - /** - * Adds the given Statement's main Snak to the RDF graph. - * - * @todo share more of this code with TruthyStatementRdfBuilder - * - * @param RdfWriter $writer - * @param Snak $snak - * @param string $propertyNamespace - * - * @throws InvalidArgumentException - */ - private function addSnak( RdfWriter $writer, Snak $snak, $propertyNamespace ) { - $propertyId = $snak->getPropertyId(); - switch ( $snak->getType() ) { - case 'value': - /** @var PropertyValueSnak $snak */ - $this->valueBuilder->addSnakValue( $writer, $propertyId, $snak->getDataValue(), $propertyNamespace ); - break; - case 'somevalue': - $propertyValueLName = $this->vocabulary->getEntityLName( $propertyId ); - - $writer->say( $propertyNamespace, $propertyValueLName )->is( '_', $writer->blank() ); - break; - case 'novalue': - $propertyValueLName = $this->vocabulary->getEntityLName( $propertyId ); - - $writer->say( 'a' )->is( RdfVocabulary::NSP_NOVALUE, $propertyValueLName ); - break; - default: - throw new InvalidArgumentException( 'Unknown snak type: ' . $snak->getType() ); - } + $this->snakBuilder->addSnak( $this->statementWriter, $snak, RdfVocabulary::NSP_CLAIM_STATEMENT ); } /** diff --git a/repo/includes/rdf/RdfBuilder.php b/repo/includes/rdf/RdfBuilder.php index 50c23ea..4255c9c 100644 --- a/repo/includes/rdf/RdfBuilder.php +++ b/repo/includes/rdf/RdfBuilder.php @@ -119,7 +119,7 @@ } /** - * @return SnakValueRdfBuilder + * @return DataValueRdfBuilder */ private function newSimpleValueRdfBuilder() { $simpleValueBuilder = new SimpleValueRdfBuilder( $this->vocabulary, $this->propertyLookup ); @@ -129,21 +129,33 @@ } /** - * @return SnakValueRdfBuilder + * @return DataValueRdfBuilder */ - private function newSnakValueBuilder() { - if ( $this->shouldProduce( RdfProducer::PRODUCE_FULL_VALUES ) ) { - // NOTE: use sub-writers for nested structures - $valueWriter = $this->writer->sub(); + private function newComplexValueRdfBuilder() { + // NOTE: use sub-writers for nested structures + $valueWriter = $this->writer->sub(); - $statementValueBuilder = new ComplexValueRdfBuilder( $this->vocabulary, $valueWriter, $this->propertyLookup ); - $statementValueBuilder->setDedupeBag( $this->dedupBag ); - $statementValueBuilder->setEntityMentionListener( $this ); + $statementValueBuilder = new ComplexValueRdfBuilder( $this->vocabulary, $valueWriter, $this->propertyLookup ); + $statementValueBuilder->setDedupeBag( $this->dedupBag ); + $statementValueBuilder->setEntityMentionListener( $this ); + + return $statementValueBuilder; + } + + /** + * @return SnakRdfBuilder + */ + private function newSnakBuilder( $full ) { + if ( $full === 'full' ) { + $statementValueBuilder = $this->newComplexValueRdfBuilder(); } else { $statementValueBuilder = $this->newSimpleValueRdfBuilder(); } - return $statementValueBuilder; + $snakBuilder = new SnakRdfBuilder( $this->vocabulary, $statementValueBuilder, $this->propertyLookup ); + $snakBuilder->setEntityMentionListener( $this ); + + return $snakBuilder; } /** @@ -151,8 +163,8 @@ */ private function newTruthyStatementRdfBuilder() { //NOTE: currently, the only simple values are supported in truthy mode! - $simpleValueBuilder = $this->newSimpleValueRdfBuilder(); - $statementBuilder = new TruthyStatementRdfBuilder( $this->vocabulary, $this->writer, $simpleValueBuilder ); + $simpleSnakBuilder = $this->newSnakBuilder( 'simple' ); + $statementBuilder = new TruthyStatementRdfBuilder( $this->vocabulary, $this->writer, $simpleSnakBuilder ); return $statementBuilder; } @@ -161,11 +173,10 @@ * @return EntityRdfBuilder */ private function newFullStatementRdfBuilder() { - $statementValueBuilder = $this->newSnakValueBuilder(); + $statementValueBuilder = $this->newSnakBuilder( $this->shouldProduce( RdfProducer::PRODUCE_FULL_VALUES ) ? 'full' : 'simple' ); $statementBuilder = new FullStatementRdfBuilder( $this->vocabulary, $this->writer, $statementValueBuilder ); $statementBuilder->setDedupeBag( $this->dedupBag ); - $statementBuilder->setEntityMentionListener( $this ); $statementBuilder->setProduceQualifiers( $this->shouldProduce( RdfProducer::PRODUCE_QUALIFIERS ) ); $statementBuilder->setProduceReferences( $this->shouldProduce( RdfProducer::PRODUCE_REFERENCES ) ); diff --git a/repo/includes/rdf/SimpleValueRdfBuilder.php b/repo/includes/rdf/SimpleValueRdfBuilder.php index c9b0358..ad0eeae 100644 --- a/repo/includes/rdf/SimpleValueRdfBuilder.php +++ b/repo/includes/rdf/SimpleValueRdfBuilder.php @@ -10,9 +10,7 @@ use DataValues\StringValue; use DataValues\TimeValue; use Wikibase\DataModel\Entity\EntityIdValue; -use Wikibase\DataModel\Entity\PropertyId; use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookup; -use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookupException; use Wikimedia\Purtle\RdfWriter; /** @@ -24,22 +22,12 @@ * @author Daniel Kinzler * @author Stas Malyshev */ -class SimpleValueRdfBuilder implements SnakValueRdfBuilder { +class SimpleValueRdfBuilder implements DataValueRdfBuilder { /** * @var EntityMentionListener */ private $mentionedEntityTracker; - - /** - * @var RdfVocabulary - */ - protected $vocabulary; - - /** - * @var PropertyDataTypeLookup - */ - private $propertyLookup; /** * @var DateTimeValueCleaner @@ -74,38 +62,6 @@ } /** - * Adds the value of the given property to the RDF graph. - * - * @param RdfWriter $writer - * @param PropertyId $propertyId - * @param DataValue $value - * @param string $propertyNamespace The property namespace for this snak - */ - public function addSnakValue( - RdfWriter $writer, - PropertyId $propertyId, - DataValue $value, - $propertyNamespace - ) { - $propertyValueLName = $this->vocabulary->getEntityLName( $propertyId ); - - $typeId = $value->getType(); - $dataType = null; - - if ( $typeId === 'string' ) { - // We only care about the actual data type of strings, so we can save time but not asking - // for any other types - try { - $dataType = $this->propertyLookup->getDataTypeIdForProperty( $propertyId ); - } catch ( PropertyDataTypeLookupException $e ) { - // keep "unknown" - } - } - - $this->addValueForDataType( $writer, $propertyNamespace, $propertyValueLName, $dataType, $value ); - } - - /** * Adds specific value * * @param RdfWriter $writer @@ -114,7 +70,7 @@ * @param string $dataType Property data type * @param DataValue $value */ - protected function addValueForDataType( + public function addValue( RdfWriter $writer, $propertyValueNamespace, $propertyValueLName, diff --git a/repo/includes/rdf/SnakRdfBuilder.php b/repo/includes/rdf/SnakRdfBuilder.php new file mode 100644 index 0000000..6ddb205 --- /dev/null +++ b/repo/includes/rdf/SnakRdfBuilder.php @@ -0,0 +1,137 @@ +<?php + +namespace Wikibase\Rdf; + +use DataValues\DataValue; +use InvalidArgumentException; +use Wikibase\DataModel\Entity\PropertyId; +use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookup; +use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookupException; +use Wikibase\DataModel\Snak\PropertyValueSnak; +use Wikibase\DataModel\Snak\Snak; +use Wikimedia\Purtle\RdfWriter; + +/** + * Implementation for RDF mapping for Snaks. + * + * @since 0.5 + * + * @licence GNU GPL v2+ + * @author Daniel Kinzler + * @author Stas Malyshev + */ +class SnakRdfBuilder { + + /** + * @var EntityMentionListener + */ + private $mentionedEntityTracker; + + /** + * @var RdfVocabulary + */ + private $vocabulary; + + /** + * @var DataValueRdfBuilder + */ + private $valueBuilder; + + /** + * @var PropertyDataTypeLookup + */ + private $propertyLookup; + + /** + * @param RdfVocabulary $vocabulary + * @param DataValueRdfBuilder $valueBuilder + * @param PropertyDataTypeLookup $propertyLookup + */ + public function __construct( RdfVocabulary $vocabulary, DataValueRdfBuilder $valueBuilder, PropertyDataTypeLookup $propertyLookup ) { + $this->vocabulary = $vocabulary; + $this->valueBuilder = $valueBuilder; + $this->propertyLookup = $propertyLookup; + + $this->mentionedEntityTracker = new NullEntityMentionListener(); + } + + /** + * @return EntityMentionListener + */ + public function getEntityMentionListener() { + return $this->mentionedEntityTracker; + } + + /** + * @param EntityMentionListener $mentionedEntityTracker + */ + public function setEntityMentionListener( EntityMentionListener $mentionedEntityTracker ) { + $this->mentionedEntityTracker = $mentionedEntityTracker; + } + + /** + * Adds the given Statement's main Snak to the RDF graph. + * + * @param RdfWriter $writer + * @param Snak $snak + * @param string $propertyNamespace + * + * @throws InvalidArgumentException + */ + public function addSnak( RdfWriter $writer, Snak $snak, $propertyNamespace ) { + $propertyId = $snak->getPropertyId(); + switch ( $snak->getType() ) { + case 'value': + /** @var PropertyValueSnak $snak */ + $this->addSnakValue( $writer, $propertyId, $snak->getDataValue(), $propertyNamespace ); + break; + case 'somevalue': + $propertyValueLName = $this->vocabulary->getEntityLName( $propertyId ); + + $writer->say( $propertyNamespace, $propertyValueLName )->is( '_', $writer->blank() ); + break; + case 'novalue': + $propertyValueLName = $this->vocabulary->getEntityLName( $propertyId ); + + $writer->say( 'a' )->is( RdfVocabulary::NSP_NOVALUE, $propertyValueLName ); + break; + default: + throw new InvalidArgumentException( 'Unknown snak type: ' . $snak->getType() ); + } + + $this->mentionedEntityTracker->propertyMentioned( $snak->getPropertyId() ); + } + + /** + * Adds the value of the given property to the RDF graph. + * + * @param RdfWriter $writer + * @param PropertyId $propertyId + * @param DataValue $value + * @param string $propertyNamespace The property namespace for this snak + */ + private function addSnakValue( + RdfWriter $writer, + PropertyId $propertyId, + DataValue $value, + $propertyNamespace + ) { + $propertyValueLName = $this->vocabulary->getEntityLName( $propertyId ); + + $typeId = $value->getType(); + $dataType = null; + + if ( $typeId === 'string' ) { + // We only care about the actual data type of strings, so we can save time but not asking + // for any other types + try { + $dataType = $this->propertyLookup->getDataTypeIdForProperty( $propertyId ); + } catch ( PropertyDataTypeLookupException $e ) { + // keep "unknown" + } + } + + $this->valueBuilder->addValue( $writer, $propertyNamespace, $propertyValueLName, $dataType, $value ); + } + +} diff --git a/repo/includes/rdf/SnakValueRdfBuilder.php b/repo/includes/rdf/SnakValueRdfBuilder.php deleted file mode 100644 index aa71e62..0000000 --- a/repo/includes/rdf/SnakValueRdfBuilder.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php - -namespace Wikibase\Rdf; - -use DataValues\DataValue; -use Wikibase\DataModel\Entity\PropertyId; -use Wikimedia\Purtle\RdfWriter; - -/** - * Interface for RDF mapping for wikibase data values. - * - * @since 0.5 - * - * @licence GNU GPL v2+ - * @author Daniel Kinzler - * @author Stas Malyshev - */ -interface SnakValueRdfBuilder { - - /** - * Adds the value of the given property to the RDF graph. - * - * @param RdfWriter $writer entity-level writer - * @param PropertyId $propertyId - * @param DataValue $value - * @param string $propertyNamespace The property namespace for this snak - * - * @return - */ - public function addSnakValue( - RdfWriter $writer, - PropertyId $propertyId, - DataValue $value, - $propertyNamespace - ); - -} diff --git a/repo/includes/rdf/TruthyStatementRdfBuilder.php b/repo/includes/rdf/TruthyStatementRdfBuilder.php index 92e3f38..5f9992d 100644 --- a/repo/includes/rdf/TruthyStatementRdfBuilder.php +++ b/repo/includes/rdf/TruthyStatementRdfBuilder.php @@ -5,7 +5,6 @@ use InvalidArgumentException; use Wikibase\DataModel\Entity\EntityDocument; use Wikibase\DataModel\Entity\EntityId; -use Wikibase\DataModel\Snak\PropertyValueSnak; use Wikibase\DataModel\Statement\Statement; use Wikibase\DataModel\Statement\StatementList; use Wikibase\DataModel\Statement\StatementListProvider; @@ -43,19 +42,19 @@ private $writer; /** - * @var SnakValueRdfBuilder + * @var SnakRdfBuilder */ - private $valueBuilder; + private $snakBuilder; /** * @param RdfVocabulary $vocabulary * @param RdfWriter $writer - * @param SnakValueRdfBuilder $valueBuilder + * @param SnakRdfBuilder $snakBuilder */ - public function __construct( RdfVocabulary $vocabulary, RdfWriter $writer, SnakValueRdfBuilder $valueBuilder ) { + public function __construct( RdfVocabulary $vocabulary, RdfWriter $writer, SnakRdfBuilder $snakBuilder ) { $this->vocabulary = $vocabulary; $this->writer = $writer; - $this->valueBuilder = $valueBuilder; + $this->snakBuilder = $snakBuilder; } /** @@ -90,25 +89,7 @@ $this->writer->about( RdfVocabulary::NS_ENTITY, $entityLName ); - $propertyId = $snak->getPropertyId(); - switch ( $snak->getType() ) { - case 'value': - /** @var PropertyValueSnak $snak */ - $this->valueBuilder->addSnakValue( $this->writer, $propertyId, $snak->getDataValue(), RdfVocabulary::NSP_DIRECT_CLAIM ); - break; - case 'somevalue': - $propertyValueLName = $this->vocabulary->getEntityLName( $propertyId ); - - $this->writer->say( RdfVocabulary::NSP_DIRECT_CLAIM, $propertyValueLName )->is( '_', $this->writer->blank() ); - break; - case 'novalue': - $propertyValueLName = $this->vocabulary->getEntityLName( $propertyId ); - - $this->writer->say( 'a' )->is( RdfVocabulary::NSP_NOVALUE, $propertyValueLName ); - break; - default: - throw new InvalidArgumentException( 'Unknown snak type: ' . $snak->getType() ); - } + $this->snakBuilder->addSnak( $this->writer, $snak, RdfVocabulary::NSP_DIRECT_CLAIM ); } /** diff --git a/repo/tests/phpunit/includes/rdf/ComplexValueRdfBuilderTest.php b/repo/tests/phpunit/includes/rdf/ComplexValueRdfBuilderTest.php index e91955d..2af4884 100644 --- a/repo/tests/phpunit/includes/rdf/ComplexValueRdfBuilderTest.php +++ b/repo/tests/phpunit/includes/rdf/ComplexValueRdfBuilderTest.php @@ -109,12 +109,13 @@ $this->assertEquals( $expectedTriples, $actualTripels ); } - public function provideAddSnakValue() { + public function provideAddValue() { // NOTE: data types must match $this->getTestData()->getMockRepository(); return array( 'wikibase-entityid' => array( new PropertyId( 'P2' ), + 'wikibase-item', new EntityIdValue( new ItemId( 'Q42' ) ), array( '<http://acme.test/Q11> <http://acme.test/prop/statement/P2> <http://acme.test/Q42> .', @@ -123,6 +124,7 @@ ), 'commonsMedia' => array( new PropertyId( 'P3' ), + 'commonsMedia', new StringValue( 'Test.jpg' ), array( '<http://acme.test/Q11> <http://acme.test/prop/statement/P3> <http://commons.wikimedia.org/wiki/Special:FilePath/Test.jpg> .', @@ -131,6 +133,7 @@ ), 'globecoordinate' => array( new PropertyId( 'P4' ), + 'globecoordinate', new GlobeCoordinateValue( new LatLongValue( 12.25, -45.5 ), 0.025, @@ -164,6 +167,7 @@ ), 'monolingualtext' => array( new PropertyId( 'P5' ), + 'monolingualtext', new MonolingualTextValue( 'ru', 'Берлин' ), array( '<http://acme.test/Q11> <http://acme.test/prop/statement/P5> "\u0411\u0435\u0440\u043B\u0438\u043D"@ru .', @@ -172,6 +176,7 @@ ), 'quantity' => array( new PropertyId( 'P6' ), + 'quantity', new QuantityValue( new DecimalValue( '+0.00011' ), '1', @@ -200,6 +205,7 @@ ), 'quantity-unit' => array( new PropertyId( 'P6' ), + 'quantity', new QuantityValue( new DecimalValue( '-2.3' ), 'https://www.wikidata.org/entity/Q11573', @@ -229,6 +235,7 @@ ), 'string' => array( new PropertyId( 'P7' ), + 'string', new StringValue( 'Kittens' ), array( '<http://acme.test/Q11> <http://acme.test/prop/statement/P7> "Kittens" .', @@ -237,6 +244,7 @@ ), 'time' => array( new PropertyId( 'P8' ), + 'time', new TimeValue( '+2015-03-03T00:00:00Z', 0, 0, 0, TimeValue::PRECISION_DAY, RdfVocabulary::GREGORIAN_CALENDAR ), array( '<http://acme.test/Q11> <http://acme.test/prop/statement/P8> "2015-03-03T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .', @@ -262,6 +270,7 @@ ), 'time-year' => array( // NOTE: may changed to use xsd:gYear new PropertyId( 'P8' ), + 'time', new TimeValue( '+2015-00-00T00:00:00Z', 0, 0, 0, TimeValue::PRECISION_YEAR, RdfVocabulary::GREGORIAN_CALENDAR ), array( '<http://acme.test/Q11> <http://acme.test/prop/statement/P8> "2015-01-01T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .', @@ -287,6 +296,7 @@ ), 'time-margin' => array( new PropertyId( 'P8' ), + 'time', new TimeValue( '+2015-03-03T00:00:00Z', 0, 3, 3, TimeValue::PRECISION_DAY, RdfVocabulary::GREGORIAN_CALENDAR ), array( '<http://acme.test/Q11> <http://acme.test/prop/statement/P8> "2015-03-03T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .', @@ -316,6 +326,7 @@ // XSD 1.1 uses astronomical numbering (-44 means 43 BCE), // conversion would apply. new PropertyId( 'P8' ), + 'time', new TimeValue( '-0044-03-15T00:00:00Z', 0, 3, 3, TimeValue::PRECISION_DAY, RdfVocabulary::GREGORIAN_CALENDAR ), array( '<http://acme.test/Q11> <http://acme.test/prop/statement/P8> "-0043-03-15T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .', @@ -340,6 +351,7 @@ // are known, they could be converted to (proleptic) // gregorian an output as an XSD date. new PropertyId( 'P8' ), + 'time', new TimeValue( '+1492-10-12T00:00:00Z', 0, 0, 0, TimeValue::PRECISION_DAY, RdfVocabulary::JULIAN_CALENDAR ), array( // Julian-to-Gregorian conversion applies. @@ -366,6 +378,7 @@ ), 'url' => array( new PropertyId( 'P9' ), + 'url', new StringValue( 'http://quux.test/xyzzy' ), array( '<http://acme.test/Q11> <http://acme.test/prop/statement/P9> <http://quux.test/xyzzy> .', @@ -374,6 +387,7 @@ ), 'url-mailto' => array( new PropertyId( 'P9' ), + 'url', new StringValue( 'mailto:xy...@quux.test' ), array( '<http://acme.test/Q11> <http://acme.test/prop/statement/P9> <mailto:xy...@quux.test> .', @@ -384,14 +398,14 @@ } /** - * @dataProvider provideAddSnakValue + * @dataProvider provideAddValue */ - public function testAddSnakValue( PropertyId $propertyId, DataValue $value, array $expectedTriples, array $expectedValueTriples ) { + public function testAddValue( PropertyId $propertyId, $dataType, DataValue $value, array $expectedTriples, array $expectedValueTriples ) { $writer = $this->getTestData()->getNTriplesWriter(); $writer->about( RdfVocabulary::NS_ENTITY, 'Q11' ); $builder = $this->newBuilder(); - $builder->addSnakValue( $writer, $propertyId, $value, RdfVocabulary::NSP_CLAIM_STATEMENT ); + $builder->addValue( $writer, RdfVocabulary::NSP_CLAIM_STATEMENT, $propertyId->getSerialization(), $dataType, $value ); $this->assertTriplesEqual( $expectedTriples, $writer ); @@ -399,8 +413,9 @@ $this->assertTriplesEqual( $expectedValueTriples, $builder->test_value_writer ); } - public function testAddSnakValue_mention() { + public function testAddValue_mention() { $propertyId = new PropertyId( 'P2' ); + $dataType = 'wikibase-item'; $value = new EntityIdValue( new ItemId( 'Q42' ) ); $writer = $this->getTestData()->getNTriplesWriter(); @@ -408,14 +423,15 @@ $mentioned = array(); $builder = $this->newBuilder( $mentioned ); - $builder->addSnakValue( $writer, $propertyId, $value, RdfVocabulary::NSP_CLAIM_STATEMENT ); + $builder->addValue( $writer, RdfVocabulary::NSP_CLAIM_STATEMENT, $propertyId->getSerialization(), $dataType, $value ); $this->assertEquals( array( 'Q42' ), array_keys( $mentioned ) ); } - public function testAddSnakValue_seen() { + public function testAddValue_seen() { $propertyId = new PropertyId( 'P8' ); $value = new TimeValue( '+2015-03-03T00:00:00Z', 0, 0, 0, TimeValue::PRECISION_DAY, RdfVocabulary::GREGORIAN_CALENDAR ); + $dataType = 'time'; $writer = $this->getTestData()->getNTriplesWriter(); $writer->about( RdfVocabulary::NS_ENTITY, 'Q11' ); @@ -426,7 +442,7 @@ $seen->alreadySeen( $value->getHash(), 'V' ); $builder = $this->newBuilder( $mentioned, $seen ); - $builder->addSnakValue( $writer, $propertyId, $value, RdfVocabulary::NSP_CLAIM_STATEMENT ); + $builder->addValue( $writer, RdfVocabulary::NSP_CLAIM_STATEMENT, $propertyId->getSerialization(), $dataType, $value ); // since the value was already "seen", the value writer should be empty. $this->assertTriplesEqual( array(), $builder->test_value_writer ); diff --git a/repo/tests/phpunit/includes/rdf/FullStatementsRdfBuilderTest.php b/repo/tests/phpunit/includes/rdf/FullStatementsRdfBuilderTest.php index 1f5a507..fa2c159 100644 --- a/repo/tests/phpunit/includes/rdf/FullStatementsRdfBuilderTest.php +++ b/repo/tests/phpunit/includes/rdf/FullStatementsRdfBuilderTest.php @@ -10,6 +10,7 @@ use Wikibase\Rdf\NullDedupeBag; use Wikibase\Rdf\RdfProducer; use Wikibase\Rdf\SimpleValueRdfBuilder; +use Wikibase\Rdf\SnakRdfBuilder; /** * @covers Wikibase\Rdf\FullStatementRdfBuilder @@ -72,11 +73,13 @@ $statementValueBuilder = new SimpleValueRdfBuilder( $vocabulary, $this->getTestData()->getMockRepository() ); } - $statementBuilder = new FullStatementRdfBuilder( $vocabulary, $writer, $statementValueBuilder ); + $snakRdfBuilder = new SnakRdfBuilder( $vocabulary, $statementValueBuilder, $this->getTestData()->getMockRepository() ); + $statementBuilder = new FullStatementRdfBuilder( $vocabulary, $writer, $snakRdfBuilder ); $statementBuilder->setDedupeBag( $dedupe ?: new NullDedupeBag() ); if ( $flavor & RdfProducer::PRODUCE_PROPERTIES ) { - $statementBuilder->setEntityMentionListener( $mentionTracker ); + $snakRdfBuilder->setEntityMentionListener( $mentionTracker ); + $statementValueBuilder->setEntityMentionListener( $mentionTracker ); } $statementBuilder->setProduceQualifiers( $flavor & RdfProducer::PRODUCE_QUALIFIERS ); diff --git a/repo/tests/phpunit/includes/rdf/SimpleValueRdfBuilderTest.php b/repo/tests/phpunit/includes/rdf/SimpleValueRdfBuilderTest.php index c52c6a5..22ccab8 100644 --- a/repo/tests/phpunit/includes/rdf/SimpleValueRdfBuilderTest.php +++ b/repo/tests/phpunit/includes/rdf/SimpleValueRdfBuilderTest.php @@ -96,12 +96,13 @@ $this->assertEquals( $expectedTriples, $actualTripels ); } - public function provideAddSnakValue() { + public function provideAddValue() { // NOTE: data types must match $this->getTestData()->getMockRepository(); return array( 'wikibase-entityid' => array( new PropertyId( 'P2' ), + 'wikibase-item', new EntityIdValue( new ItemId( 'Q42' ) ), array( '<http://acme.test/Q11> <http://acme.test/prop/direct/P2> <http://acme.test/Q42> .', @@ -109,6 +110,7 @@ ), 'commonsMedia' => array( new PropertyId( 'P3' ), + 'commonsMedia', new StringValue( 'Test.jpg' ), array( '<http://acme.test/Q11> <http://acme.test/prop/direct/P3> <http://commons.wikimedia.org/wiki/Special:FilePath/Test.jpg> .', @@ -116,6 +118,7 @@ ), 'globecoordinate' => array( new PropertyId( 'P4' ), + 'globecoordinate', new GlobeCoordinateValue( new LatLongValue( 12.25, -45.5 ), 0.025, @@ -127,6 +130,7 @@ ), 'monolingualtext' => array( new PropertyId( 'P5' ), + 'monolingualtext', new MonolingualTextValue( 'ru', 'Берлин' ), array( '<http://acme.test/Q11> <http://acme.test/prop/direct/P5> "\u0411\u0435\u0440\u043B\u0438\u043D"@ru .', @@ -134,6 +138,7 @@ ), 'quantity' => array( new PropertyId( 'P6' ), + 'quantity', new QuantityValue( new DecimalValue( '+0.00011' ), '1', @@ -145,6 +150,7 @@ ), 'quantity-unit' => array( new PropertyId( 'P6' ), + 'quantity', new QuantityValue( new DecimalValue( '-2.3' ), 'https://www.wikidata.org/entity/Q11573', @@ -156,6 +162,7 @@ ), 'string' => array( new PropertyId( 'P7' ), + 'string', new StringValue( 'Kittens' ), array( '<http://acme.test/Q11> <http://acme.test/prop/direct/P7> "Kittens" .', @@ -163,6 +170,7 @@ ), 'time' => array( new PropertyId( 'P8' ), + 'time', new TimeValue( '+2015-03-03T00:00:00Z', 0, 0, 0, TimeValue::PRECISION_DAY, RdfVocabulary::GREGORIAN_CALENDAR ), array( '<http://acme.test/Q11> <http://acme.test/prop/direct/P8> "2015-03-03T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .', @@ -170,6 +178,7 @@ ), 'time-year' => array( // NOTE: may changed to use xsd:gYear new PropertyId( 'P8' ), + 'time', new TimeValue( '+2015-00-00T00:00:00Z', 0, 0, 0, TimeValue::PRECISION_YEAR, RdfVocabulary::GREGORIAN_CALENDAR ), array( '<http://acme.test/Q11> <http://acme.test/prop/direct/P8> "2015-01-01T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .', @@ -177,6 +186,7 @@ ), 'time-margin' => array( new PropertyId( 'P8' ), + 'time', new TimeValue( '+2015-03-03T00:00:00Z', 0, 3, 3, TimeValue::PRECISION_DAY, RdfVocabulary::GREGORIAN_CALENDAR ), array( '<http://acme.test/Q11> <http://acme.test/prop/direct/P8> "2015-03-03T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .', @@ -188,6 +198,7 @@ // XSD 1.1 uses astronomical numbering (-44 means 43 BCE), // conversion would apply. new PropertyId( 'P8' ), + 'time', new TimeValue( '-0044-03-15T00:00:00Z', 0, 3, 3, TimeValue::PRECISION_DAY, RdfVocabulary::GREGORIAN_CALENDAR ), array( '<http://acme.test/Q11> <http://acme.test/prop/direct/P8> "-0043-03-15T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .', @@ -199,6 +210,7 @@ // are known, they could be converted to (proleptic) // gregorian an output as an XSD date. new PropertyId( 'P8' ), + 'time', new TimeValue( '+1492-10-12T00:00:00Z', 0, 0, 0, TimeValue::PRECISION_DAY, RdfVocabulary::JULIAN_CALENDAR ), array( '<http://acme.test/Q11> <http://acme.test/prop/direct/P8> "1492-10-21T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .', @@ -206,6 +218,7 @@ ), 'url' => array( new PropertyId( 'P9' ), + 'url', new StringValue( 'http://quux.test/xyzzy' ), array( '<http://acme.test/Q11> <http://acme.test/prop/direct/P9> <http://quux.test/xyzzy> .', @@ -213,6 +226,7 @@ ), 'url-mailto' => array( new PropertyId( 'P9' ), + 'url', new StringValue( 'mailto:xy...@quux.test' ), array( '<http://acme.test/Q11> <http://acme.test/prop/direct/P9> <mailto:xy...@quux.test> .', @@ -222,21 +236,22 @@ } /** - * @dataProvider provideAddSnakValue + * @dataProvider provideAddValue */ - public function testAddSnakValue( PropertyId $propertyId, DataValue $value, array $expectedTriples ) { + public function testAddValue( PropertyId $propertyId, $dataType, DataValue $value, array $expectedTriples ) { $writer = $this->getTestData()->getNTriplesWriter(); $writer->about( RdfVocabulary::NS_ENTITY, 'Q11' ); $builder = $this->newBuilder(); - $builder->addSnakValue( $writer, $propertyId, $value, RdfVocabulary::NSP_DIRECT_CLAIM ); + $builder->addValue( $writer, RdfVocabulary::NSP_DIRECT_CLAIM, $propertyId->getSerialization(), $dataType, $value ); $this->assertTriplesEqual( $expectedTriples, $writer ); } - public function testAddSnakValue_mention() { + public function testAddValue_mention() { $propertyId = new PropertyId( 'P2' ); + $dataType = 'wikibase-item'; $value = new EntityIdValue( new ItemId( 'Q42' ) ); $writer = $this->getTestData()->getNTriplesWriter(); @@ -245,7 +260,7 @@ $mentioned = array(); $builder = $this->newBuilder( $mentioned ); - $builder->addSnakValue( $writer, $propertyId, $value, RdfVocabulary::NSP_DIRECT_CLAIM ); + $builder->addValue( $writer, RdfVocabulary::NSP_DIRECT_CLAIM, $propertyId->getSerialization(), $dataType, $value ); $this->assertEquals( array( 'Q42' ), array_keys( $mentioned ) ); } diff --git a/repo/tests/phpunit/includes/rdf/SnakRdfBuilderTest.php b/repo/tests/phpunit/includes/rdf/SnakRdfBuilderTest.php new file mode 100644 index 0000000..73945e4 --- /dev/null +++ b/repo/tests/phpunit/includes/rdf/SnakRdfBuilderTest.php @@ -0,0 +1,203 @@ +<?php + +namespace Wikibase\Test\Rdf; + +use DataValues\DataValue; +use DataValues\StringValue; +use Wikibase\DataModel\Entity\EntityId; +use Wikibase\DataModel\Entity\EntityIdValue; +use Wikibase\DataModel\Entity\ItemId; +use Wikibase\DataModel\Entity\Property; +use Wikibase\DataModel\Entity\PropertyId; +use Wikibase\DataModel\Snak\PropertyNoValueSnak; +use Wikibase\DataModel\Snak\PropertyValueSnak; +use Wikibase\DataModel\Snak\Snak; +use Wikibase\Rdf\RdfVocabulary; +use Wikibase\Rdf\SnakRdfBuilder; +use Wikimedia\Purtle\RdfWriter; + +/** + * @covers Wikibase\Rdf\SnakRdfBuilder + * + * @group Wikibase + * @group WikibaseRepo + * @group WikibaseRdf + * + * @licence GNU GPL v2+ + * @author Daniel Kinzler + * @author Stas Malyshev + */ +class SnakRdfBuilderTest extends \PHPUnit_Framework_TestCase { + + /** + * @var RdfBuilderTestData|null + */ + private $testData = null; + + /** + * Initialize repository data + * + * @return RdfBuilderTestData + */ + private function getTestData() { + if ( $this->testData === null ) { + $this->testData = new RdfBuilderTestData( + __DIR__ . "/../../data/rdf", + __DIR__ . "/../../data/rdf/SnakRdfBuilder" + ); + } + + return $this->testData; + } + + /** + * @param string $propertyNamespace + * @param string $propertyValueLName + * @param string $dataType + * @param DataValue $value + * @param EntityId[] &$mentioned receives the IDs of any mentioned entities. + * + * @return SnakRdfBuilder + */ + private function newBuilder( + $propertyNamespace, + $propertyValueLName, + $dataType = null, + DataValue $value = null, + array &$mentioned = array() + ) { + $mentionTracker = $this->getMock( 'Wikibase\Rdf\EntityMentionListener' ); + $mentionTracker->expects( $this->any() ) + ->method( 'propertyMentioned' ) + ->will( $this->returnCallback( function( EntityId $id ) use ( &$mentioned ) { + $key = $id->getSerialization(); + $mentioned[$key] = $id; + } ) ); + + $valueBuilder = $this->getMock( 'Wikibase\Rdf\DataValueRdfBuilder' ); + + if ( $value ) { + $valueBuilder->expects( $this->once() ) + ->method( 'addValue' ) + ->with( $this->anything(), $propertyNamespace, $propertyValueLName, $dataType, $value ); + } else { + $valueBuilder->expects( $this->never() ) + ->method( 'addValue' ); + } + + $vocabulary = $this->getTestData()->getVocabulary(); + + $builder = new SnakRdfBuilder( $vocabulary, $valueBuilder, $this->getTestData()->getMockRepository() ); + $builder->setEntityMentionListener( $mentionTracker ); + + return $builder; + } + + /** + * Extract text test data from RDF builder + * + * @param RdfWriter $writer + * + * @return string[] ntriples lines, sorted + */ + private function getDataFromWriter( RdfWriter $writer ) { + $ntriples = $writer->drain(); + + $lines = explode( "\n", trim( $ntriples ) ); + sort( $lines ); + return $lines; + } + + private function assertTriplesEqual( array $expectedTriples, RdfWriter $writer ) { + $actualTripels = $this->getDataFromWriter( $writer ); + sort( $expectedTriples ); + + $this->assertEquals( $expectedTriples, $actualTripels ); + } + + public function provideAddSnakValue() { + // NOTE: data types must match $this->getTestData()->getMockRepository(); + + return array( + 'value snak' => array( + new PropertyValueSnak( + new PropertyId( 'P2' ), + new EntityIdValue( new ItemId( 'Q42' ) ) + ), + null, // Currently, the data type is only looked up for string values + ), + 'value snak with data type' => array( + new PropertyValueSnak( + new PropertyId( 'P9' ), + new StringValue( 'http://acme.com' ) + ), + 'url', // Data type should be supplied at least for string values + array() + ), + ); + } + + /** + * @dataProvider provideAddSnakValue + */ + public function testAddSnakValue( Snak $snak, $dataType ) { + $writer = $this->getTestData()->getNTriplesWriter(); + + $writer->about( RdfVocabulary::NS_ENTITY, 'Q11' ); + + $propertyId = $snak->getPropertyId(); + $value = $snak instanceof PropertyValueSnak ? $snak->getDataValue() : null; + + $builder = $this->newBuilder( + RdfVocabulary::NSP_DIRECT_CLAIM, + $propertyId->getSerialization(), + $dataType, + $value + ); + + // assertions are done by the mocks + $builder->addSnak( $writer, $snak, RdfVocabulary::NSP_DIRECT_CLAIM ); + } + + public function testAddSnakValue_novalue() { + $propertyId = new PropertyId( 'P2' ); + $snak = new PropertyNoValueSnak( $propertyId ); + + $writer = $this->getTestData()->getNTriplesWriter(); + $writer->about( RdfVocabulary::NS_ENTITY, 'Q11' ); + + $builder = $this->newBuilder( + RdfVocabulary::NSP_DIRECT_CLAIM, + $propertyId->getSerialization() + ); + + $expectedTriples = array( + '<http://acme.test/Q11> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://acme.test/prop/novalue/P2> .', + ); + + $builder->addSnak( $writer, $snak, RdfVocabulary::NSP_DIRECT_CLAIM ); + $this->assertTriplesEqual( $expectedTriples, $writer ); + } + + public function testAddSnakValue_mention() { + $propertyId = new PropertyId( 'P2' ); + $value = new EntityIdValue( new ItemId( 'Q42' ) ); + $snak = new PropertyValueSnak( $propertyId, $value ); + + $writer = $this->getTestData()->getNTriplesWriter(); + $writer->about( RdfVocabulary::NS_ENTITY, 'Q11' ); + + $mentioned = array(); + $builder = $this->newBuilder( + RdfVocabulary::NSP_DIRECT_CLAIM, + $propertyId->getSerialization(), + null, + $value, + $mentioned + ); + + $builder->addSnak( $writer, $snak, RdfVocabulary::NSP_DIRECT_CLAIM ); + $this->assertEquals( array( 'P2' ), array_keys( $mentioned ) ); + } + +} diff --git a/repo/tests/phpunit/includes/rdf/TruthyStatementsRdfBuilderTest.php b/repo/tests/phpunit/includes/rdf/TruthyStatementsRdfBuilderTest.php index c9b7311..2ee6854 100644 --- a/repo/tests/phpunit/includes/rdf/TruthyStatementsRdfBuilderTest.php +++ b/repo/tests/phpunit/includes/rdf/TruthyStatementsRdfBuilderTest.php @@ -3,6 +3,7 @@ namespace Wikibase\Test\Rdf; use Wikibase\Rdf\SimpleValueRdfBuilder; +use Wikibase\Rdf\SnakRdfBuilder; use Wikibase\Rdf\TruthyStatementRdfBuilder; /** @@ -47,11 +48,12 @@ $writer = $this->getTestData()->getNTriplesWriter(); $valueBuilder = new SimpleValueRdfBuilder( $vocabulary, $this->getTestData()->getMockRepository() ); + $snakBuilder = new SnakRdfBuilder( $vocabulary, $valueBuilder, $this->getTestData()->getMockRepository() ); $builder = new TruthyStatementRdfBuilder( $vocabulary, $writer, - $valueBuilder + $snakBuilder ); // HACK: stick the writer into a public field, for use by getDataFromBuilder() -- To view, visit https://gerrit.wikimedia.org/r/229957 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I946f4593895c49c937bad0c0c66e1cf0e932ad2a 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: Daniel Kinzler <daniel.kinz...@wikimedia.de> Gerrit-Reviewer: Hoo man <h...@online.de> Gerrit-Reviewer: Smalyshev <smalys...@wikimedia.org> 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