jenkins-bot has submitted this change and it was merged.
Change subject: Introduce PageImagesDataUpdate for PageImages extension
......................................................................
Introduce PageImagesDataUpdate for PageImages extension
Bug: T112865
Change-Id: I5fba0e4a87d3034ca7d63ae9332eeb5f9b3bf449
---
M docs/options.wiki
M repo/config/Wikibase.default.php
A repo/includes/DataUpdates/PageImagesDataUpdate.php
M repo/includes/EntityParserOutputGenerator.php
A repo/tests/phpunit/includes/DataUpdates/PageImagesDataUpdateTest.php
5 files changed, 352 insertions(+), 0 deletions(-)
Approvals:
Daniel Kinzler: Looks good to me, approved
jenkins-bot: Verified
diff --git a/docs/options.wiki b/docs/options.wiki
index 0af7d25..83e81da 100644
--- a/docs/options.wiki
+++ b/docs/options.wiki
@@ -46,6 +46,7 @@
;dataRightsUrl: Url to link to license for data contents. Defaults to
$wgRightsUrl setting.
;dataRightsText: Text for data license link. Defaults to $wgRightsText setting.
;badgeItems: Items allowed to be used as badges. This setting expects an array
of serialized item ids pointing to their CSS class names, like <code>array(
'Q101' => 'wb-badge-goodarticle' )</code>. With this class name it is possible
to change the icon of a specific badge.
+;preferredPageImagesProperties: List of image property id strings, in order of
preference, that should be considered for the <code>page_image</code> page
property. Defaults to an empty array.
;conceptBaseUri: Base URI for building concept URIs (for example used in Rdf
output). This has to include the protocol and domain, only an entity identifier
will be appended.
=== Expert Settings ===
diff --git a/repo/config/Wikibase.default.php b/repo/config/Wikibase.default.php
index dd84ee2..863bb9c 100644
--- a/repo/config/Wikibase.default.php
+++ b/repo/config/Wikibase.default.php
@@ -38,6 +38,10 @@
// Items allowed to be used as badges pointing to their CSS
class names
'badgeItems' => array(),
+ // List of image property id strings, in order of preference,
that should be considered for
+ // the "page_image" page property.
+ 'preferredPageImagesProperties' => array(),
+
// Number of seconds for which data output shall be cached.
// Note: keep that low, because such caches cannot always be
purged easily.
'dataSquidMaxage' => $wgSquidMaxage,
diff --git a/repo/includes/DataUpdates/PageImagesDataUpdate.php
b/repo/includes/DataUpdates/PageImagesDataUpdate.php
new file mode 100644
index 0000000..43f6eb9
--- /dev/null
+++ b/repo/includes/DataUpdates/PageImagesDataUpdate.php
@@ -0,0 +1,195 @@
+<?php
+
+namespace Wikibase\Repo\DataUpdates;
+
+use DataValues\StringValue;
+use Wikibase\DataModel\Entity\PropertyId;
+use Wikibase\DataModel\Snak\PropertyValueSnak;
+use Wikibase\DataModel\Snak\Snak;
+use Wikibase\DataModel\Statement\Statement;
+use Wikibase\DataModel\Statement\StatementList;
+
+/**
+ * Code to make the PageImages extension aware of pages in the Wikibase
namespaces.
+ *
+ * @since 0.5
+ *
+ * @licence GNU GPL v2+
+ * @author Thiemo Mättig
+ */
+class PageImagesDataUpdate {
+
+ /**
+ * @var int[] Hash table of image property id strings pointing to
priorities (smaller numbers
+ * are better).
+ */
+ private $propertyPriorities = array();
+
+ /**
+ * @var string
+ */
+ private $bestProperty;
+
+ /**
+ * @var int
+ */
+ private $bestRank;
+
+ /**
+ * @var string
+ */
+ private $bestFileName;
+
+ /**
+ * @param string[] $imagePropertyIds List of image property id strings,
in order of preference.
+ */
+ public function __construct( array $imagePropertyIds ) {
+ $this->setPropertyIds( $imagePropertyIds );
+ }
+
+ /**
+ * @param string[] $ids
+ */
+ private function setPropertyIds( array $ids ) {
+ $this->propertyPriorities = array_flip( array_unique(
array_values( $ids ) ) );
+ }
+
+ /**
+ * @param StatementList $statements
+ *
+ * @return string|null The file's page name without the NS_FILE
namespace, or null if not found.
+ */
+ public function getBestImageFileName( StatementList $statements ) {
+ $this->bestProperty = null;
+ $this->bestRank = null;
+ $this->bestFileName = null;
+
+ foreach ( $statements->toArray() as $statement ) {
+ $this->processStatement( $statement );
+ }
+
+ return $this->bestFileName;
+ }
+
+ /**
+ * @param Statement $statement
+ */
+ public function processStatement( Statement $statement ) {
+ $this->processSnak(
+ $statement->getMainSnak(),
+ $statement->getPropertyId(),
+ $statement->getRank()
+ );
+ }
+
+ /**
+ * @param Snak $snak
+ * @param PropertyId $propertyId
+ * @param int $rank
+ */
+ private function processSnak(
+ Snak $snak,
+ PropertyId $propertyId,
+ $rank = Statement::RANK_NORMAL
+ ) {
+ $id = $propertyId->getSerialization();
+ $fileName = str_replace( ' ', '_', $this->getString( $snak ) );
+
+ if ( $fileName === null || $fileName === '' ) {
+ return;
+ }
+
+ if ( !$this->isAcceptableRank( $rank ) ) {
+ return;
+ }
+
+ if ( !$this->isAcceptablePriority( $id ) ) {
+ return;
+ }
+
+ if ( $this->isSamePriority( $id ) && !$this->isBetterRank(
$rank ) ) {
+ return;
+ }
+
+ $this->bestProperty = $id;
+ $this->bestRank = $rank;
+ $this->bestFileName = $fileName;
+ }
+
+ /**
+ * @param Snak $snak
+ *
+ * @return string|null
+ */
+ private function getString( Snak $snak ) {
+ if ( $snak instanceof PropertyValueSnak ) {
+ $value = $snak->getDataValue();
+
+ if ( $value instanceof StringValue ) {
+ return $value->getValue();
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @param string $propertyId
+ *
+ * @return bool True if the property is configured as one of the image
properties and it's
+ * priority is equal or better than the current best.
+ */
+ private function isAcceptablePriority( $propertyId ) {
+ if ( !array_key_exists( $propertyId, $this->propertyPriorities
) ) {
+ return false;
+ }
+
+ if ( $this->bestProperty === null ) {
+ return true;
+ }
+
+ $priority = $this->propertyPriorities[$propertyId];
+ $bestPriority = $this->propertyPriorities[$this->bestProperty];
+ return $priority <= $bestPriority;
+ }
+
+ /**
+ * @param string $propertyId
+ *
+ * @return bool True if the property's priority is identical to the
current best.
+ */
+ private function isSamePriority( $propertyId ) {
+ if ( $this->bestProperty === null ) {
+ return false;
+ }
+
+ $priority = $this->propertyPriorities[$propertyId];
+ $bestPriority = $this->propertyPriorities[$this->bestProperty];
+ return $priority === $bestPriority;
+ }
+
+ /**
+ * @param int $rank
+ *
+ * @return bool True if the rank is not deprecated.
+ */
+ private function isAcceptableRank( $rank ) {
+ return $rank !== Statement::RANK_DEPRECATED;
+ }
+
+ /**
+ * @param int $rank
+ *
+ * @return bool
+ */
+ private function isBetterRank( $rank ) {
+ if ( $this->bestRank === null ) {
+ // Everything is better than nothing.
+ return true;
+ }
+
+ // Ranks are guaranteed to be in increasing, numerical order.
+ return $rank > $this->bestRank;
+ }
+
+}
diff --git a/repo/includes/EntityParserOutputGenerator.php
b/repo/includes/EntityParserOutputGenerator.php
index 0402924..ddb3fc5 100644
--- a/repo/includes/EntityParserOutputGenerator.php
+++ b/repo/includes/EntityParserOutputGenerator.php
@@ -15,6 +15,7 @@
use Wikibase\DataModel\SiteLink;
use Wikibase\DataModel\SiteLinkList;
use Wikibase\DataModel\Snak\Snak;
+use Wikibase\DataModel\Statement\StatementList;
use Wikibase\DataModel\Statement\StatementListProvider;
use Wikibase\DataModel\Term\FingerprintProvider;
use Wikibase\Lib\Store\EntityInfo;
@@ -22,8 +23,10 @@
use Wikibase\Lib\Store\EntityInfoTermLookup;
use Wikibase\Lib\Store\EntityTitleLookup;
use Wikibase\Lib\Store\LanguageFallbackLabelDescriptionLookup;
+use Wikibase\Repo\DataUpdates\PageImagesDataUpdate;
use Wikibase\Repo\LinkedData\EntityDataFormatProvider;
use Wikibase\Repo\View\RepoSpecialPageLinker;
+use Wikibase\Repo\WikibaseRepo;
use Wikibase\View\EmptyEditSectionGenerator;
use Wikibase\View\EntityViewFactory;
use Wikibase\View\Template\TemplateFactory;
@@ -129,6 +132,7 @@
* @param ParserOptions $options
* @param bool $generateHtml
*
+ * @throws InvalidArgumentException
* @return ParserOutput
*/
public function getParserOutput(
@@ -172,6 +176,7 @@
$configVars = $this->configBuilder->build( $entity );
$parserOutput->addJsConfigVars( $configVars );
+ $this->addBestImageToParserOutput( $parserOutput,
$entity->getStatements() );
$this->addLinksToParserOutput( $parserOutput, $usedEntityIds,
$snaks );
// FIXME: OCP violation -
https://phabricator.wikimedia.org/T75495
@@ -210,6 +215,19 @@
return $parserOutput;
}
+ private function addBestImageToParserOutput( ParserOutput
$parserOutput, StatementList $statements ) {
+ $repo = WikibaseRepo::getDefaultInstance();
+ // TODO: Inject this setting!
+ $propertyIds = $repo->getSettings()->getSetting(
'preferredPageImagesProperties' );
+
+ if ( !empty( $propertyIds ) ) {
+ $dataUpdate = new PageImagesDataUpdate( $propertyIds );
+ $fileName = $dataUpdate->getBestImageFileName(
$statements );
+ // This property name is the only "soft dependency" on
the PageImages extension.
+ $parserOutput->setProperty( 'page_image', $fileName );
+ }
+ }
+
/**
* @param ParserOutput $parserOutput
* @param EntityId[] $usedEntityIds
diff --git
a/repo/tests/phpunit/includes/DataUpdates/PageImagesDataUpdateTest.php
b/repo/tests/phpunit/includes/DataUpdates/PageImagesDataUpdateTest.php
new file mode 100644
index 0000000..6be288d
--- /dev/null
+++ b/repo/tests/phpunit/includes/DataUpdates/PageImagesDataUpdateTest.php
@@ -0,0 +1,134 @@
+<?php
+
+namespace Wikibase\Repo\Tests\DataUpdates;
+
+use DataValues\BooleanValue;
+use DataValues\StringValue;
+use PHPUnit_Framework_TestCase;
+use Wikibase\DataModel\Snak\PropertyNoValueSnak;
+use Wikibase\DataModel\Snak\PropertySomeValueSnak;
+use Wikibase\DataModel\Snak\PropertyValueSnak;
+use Wikibase\DataModel\Statement\Statement;
+use Wikibase\DataModel\Statement\StatementList;
+use Wikibase\Repo\DataUpdates\PageImagesDataUpdate;
+
+/**
+ * @covers Wikibase\Repo\DataUpdates\PageImagesDataUpdate
+ *
+ * @since 0.5
+ *
+ * @group WikibaseRepo
+ * @group Wikibase
+ *
+ * @license GNU GPL v2+
+ * @author Thiemo Mättig
+ */
+class PageImagesDataUpdateTest extends PHPUnit_Framework_TestCase {
+
+ /**
+ * @param string[] $propertyIds
+ *
+ * @return PageImagesDataUpdate
+ */
+ private function newInstance( array $propertyIds ) {
+ return new PageImagesDataUpdate( $propertyIds );
+ }
+
+ /**
+ * @param StatementList $statements
+ * @param int $propertyId
+ * @param string $string
+ * @param int $rank
+ */
+ private function addStatement(
+ StatementList $statements,
+ $propertyId,
+ $string,
+ $rank = Statement::RANK_NORMAL
+ ) {
+ $statement = new Statement(
+ new PropertyValueSnak( $propertyId, new StringValue(
$string ) )
+ );
+ $statement->setRank( $rank );
+ $statements->addStatement( $statement );
+ }
+
+ /**
+ * @dataProvider constructorArgumentsProvider
+ */
+ public function testConstructor( $propertyIds ) {
+ $instance = $this->newInstance( $propertyIds );
+ $this->assertInstanceOf(
'Wikibase\Repo\DataUpdates\PageImagesDataUpdate', $instance );
+ }
+
+ public function constructorArgumentsProvider() {
+ return array(
+ 'Empty' => array( array() ),
+ 'Property ids' => array( array( 'P1', 'P9999' ) ),
+ 'Non-property ids' => array( array( 'Q1' ) ),
+ 'Invalid ids' => array( array( 'invalid' ) ),
+ );
+ }
+
+ /**
+ * @dataProvider bestImageProvider
+ */
+ public function testGetBestImageFileName(
+ StatementList $statements,
+ array $propertyIds,
+ $expected
+ ) {
+ $instance = $this->newInstance( $propertyIds );
+ $this->assertSame( $expected, $instance->getBestImageFileName(
$statements ) );
+ }
+
+ public function bestImageProvider() {
+ $statements = new StatementList();
+
+ $this->addStatement( $statements, 1, '1.jpg' );
+
+ $statements->addNewStatement( new PropertyNoValueSnak( 2 ) );
+ $statements->addNewStatement( new PropertySomeValueSnak( 2 ) );
+ $statements->addNewStatement( new PropertyValueSnak( 2, new
BooleanValue( true ) ) );
+ $this->addStatement( $statements, 2, '' );
+ $this->addStatement( $statements, 2, '2.jpg',
Statement::RANK_DEPRECATED );
+
+ $statements->addNewStatement( new PropertySomeValueSnak( 3 ) );
+ $this->addStatement( $statements, 3, '3a.jpg' );
+ $this->addStatement( $statements, 3, '3b.jpg' );
+
+ $this->addStatement( $statements, 4, 'Four 1.jpg',
Statement::RANK_DEPRECATED );
+ $this->addStatement( $statements, 4, 'Four 2.jpg' );
+ $this->addStatement( $statements, 4, 'Four 3.jpg' );
+
+ $this->addStatement( $statements, 5, '5a.jpg' );
+ $this->addStatement( $statements, 4, '5b.jpg',
Statement::RANK_DEPRECATED );
+ $this->addStatement( $statements, 5, '5c.jpg',
Statement::RANK_PREFERRED );
+ $this->addStatement( $statements, 5, '5d.jpg' );
+ $this->addStatement( $statements, 5, '5e.jpg',
Statement::RANK_PREFERRED );
+
+ return array(
+ // Find nothing for various reasons.
+ 'Ignore non-strings' => array( $statements, array( 'P2'
), null ),
+ 'Property not found' => array( $statements, array(
'P9999' ), null ),
+ 'Not a property id' => array( $statements, array( 'Q1'
), null ),
+ 'Invalid id' => array( $statements, array( 'invalid' ),
null ),
+ 'Ignore misconfiguration' => array( $statements, array(
'P1', 'P2', 'P1' ), '1.jpg' ),
+ 'Ignore keys' => array( $statements, array( 2 => 'P1',
1 => 'P2' ), '1.jpg' ),
+
+ // Simple searches.
+ 'Find 1' => array( $statements, array( 'P1' ), '1.jpg'
),
+ 'Skip non-strings' => array( $statements, array( 'P3'
), '3a.jpg' ),
+ 'Skip missing ids' => array( $statements, array(
'P9999', 'P1' ), '1.jpg' ),
+ 'Skip item ids' => array( $statements, array( 'Q1',
'P1' ), '1.jpg' ),
+ 'Skip invalid ids' => array( $statements, array(
'invalid', 'P1' ), '1.jpg' ),
+
+ 'Increasing order' => array( $statements, array( 'P1',
'P2', 'P3' ), '1.jpg' ),
+ 'Decreasing order' => array( $statements, array( 'P3',
'P2', 'P1' ), '3a.jpg' ),
+
+ 'Skip deprecated' => array( $statements, array( 'P4' ),
'Four_2.jpg' ),
+ 'Prefer preferred' => array( $statements, array( 'P5'
), '5c.jpg' ),
+ );
+ }
+
+}
--
To view, visit https://gerrit.wikimedia.org/r/243673
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I5fba0e4a87d3034ca7d63ae9332eeb5f9b3bf449
Gerrit-PatchSet: 7
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Thiemo Mättig (WMDE) <[email protected]>
Gerrit-Reviewer: Aude <[email protected]>
Gerrit-Reviewer: Daniel Kinzler <[email protected]>
Gerrit-Reviewer: Hoo man <[email protected]>
Gerrit-Reviewer: Jonas Kress (WMDE) <[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