Ladsgroup has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/340696 )
Change subject: Add EntityRdfBuilderFactory and DispatchingEntityRdfBuilder. ...................................................................... Add EntityRdfBuilderFactory and DispatchingEntityRdfBuilder. Bug: T157311 Change-Id: Id5920889655136cf06800ca92d06edda4551813e --- M lib/includes/EntityTypeDefinitions.php M lib/tests/phpunit/EntityTypeDefinitionsTest.php A repo/includes/Rdf/DispatchingEntityRdfBuilder.php A repo/includes/Rdf/EntityRdfBuilderFactory.php M repo/includes/WikibaseRepo.php A repo/tests/phpunit/includes/Rdf/DispatchingEntityRdfBuilderTest.php A repo/tests/phpunit/includes/Rdf/EntityRdfBuilderFactoryTest.php 7 files changed, 338 insertions(+), 1 deletion(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikibase refs/changes/96/340696/1 diff --git a/lib/includes/EntityTypeDefinitions.php b/lib/includes/EntityTypeDefinitions.php index 336f534..12e3453 100644 --- a/lib/includes/EntityTypeDefinitions.php +++ b/lib/includes/EntityTypeDefinitions.php @@ -164,4 +164,13 @@ return $this->getMapForDefinitionField( 'changeop-deserializer-callback' ); } + /** + * @return callable[] An array mapping entity type identifiers + * to callables instantiating EntityRdfBuilder objects + * Not guaranteed to contain all entity types. + */ + public function getRdfBuilderFactoryCallbacks() { + return $this->getMapForDefinitionField( 'rdf-builder-factory-callback' ); + } + } diff --git a/lib/tests/phpunit/EntityTypeDefinitionsTest.php b/lib/tests/phpunit/EntityTypeDefinitionsTest.php index 45ab259..1110cb6 100644 --- a/lib/tests/phpunit/EntityTypeDefinitionsTest.php +++ b/lib/tests/phpunit/EntityTypeDefinitionsTest.php @@ -31,7 +31,8 @@ 'entity-id-pattern' => 'foo-id-pattern', 'entity-id-builder' => 'new-foo-id', 'entity-id-composer-callback' => 'new-composed-foo-id', - 'changeop-deserializer-callback' => 'new-changeop-deserializer-callback' + 'changeop-deserializer-callback' => 'new-changeop-deserializer-callback', + 'rdf-builder-factory-callback' => 'new-rdf-builder-factory-callback' ), 'bar' => array( 'serializer-factory-callback' => 'bar-serializer', @@ -166,4 +167,13 @@ ); } + public function testGetRdfBuilderFactoryCallbacks() { + $definitions = new EntityTypeDefinitions( $this->getDefinitions() ); + + $this->assertSame( + [ 'foo' => 'new-rdf-builder-factory-callback' ], + $definitions->getRdfBuilderFactoryCallbacks() + ); + } + } diff --git a/repo/includes/Rdf/DispatchingEntityRdfBuilder.php b/repo/includes/Rdf/DispatchingEntityRdfBuilder.php new file mode 100644 index 0000000..4a3403d --- /dev/null +++ b/repo/includes/Rdf/DispatchingEntityRdfBuilder.php @@ -0,0 +1,62 @@ +<?php + +namespace Wikibase\Rdf; + +use Wikibase\DataModel\Entity\EntityDocument; +use Wikimedia\Assert\Assert; + +/** + * Dispatching implementation of EntityRdfBuilder. This allows extensions to register + * EntityRdfBuilders for custom data types. + * + * @license GPL-2.0+ + * @author Amir Sarabadani + */ +class DispatchingEntityRdfBuilder implements EntityRdfBuilder { + + /** + * @var EntityRdfBuilder[] + */ + private $rdfBuilders; + + /** + * @param EntityRdfBuilder[] $rdfBuilders EntityRdfBuilder objects keyed by entity type + */ + public function __construct( array $rdfBuilders ) { + Assert::parameterElementType( EntityRdfBuilder::class, $rdfBuilders, '$rdfBuilders' ); + + $this->rdfBuilders = $rdfBuilders; + } + + /** + * Adds specific entity + * + * @param EntityDocument $entity + */ + public function addEntity( + EntityDocument $entity + ) { + $builder = $this->getRdfBuilder( $entity->getType() ); + + if ( $builder ) { + $builder->addEntity( $entity ); + } + } + + /** + * @param string $entityType + * + * @return null|EntityRdfBuilder + */ + private function getRdfBuilder( $entityType ) { + if ( $entityType !== null ) { + if ( isset( $this->rdfBuilders[$entityType] ) ) { + return $this->rdfBuilders[$entityType]; + } + } + + wfLogWarning( __METHOD__ . ": No RDF builder defined for entity type $entityType." ); + return null; + } + +} diff --git a/repo/includes/Rdf/EntityRdfBuilderFactory.php b/repo/includes/Rdf/EntityRdfBuilderFactory.php new file mode 100644 index 0000000..04ec52e --- /dev/null +++ b/repo/includes/Rdf/EntityRdfBuilderFactory.php @@ -0,0 +1,98 @@ +<?php + +namespace Wikibase\Rdf; + +use Wikimedia\Assert\Assert; +use Wikimedia\Purtle\RdfWriter; + +/** + * Factory for ValueSnakRdfBuilder based on factory callbacks. + * For use with DataTypeDefinitions. + * + * @license GPL-2.0+ + * @author Amir Sarabadani <ladsgr...@gmail.com> + */ +class EntityRdfBuilderFactory { + + /** + * @var callable[] + */ + private $factoryCallbacks; + + /** + * @param callable[] $factoryCallbacks Factory callback functions as returned by + * EntityTypeDefinitions::getRdfBuilderFactoryCallbacks(). Callbacks will be invoked + * with the signature ($mode, RdfVocabulary, EntityMentionListener) and must + * return a EntityRdfBuilder (or null). + */ + public function __construct( array $factoryCallbacks ) { + Assert::parameterElementType( 'callable', $factoryCallbacks, '$factoryCallbacks' ); + + $this->factoryCallbacks = $factoryCallbacks; + } + + /** + * Returns an EntityRdfBuilder for reified value output. + * + * @param int $flavorFlags Flavor flags to use for the entity rdf builder + * @param RdfVocabulary $vocabulary + * @param RdfWriter $writer + * @param EntityMentionListener $mentionedEntityTracker + * @param DedupeBag $dedupe + * @return DispatchingEntityRdfBuilder + */ + public function getEntityRdfBuilder( + $flavorFlags, + RdfVocabulary $vocabulary, + RdfWriter $writer, + EntityMentionListener $mentionedEntityTracker, + DedupeBag $dedupe + ) { + $builders = $this->createEntityRdfBuilders( + $flavorFlags, + $vocabulary, + $writer, + $mentionedEntityTracker, + $dedupe + ); + + return new DispatchingEntityRdfBuilder( $builders ); + } + + /** + * @param int $flavorFlags Flavor flags to use for the entity rdf builder + * @param RdfVocabulary $vocabulary + * @param RdfWriter $writer + * @param EntityMentionListener $mentionedEntityTracker + * @param DedupeBag $dedupe + * + * @return EntityRdfBuilder[] + */ + private function createEntityRdfBuilders( + $flavorFlags, + RdfVocabulary $vocabulary, + RdfWriter $writer, + EntityMentionListener $mentionedEntityTracker, + DedupeBag $dedupe + ) { + $builders = []; + + foreach ( $this->factoryCallbacks as $key => $callback ) { + $builder = call_user_func( + $callback, + $flavorFlags, + $vocabulary, + $writer, + $mentionedEntityTracker, + $dedupe + ); + + if ( $builder instanceof EntityRdfBuilder ) { + $builders[$key] = $builder; + } + } + + return $builders; + } + +} diff --git a/repo/includes/WikibaseRepo.php b/repo/includes/WikibaseRepo.php index da724a6..a6fa8f6 100644 --- a/repo/includes/WikibaseRepo.php +++ b/repo/includes/WikibaseRepo.php @@ -84,6 +84,7 @@ use Wikibase\Lib\Store\EntityRevisionLookup; use Wikibase\Lib\Store\EntityStore; use Wikibase\Lib\Store\EntityStoreWatcher; +use Wikibase\Rdf\EntityRdfBuilderFactory; use Wikibase\Repo\Store\EntityTitleStoreLookup; use Wikibase\Lib\Store\LanguageFallbackLabelDescriptionLookupFactory; use Wikibase\Lib\Store\PrefetchingTermLookup; @@ -283,6 +284,11 @@ * @var SettingsArray|null */ private $clientSettings = null; + + /** + * @var EntityRdfBuilderFactory|null + */ + private $entityRdfBuilderFactory = null; /** * IMPORTANT: Use only when it is not feasible to inject an instance properly. @@ -1868,4 +1874,17 @@ return $this->entityTypeDefinitions->getChangeOpDeserializerCallbacks(); } + /** + * @return EntityRdfBuilderFactory + */ + public function getEntityRdfBuilderFactory() { + if ( $this->entityRdfBuilderFactory === null ) { + $this->entityRdfBuilderFactory = new EntityRdfBuilderFactory( + $this->dataTypeDefinitions->getRdfBuilderFactoryCallbacks() + ); + } + + return $this->entityRdfBuilderFactory; + } + } diff --git a/repo/tests/phpunit/includes/Rdf/DispatchingEntityRdfBuilderTest.php b/repo/tests/phpunit/includes/Rdf/DispatchingEntityRdfBuilderTest.php new file mode 100644 index 0000000..428d90a --- /dev/null +++ b/repo/tests/phpunit/includes/Rdf/DispatchingEntityRdfBuilderTest.php @@ -0,0 +1,36 @@ +<?php + +namespace Wikibase\Repo\Tests\Rdf; + +use Wikibase\DataModel\Entity\Item; +use Wikibase\DataModel\Entity\ItemId; +use Wikibase\Rdf\DispatchingEntityRdfBuilder; +use Wikibase\Rdf\EntityRdfBuilder; + +/** + * @covers Wikibase\Rdf\DispatchingEntityRdfBuilder + * + * @group Wikibase + * @group WikibaseRdf + * + * @license GPL-2.0+ + * @author Amir Sarabadani <ladsgr...@gmail.com> + */ +class DispatchingEntityRdfBuilderTest extends \PHPUnit_Framework_TestCase { + + public function testAddValue() { + $entity = new Item( new ItemId( 'Q1' ) ); + + $fooBuilder = $this->getMock( EntityRdfBuilder::class ); + $fooBuilder->expects( $this->once() ) + ->method( 'addEntity' ) + ->with( $entity ); + + $dispatchingBuilder = new DispatchingEntityRdfBuilder( [ + 'item' => $fooBuilder, + ] ); + + $dispatchingBuilder->addEntity( $entity ); + } + +} diff --git a/repo/tests/phpunit/includes/Rdf/EntityRdfBuilderFactoryTest.php b/repo/tests/phpunit/includes/Rdf/EntityRdfBuilderFactoryTest.php new file mode 100644 index 0000000..8a7bf59 --- /dev/null +++ b/repo/tests/phpunit/includes/Rdf/EntityRdfBuilderFactoryTest.php @@ -0,0 +1,103 @@ +<?php + +namespace Wikibase\Repo\Tests\Rdf; + +use Closure; +use PHPUnit_Framework_TestCase; +use Wikibase\Rdf\RdfProducer; +use Wikibase\Rdf\EntityRdfBuilder; +use Wikibase\Rdf\EntityRdfBuilderFactory; +use Wikibase\Rdf\RdfVocabulary; +use Wikibase\Rdf\NullEntityMentionListener; +use Wikibase\Rdf\NullDedupeBag; +use Wikimedia\Purtle\NTriplesRdfWriter; +use Wikimedia\Purtle\RdfWriter; +use Wikibase\Rdf\EntityMentionListener; +use Wikibase\Rdf\DedupeBag; + +/** + * @covers Wikibase\Rdf\EntityRdfBuilderFactory + * + * @group Wikibase + * @group WikibaseRdf + * + * @license GPL-2.0+ + * @author Amir Sarabadani <ladsgr...@gmail.com> + */ +class EntityRdfBuilderFactoryTest extends PHPUnit_Framework_TestCase { + + public function getBuilderFlags() { + return [ + [ 0 ], // simple values + [ RdfProducer::PRODUCE_FULL_VALUES ], // complex values + ]; + } + + /** + * @dataProvider getBuilderFlags + */ + public function testGetEntityRdfBuilder( $flags ) { + $vocab = new RdfVocabulary( RdfBuilderTestData::URI_BASE, RdfBuilderTestData::URI_DATA ); + $writer = new NTriplesRdfWriter(); + $tracker = new NullEntityMentionListener(); + $dedupe = new NullDedupeBag(); + $called = false; + + $constructor = $this->newRdfBuilderConstructorCallback( + $flags, $vocab, $writer, $tracker, $dedupe, $called + ); + + $factory = new EntityRdfBuilderFactory( [ 'test' => $constructor ] ); + $factory->getEntityRdfBuilder( $flags, $vocab, $writer, $tracker, $dedupe ); + $this->assertTrue( $called ); + } + + /** + * Constructs a closure that asserts that it is being called with the expected parameters. + * + * @param int $expectedMode + * @param RdfVocabulary $expectedVocab + * @param RdfWriter $expectedWriter + * @param EntityMentionListener $expectedTracker + * @param DedupeBag $expectedDedupe + * @param bool &$called Will be set to true once the returned function has been called. + * + * @return Closure + */ + private function newRdfBuilderConstructorCallback( + $expectedMode, + RdfVocabulary $expectedVocab, + RdfWriter $expectedWriter, + EntityMentionListener $expectedTracker, + DedupeBag $expectedDedupe, + &$called + ) { + $entityRdfBuilder = $this->getMock( EntityRdfBuilder::class ); + + return function( + $mode, + RdfVocabulary $vocab, + RdfWriter $writer, + EntityMentionListener $tracker, + DedupeBag $dedupe + ) use ( + $expectedMode, + $expectedVocab, + $expectedWriter, + $expectedTracker, + $expectedDedupe, + $entityRdfBuilder, + &$called + ) { + $this->assertSame( $expectedMode, $mode ); + $this->assertSame( $expectedVocab, $vocab ); + $this->assertSame( $expectedWriter, $writer ); + $this->assertSame( $expectedTracker, $tracker ); + $this->assertSame( $expectedDedupe, $dedupe ); + $called = true; + + return $entityRdfBuilder; + }; + } + +} -- To view, visit https://gerrit.wikimedia.org/r/340696 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id5920889655136cf06800ca92d06edda4551813e Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Wikibase Gerrit-Branch: master Gerrit-Owner: Ladsgroup <ladsgr...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits