jenkins-bot has submitted this change and it was merged. Change subject: Implement LabelLookup ......................................................................
Implement LabelLookup implementations that can take either LanguageFallbackChain or a language code. formatters can take a LabelLookup (of either implementation) rather than stuffing a LanguageFallbackChain into formatter options, and such evilness. Change-Id: I420df654a8ef7d17e3e45b7e2b0444f5c130a873 --- A lib/includes/store/EntityTermLookup.php A lib/includes/store/LabelLookup.php A lib/includes/store/LanguageFallbackLabelLookup.php A lib/includes/store/LanguageLabelLookup.php M lib/includes/store/TermIndex.php A lib/includes/store/TermLookup.php A lib/tests/phpunit/store/EntityTermLookupTest.php A lib/tests/phpunit/store/LanguageFallbackLabelLookupTest.php A lib/tests/phpunit/store/LanguageLabelLookupTest.php M lib/tests/phpunit/store/MockTermIndex.php 10 files changed, 622 insertions(+), 8 deletions(-) Approvals: Jeroen De Dauw: Looks good to me, approved jenkins-bot: Verified diff --git a/lib/includes/store/EntityTermLookup.php b/lib/includes/store/EntityTermLookup.php new file mode 100644 index 0000000..a8b282b --- /dev/null +++ b/lib/includes/store/EntityTermLookup.php @@ -0,0 +1,116 @@ +<?php + +namespace Wikibase\Lib\Store; + +use OutOfBoundsException; +use Wikibase\DataModel\Entity\EntityId; +use Wikibase\TermIndex; + +/** + * @since 0.5 + * + * @licence GNU GPL v2+ + * @author Katie Filbert < [email protected] > + */ +class EntityTermLookup implements TermLookup { + + /** + * @var TermIndex + */ + private $termIndex; + + /** + * @param TermIndex $termIndex + */ + public function __construct( TermIndex $termIndex ) { + $this->termIndex = $termIndex; + } + + /** + * @param EntityId $entityId + * @param string $languageCode + * + * @throws OutOfBoundsException + * @return string + */ + public function getLabel( EntityId $entityId, $languageCode ) { + $labels = $this->getLabels( $entityId ); + return $this->filterByLanguage( $labels, $languageCode ); + } + + /** + * @param EntityId $entityId + * + * @return string[] + */ + public function getLabels( EntityId $entityId ) { + return $this->getTermsOfType( $entityId, 'label' ); + } + + /** + * @param EntityId $entityId + * @param string $languageCode + * + * @throws OutOfBoundsException + * @return string + */ + public function getDescription( EntityId $entityId, $languageCode ) { + $descriptions = $this->getTermsOfType( $entityId, 'description' ); + return $this->filterByLanguage( $descriptions, $languageCode ); + } + + /** + * @param EntityId $entityId + * + * @return string[] + */ + public function getDescriptions( EntityId $entityId ) { + return $this->getTermsOfType( $entityId, 'description' ); + } + + /** + * @param EntityId $entityId + * @param string $termType + * + * @return string[] + */ + private function getTermsOfType( EntityId $entityId, $termType ) { + $wikibaseTerms = $this->termIndex->getTermsOfEntity( $entityId ); + return $this->convertTermsToTermTypeArray( $wikibaseTerms, $termType ); + } + + /** + * @param string[] $labels + * @param string $languageCode + * + * @throws OutOfBoundsException + * @return string + */ + private function filterByLanguage( array $labels, $languageCode ) { + if ( array_key_exists( $languageCode, $labels ) ) { + return $labels[$languageCode]; + } + + throw new OutOfBoundsException( 'Label not found for ' . $languageCode ); + } + + /** + * @param \Wikibase\Term[] $wikibaseTerms + * @param string $termType + * + * @return string[] + */ + private function convertTermsToTermTypeArray( array $wikibaseTerms, $termType ) { + $terms = array(); + + foreach( $wikibaseTerms as $wikibaseTerm ) { + if ( $wikibaseTerm->getType() === $termType ) { + $languageCode = $wikibaseTerm->getLanguage(); + $terms[$languageCode] = $wikibaseTerm->getText(); + } + } + + return $terms; + } + +} diff --git a/lib/includes/store/LabelLookup.php b/lib/includes/store/LabelLookup.php new file mode 100644 index 0000000..2c9d947 --- /dev/null +++ b/lib/includes/store/LabelLookup.php @@ -0,0 +1,24 @@ +<?php + +namespace Wikibase\Lib\Store; + +use OutOfBoundsException; +use Wikibase\DataModel\Entity\EntityId; + +/** + * @since 0.5 + * + * @licence GNU GPL v2+ + * @author Katie Filbert < [email protected] > + */ +interface LabelLookup { + + /** + * @param EntityId $entityId + * + * @throws OutOfBoundsException + * @return string + */ + public function getLabel( EntityId $entityId ); + +} diff --git a/lib/includes/store/LanguageFallbackLabelLookup.php b/lib/includes/store/LanguageFallbackLabelLookup.php new file mode 100644 index 0000000..1c93bb3 --- /dev/null +++ b/lib/includes/store/LanguageFallbackLabelLookup.php @@ -0,0 +1,56 @@ +<?php + +namespace Wikibase\Lib\Store; + +use OutOfBoundsException; +use Wikibase\DataModel\Entity\EntityId; +use Wikibase\LanguageFallbackChain; + +/** + * @since 0.5 + * + * @licence GNU GPL v2+ + * @author Katie Filbert < [email protected] > + */ +class LanguageFallbackLabelLookup implements LabelLookup { + + /** + * @var TermLookup + */ + private $termLookup; + + /** + * @var LanguageFallbackChain + */ + private $languageFallbackChain; + + /** + * @param TermLookup $termLookup + * @param LanguageFallbackChain $languageFallbackChain + */ + public function __construct( + TermLookup $termLookup, + LanguageFallbackChain $languageFallbackChain + ) { + $this->termLookup = $termLookup; + $this->languageFallbackChain = $languageFallbackChain; + } + + /** + * @param EntityId $entityId + * + * @throws OutOfBoundsException + * @return string + */ + public function getLabel( EntityId $entityId ) { + $labels = $this->termLookup->getLabels( $entityId ); + $extractedData = $this->languageFallbackChain->extractPreferredValue( $labels ); + + if ( $extractedData && isset( $extractedData['value'] ) ) { + return $extractedData['value']; + } + + throw new OutOfBoundsException( 'Label not found for fallback chain.' ); + } + +} diff --git a/lib/includes/store/LanguageLabelLookup.php b/lib/includes/store/LanguageLabelLookup.php new file mode 100644 index 0000000..75020f5 --- /dev/null +++ b/lib/includes/store/LanguageLabelLookup.php @@ -0,0 +1,45 @@ +<?php + +namespace Wikibase\Lib\Store; + +use OutOfBoundsException; +use Wikibase\DataModel\Entity\EntityId; + +/** + * @since 0.5 + * + * @licence GNU GPL v2+ + * @author Katie Filbert < [email protected] > + */ +class LanguageLabelLookup implements LabelLookup { + + /** + * @var TermLookup + */ + private $termLookup; + + /** + * @var string + */ + private $languageCode; + + /** + * @param TermLookup $termLookup + * @param string $languageCode + */ + public function __construct( TermLookup $termLookup, $languageCode ) { + $this->termLookup = $termLookup; + $this->languageCode = $languageCode; + } + + /** + * @param EntityId $entityId + * + * @throws OutOfBoundsException + * @return string + */ + public function getLabel( EntityId $entityId ) { + return $this->termLookup->getLabel( $entityId, $this->languageCode ); + } + +} diff --git a/lib/includes/store/TermIndex.php b/lib/includes/store/TermIndex.php index 3ee94e9..8b36af2 100644 --- a/lib/includes/store/TermIndex.php +++ b/lib/includes/store/TermIndex.php @@ -57,11 +57,11 @@ /** * Returns the terms stored for the given entity. * - * @param EntityId $id + * @param EntityId $entityId * * @return Term[] */ - public function getTermsOfEntity( EntityId $id ); + public function getTermsOfEntity( EntityId $entityId ); /** * Returns the terms stored for the given entities. Can be filtered by language. diff --git a/lib/includes/store/TermLookup.php b/lib/includes/store/TermLookup.php new file mode 100644 index 0000000..75bc490 --- /dev/null +++ b/lib/includes/store/TermLookup.php @@ -0,0 +1,53 @@ +<?php + +namespace Wikibase\Lib\Store; + +use Wikibase\DataModel\Entity\EntityId; + +/** + * @since 0.5 + * + * @licence GNU GPL v2+ + * @author Katie Filbert < [email protected] > + */ +interface TermLookup { + + /** + * Gets the label of an Entity with the specified EntityId and language code. + * + * @param EntityId $entityId + * @param string $languageCode + * + * @return string + */ + public function getLabel( EntityId $entityId, $languageCode ); + + /** + * Gets all labels of an Entity with the specified EntityId. + * + * @param EntityId $entityId + * + * @return string[] + */ + public function getLabels( EntityId $entityId ); + + /** + * Gets the description of an Entity with the specified EntityId and language code. + * + * @param EntityId $entityId + * @param string $languageCode + * + * @return string + */ + public function getDescription( EntityId $entityId, $languageCode ); + + /** + * Gets all descriptions of an Entity with the specified EntityId. + * + * @param EntityId $entityId + * + * @return string[] + */ + public function getDescriptions( EntityId $entityId ); + +} diff --git a/lib/tests/phpunit/store/EntityTermLookupTest.php b/lib/tests/phpunit/store/EntityTermLookupTest.php new file mode 100644 index 0000000..c237da9 --- /dev/null +++ b/lib/tests/phpunit/store/EntityTermLookupTest.php @@ -0,0 +1,137 @@ +<?php + +namespace Wikibase\Test; + +use Wikibase\DataModel\Entity\EntityId; +use Wikibase\DataModel\Entity\ItemId; +use Wikibase\Lib\Store\EntityTermLookup; + +class EntityTermLookupTest extends \MediaWikiTestCase { + + public function testGetLabel() { + $termLookup = $this->getEntityTermLookup(); + + $label = $termLookup->getLabel( new ItemId( 'Q116' ), 'en' ); + $this->assertEquals( 'New York City', $label ); + } + + public function testGetLabel_notFoundThrowsException() { + $termLookup = $this->getEntityTermLookup(); + + $this->setExpectedException( 'OutOfBoundsException' ); + $termLookup->getLabel( new ItemId( 'Q120' ), 'en' ); + } + + /** + * @dataProvider getLabelsProvider + */ + public function testGetLabels( $expected, EntityId $entityId ) { + $termLookup = $this->getEntityTermLookup(); + + $labels = $termLookup->getLabels( $entityId ); + $this->assertEquals( $expected, $labels ); + } + + public function getLabelsProvider() { + return array( + array( + array( 'en' => 'New York City', 'es' => 'Nueva York' ), + new ItemId( 'Q116' ) + ), + array( + array(), + new ItemId( 'Q120' ) + ) + ); + } + + public function testGetDescription() { + $termLookup = $this->getEntityTermLookup(); + + $description = $termLookup->getDescription( new ItemId( 'Q116' ), 'de' ); + $expected = 'Metropole an der Ostküste der Vereinigten Staaten'; + + $this->assertEquals( $expected, $description ); + } + + public function testGetDescription_notFoundThrowsException() { + $termLookup = $this->getEntityTermLookup(); + + $this->setExpectedException( 'OutOfBoundsException' ); + $termLookup->getDescription( new ItemId( 'Q90000' ), 'fr' ); + } + + /** + * @dataProvider getDescriptionsProvider + */ + public function getDescriptions( $expected, EntityId $entityId ) { + $termLookup = $this->getEntityTermLookup(); + + $descriptions = $termLookup->getDescriptions( $entityId ); + $this->assertEquals( $expected, $descriptions ); + } + + public function getDescriptionsProvider() { + return array( + array( + array( + 'de' => 'Metropole an der Ostküste der Vereinigten Staaten', + 'en' => 'largest city in New York and the United States of America', + ), + new ItemId( 'Q116' ) + ), + array( + array(), + new ItemId( 'Q90001' ) + ) + ); + } + + private function getEntityTermLookup() { + $termIndex = $this->getTermIndex(); + return new EntityTermLookup( $termIndex ); + } + + private function getTermIndex() { + $terms = array( + new \Wikibase\Term( array( + 'entityId' => 116, + 'entityType' => 'item', + 'termType' => 'label', + 'termLanguage' => 'en', + 'termText' => 'New York City' + ) ), + new \Wikibase\Term( array( + 'entityId' => 116, + 'entityType' => 'item', + 'termType' => 'label', + 'termLanguage' => 'es', + 'termText' => 'Nueva York' + ) ), + new \Wikibase\Term( array( + 'entityId' => 116, + 'entityType' => 'item', + 'termType' => 'description', + 'termLanguage' => 'en', + 'termText' => 'largest city in New York and the United States of America' + ) ), + new \Wikibase\Term( array( + 'entityId' => 116, + 'entityType' => 'item', + 'termType' => 'description', + 'termLanguage' => 'de', + 'termText' => 'Metropole an der Ostküste der Vereinigten Staaten' + ) ), + new \Wikibase\Term( array( + 'entityId' => 117, + 'entityType' => 'item', + 'termType' => 'label', + 'termLanguage' => 'en', + 'termText' => 'Berlin' + ) ), + ); + + return new MockTermIndex( $terms ); + } + +} diff --git a/lib/tests/phpunit/store/LanguageFallbackLabelLookupTest.php b/lib/tests/phpunit/store/LanguageFallbackLabelLookupTest.php new file mode 100644 index 0000000..470ffd4 --- /dev/null +++ b/lib/tests/phpunit/store/LanguageFallbackLabelLookupTest.php @@ -0,0 +1,77 @@ +<?php + +namespace Wikibase\Test; + +use Language; +use Wikibase\DataModel\Entity\ItemId; +use Wikibase\LanguageFallbackChainFactory; +use Wikibase\Lib\Store\EntityTermLookup; +use Wikibase\Lib\Store\LanguageFallbackLabelLookup; + +class LanguageFallbackLabelLookupTest extends \MediaWikiTestCase { + + public function testGetLabel() { + $languageFallbackChainFactory = new LanguageFallbackChainFactory(); + $fallbackChain = $languageFallbackChainFactory->newFromLanguage( Language::factory( 'zh' ) ); + + $termLookup = new EntityTermLookup( $this->getTermIndex() ); + $labelLookup = new LanguageFallbackLabelLookup( $termLookup, $fallbackChain ); + + $label = $labelLookup->getLabel( new ItemId( 'Q118' ) ); + $this->assertEquals( '测试', $label ); + } + + public function testGetLabel_notFound() { + $languageFallbackChainFactory = new LanguageFallbackChainFactory(); + $fallbackChain = $languageFallbackChainFactory->newFromLanguage( Language::factory( 'zh' ) ); + + $termLookup = new EntityTermLookup( $this->getTermIndex() ); + $labelLookup = new LanguageFallbackLabelLookup( $termLookup, $fallbackChain ); + + $this->setExpectedException( 'OutOfBoundsException' ); + $label = $labelLookup->getLabel( new ItemId( 'Q120' ) ); + } + + private function getTermIndex() { + $terms = array( + new \Wikibase\Term( array( + 'entityId' => 116, + 'entityType' => 'item', + 'termType' => 'label', + 'termLanguage' => 'en', + 'termText' => 'New York City' + ) ), + new \Wikibase\Term( array( + 'entityId' => 116, + 'entityType' => 'item', + 'termType' => 'label', + 'termLanguage' => 'es', + 'termText' => 'New York City' + ) ), + new \Wikibase\Term( array( + 'entityId' => 116, + 'entityType' => 'item', + 'termType' => 'description', + 'termLanguage' => 'en', + 'termText' => 'Big Apple' + ) ), + new \Wikibase\Term( array( + 'entityId' => 117, + 'entityType' => 'item', + 'termType' => 'label', + 'termLanguage' => 'en', + 'termText' => 'Berlin' + ) ), + new \Wikibase\Term( array( + 'entityId' => 118, + 'entityType' => 'item', + 'termType' => 'label', + 'termLanguage' => 'zh-cn', + 'termText' => '测试' + ) ), + ); + + return new MockTermIndex( $terms ); + } + +} diff --git a/lib/tests/phpunit/store/LanguageLabelLookupTest.php b/lib/tests/phpunit/store/LanguageLabelLookupTest.php new file mode 100644 index 0000000..27aeefa --- /dev/null +++ b/lib/tests/phpunit/store/LanguageLabelLookupTest.php @@ -0,0 +1,70 @@ +<?php + +namespace Wikibase\Test; + +use Wikibase\DataModel\Entity\ItemId; +use Wikibase\Lib\Store\EntityTermLookup; +use Wikibase\Lib\Store\LanguageLabelLookup; + +class LanguageLabelLookupTest extends \MediaWikiTestCase { + + public function testGetLabel() { + $termLookup = new EntityTermLookup( $this->getTermIndex() ); + $labelLookup = new LanguageLabelLookup( $termLookup, 'en' ); + + $label = $labelLookup->getLabel( new ItemId( 'Q116' ) ); + + $this->assertEquals( 'New York City', $label ); + } + + public function testGetLabel_notFound() { + $termLookup = new EntityTermLookup( $this->getTermIndex() ); + $labelLookup = new LanguageLabelLookup( $termLookup, 'en' ); + + $this->setExpectedException( 'OutOfBoundsException' ); + $label = $labelLookup->getLabel( new ItemId( 'Q120' ) ); + } + + private function getTermIndex() { + $terms = array( + new \Wikibase\Term( array( + 'entityId' => 116, + 'entityType' => 'item', + 'termType' => 'label', + 'termLanguage' => 'en', + 'termText' => 'New York City' + ) ), + new \Wikibase\Term( array( + 'entityId' => 116, + 'entityType' => 'item', + 'termType' => 'label', + 'termLanguage' => 'es', + 'termText' => 'New York City' + ) ), + new \Wikibase\Term( array( + 'entityId' => 116, + 'entityType' => 'item', + 'termType' => 'description', + 'termLanguage' => 'en', + 'termText' => 'Big Apple' + ) ), + new \Wikibase\Term( array( + 'entityId' => 117, + 'entityType' => 'item', + 'termType' => 'label', + 'termLanguage' => 'en', + 'termText' => 'Berlin' + ) ), + new \Wikibase\Term( array( + 'entityId' => 118, + 'entityType' => 'item', + 'termType' => 'label', + 'termLanguage' => 'zh-cn', + 'termText' => '测试' + ) ), + ); + + return new MockTermIndex( $terms ); + } + +} diff --git a/lib/tests/phpunit/store/MockTermIndex.php b/lib/tests/phpunit/store/MockTermIndex.php index 24cf50c..f92570e 100644 --- a/lib/tests/phpunit/store/MockTermIndex.php +++ b/lib/tests/phpunit/store/MockTermIndex.php @@ -34,7 +34,7 @@ /** * @param Term[] $terms */ - public function __construct( $terms ) { + public function __construct( array $terms ) { $this->terms = $terms; } @@ -131,10 +131,38 @@ } /** - * @throws Exception always + * @return EntityId[] */ - public function getEntityIdsForLabel( $label, $languageCode = null, $entityType = null, $fuzzySearch = false ) { - throw new Exception( 'not implemented by mock class ' ); + public function getEntityIdsForLabel( $label, $languageCode = null, $entityType = null, + $fuzzySearch = false + ) { + $entityIds = array(); + + foreach( $this->terms as $term ) { + if ( $languageCode !== null && $term->getLanguage() !== $languageCode ) { + continue; + } + + if ( $entityType !== null && $term->getEntityType() !== $entityType ) { + continue; + } + + if ( $term->getType() !== 'label' ) { + continue; + } + + if ( !$fuzzySearch ) { + if ( $term->getText() === $label ) { + $entityIds[] = $term->getEntityId(); + } + } else { + if ( strpos( $term->getText(), $label ) !== false ) { + $entityIds[] = $term->getEntityId(); + } + } + } + + return $entityIds; } /** @@ -152,10 +180,18 @@ } /** - * @throws Exception always + * @return Term[] */ public function getTermsOfEntity( EntityId $id ) { - throw new Exception( 'not implemented by mock class ' ); + $matchingTerms = array(); + + foreach( $this->terms as $term ) { + if ( $term->getEntityId()->equals( $id ) ) { + $matchingTerms[] = $term; + } + } + + return $matchingTerms; } /** -- To view, visit https://gerrit.wikimedia.org/r/169330 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I420df654a8ef7d17e3e45b7e2b0444f5c130a873 Gerrit-PatchSet: 7 Gerrit-Project: mediawiki/extensions/Wikibase Gerrit-Branch: master Gerrit-Owner: Aude <[email protected]> Gerrit-Reviewer: Aude <[email protected]> Gerrit-Reviewer: Daniel Kinzler <[email protected]> Gerrit-Reviewer: Jeroen De Dauw <[email protected]> Gerrit-Reviewer: Thiemo Mättig (WMDE) <[email protected]> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
