Bene has uploaded a new change for review.
https://gerrit.wikimedia.org/r/203527
Change subject: Create a new special page to list properties by data type
......................................................................
Create a new special page to list properties by data type
The new special page is called Special:ListProperties.
Queries can be done via the form or in the format
Special:ListProperties/dataType, eg Special:ListProperties/url.
Bug: T55618
Change-Id: I79a08ec87bf76adba869d4b7eb22098b41fbdb72
---
M lib/includes/store/CachingPropertyInfoStore.php
M lib/includes/store/DummyPropertyInfoStore.php
M lib/includes/store/PropertyInfoStore.php
M lib/includes/store/sql/PropertyInfoTable.php
M lib/tests/phpunit/store/MockPropertyInfoStore.php
M lib/tests/phpunit/store/PropertyInfoStoreTestHelper.php
M lib/tests/phpunit/store/Sql/PropertyInfoTableTest.php
M repo/Wikibase.i18n.alias.php
M repo/Wikibase.php
M repo/i18n/en.json
M repo/includes/DataTypeSelector.php
A repo/includes/specials/SpecialListProperties.php
M repo/includes/store/sql/SqlStore.php
A repo/tests/phpunit/includes/specials/SpecialListPropertiesTest.php
14 files changed, 394 insertions(+), 39 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikibase
refs/changes/27/203527/1
diff --git a/lib/includes/store/CachingPropertyInfoStore.php
b/lib/includes/store/CachingPropertyInfoStore.php
index 79f9e60..9023c68 100644
--- a/lib/includes/store/CachingPropertyInfoStore.php
+++ b/lib/includes/store/CachingPropertyInfoStore.php
@@ -90,6 +90,26 @@
}
/**
+ * @see PropertyInfoStore::getPropertyInfoForDataType
+ *
+ * @param string $dataType
+ *
+ * @return array[]
+ */
+ public function getPropertyInfoForDataType( $dataType ) {
+ $propertyInfo = $this->getAllPropertyInfo();
+ $propertyInfoForDataType = array();
+
+ foreach ( $propertyInfo as $id => $info ) {
+ if ( $info[PropertyInfoStore::KEY_DATA_TYPE] ===
$dataType ) {
+ $propertyInfoForDataType[$id] = $info;
+ }
+ }
+
+ return $propertyInfoForDataType;
+ }
+
+ /**
* @see PropertyInfoStore::getAllPropertyInfo
*
* @return array[]
diff --git a/lib/includes/store/DummyPropertyInfoStore.php
b/lib/includes/store/DummyPropertyInfoStore.php
index 5da4327..09c6504 100644
--- a/lib/includes/store/DummyPropertyInfoStore.php
+++ b/lib/includes/store/DummyPropertyInfoStore.php
@@ -27,6 +27,17 @@
}
/**
+ * @see PropertyInfoStore::getPropertyInfoForDataType
+ *
+ * @param string $dataType
+ *
+ * @return array[]
+ */
+ public function getPropertyInfoForDataType( $dataType ) {
+ return array();
+ }
+
+ /**
* @see PropertyInfoStore::getAllPropertyInfo
*
* @return array[]
diff --git a/lib/includes/store/PropertyInfoStore.php
b/lib/includes/store/PropertyInfoStore.php
index 8c9d01d..5df532c 100644
--- a/lib/includes/store/PropertyInfoStore.php
+++ b/lib/includes/store/PropertyInfoStore.php
@@ -9,6 +9,7 @@
/**
* @license GPL 2+
* @author Daniel Kinzler
+ * @author Bene* < [email protected] >
*/
interface PropertyInfoStore {
@@ -33,6 +34,21 @@
public function getPropertyInfo( PropertyId $propertyId );
/**
+ * Returns the property info for all properties with the given data
type.
+ *
+ * @note: There is no guarantee that an info array is returned for all
existing properties.
+ * Also, it is not guaranteed that the ionfo arrays will contain
all well known fields.
+ *
+ * @param string $dataType
+ *
+ * @return array[] An associative array mapping property IDs to info
arrays.
+ *
+ * @throws StorageException
+ * @throws DBError
+ */
+ public function getPropertyInfoForDataType( $dataType );
+
+ /**
* Returns the property info for all properties.
* The caller is responsible for avoiding calling this if there are too
many properties.
*
diff --git a/lib/includes/store/sql/PropertyInfoTable.php
b/lib/includes/store/sql/PropertyInfoTable.php
index 02e8047..c90f4f2 100644
--- a/lib/includes/store/sql/PropertyInfoTable.php
+++ b/lib/includes/store/sql/PropertyInfoTable.php
@@ -5,6 +5,7 @@
use DBAccessBase;
use DBError;
use InvalidArgumentException;
+use ResultWrapper;
use Wikibase\DataModel\Entity\PropertyId;
/**
@@ -14,6 +15,7 @@
*
* @license GPL 2+
* @author Daniel Kinzler
+ * @author Bene* < [email protected] >
*/
class PropertyInfoTable extends DBAccessBase implements PropertyInfoStore {
@@ -42,9 +44,56 @@
throw new InvalidArgumentException( '$wiki must be a
string or false.' );
}
+ parent::__construct( $wiki );
$this->tableName = 'wb_property_info';
$this->isReadonly = $isReadonly;
- $this->wiki = $wiki;
+ }
+
+ /**
+ * Decodes an info blob.
+ *
+ * @param string|null|bool $blob
+ *
+ * @return array|null The decoded blob as an associative array, or null
if the blob
+ * could not be decoded.
+ */
+ private function decodeInfo( $blob ) {
+ if ( $blob === false || $blob === null ) {
+ return null;
+ }
+
+ $info = json_decode( $blob, true );
+
+ if ( !is_array( $info ) ) {
+ $info = null;
+ }
+
+ return $info;
+ }
+
+ /**
+ * Decodes a result with info blobs.
+ *
+ * @param ResultWrapper $res
+ *
+ * @return array[] The array of decoded blobs
+ */
+ private function decodeInfoArray( ResultWrapper $res ) {
+ $infos = array();
+
+ while ( $row = $res->fetchObject() ) {
+ $info = $this->decodeInfo( $row->pi_info );
+
+ if ( $info === null ) {
+ wfLogWarning( "failed to decode property info
blob for property "
+ . $row->pi_property_id . ": " .
$row->pi_info );
+ continue;
+ }
+
+ $infos[$row->pi_property_id] = $info;
+ }
+
+ return $infos;
}
/**
@@ -83,29 +132,33 @@
}
/**
- * Decodes an info blob.
+ * @see PropertyDataTypeLookup::getPropertyInfoForDataType
*
- * @param string|null|bool $blob
+ * @param string $dataType
*
- * @return array|null The decoded blob as an associative array, or null
if the blob
- * could not be decoded.
+ * @return array[]
+ *
+ * @throws DBError
*/
- protected function decodeInfo( $blob ) {
- if ( $blob === false || $blob === null ) {
- return null;
- }
+ public function getPropertyInfoForDataType( $dataType ) {
+ $dbw = $this->getConnection( DB_SLAVE );
- $info = json_decode( $blob, true );
+ $res = $dbw->select(
+ $this->tableName,
+ array( 'pi_property_id', 'pi_info' ),
+ array( 'pi_type' => $dataType ),
+ __METHOD__
+ );
- if ( !is_array( $info ) ) {
- $info = null;
- }
+ $infos = $this->decodeInfoArray( $res );
- return $info;
+ $this->releaseConnection( $dbw );
+
+ return $infos;
}
/**
- * @see PropertyInfoStore::getAllPropertyInfo
+ * @see PropertyInfoStore::getAllPropertyInfo
*
* @return array[]
*
@@ -121,19 +174,7 @@
__METHOD__
);
- $infos = array();
-
- while ( $row = $res->fetchObject() ) {
- $info = $this->decodeInfo( $row->pi_info );
-
- if ( $info === null ) {
- wfLogWarning( "failed to decode property info
blob for property "
- . $row->pi_property_id . ": " .
$row->pi_info );
- continue;
- }
-
- $infos[$row->pi_property_id] = $info;
- }
+ $infos = $this->decodeInfoArray( $res );
$this->releaseConnection( $dbw );
diff --git a/lib/tests/phpunit/store/MockPropertyInfoStore.php
b/lib/tests/phpunit/store/MockPropertyInfoStore.php
index 18d59bb..140243b 100644
--- a/lib/tests/phpunit/store/MockPropertyInfoStore.php
+++ b/lib/tests/phpunit/store/MockPropertyInfoStore.php
@@ -48,7 +48,27 @@
}
/**
- * @see PropertyInfoStore::getAllPropertyInfo
+ * @see PropertyInfoStore::getPropertyInfoForDataType
+ *
+ * @param string $dataType
+ *
+ * @return array[]
+ */
+ public function getPropertyInfoForDataType( $dataType ) {
+ $propertyInfo = $this->getAllPropertyInfo();
+ $propertyInfoForDataType = array();
+
+ foreach ( $propertyInfo as $id => $info ) {
+ if ( $info[PropertyInfoStore::KEY_DATA_TYPE] ===
$dataType ) {
+ $propertyInfoForDataType[$id] = $info;
+ }
+ }
+
+ return $propertyInfoForDataType;
+ }
+
+ /**
+ * @see PropertyInfoStore::getAllPropertyInfo
*
* @return array[]
*/
diff --git a/lib/tests/phpunit/store/PropertyInfoStoreTestHelper.php
b/lib/tests/phpunit/store/PropertyInfoStoreTestHelper.php
index 44c59a9..da2a08e 100644
--- a/lib/tests/phpunit/store/PropertyInfoStoreTestHelper.php
+++ b/lib/tests/phpunit/store/PropertyInfoStoreTestHelper.php
@@ -85,6 +85,28 @@
$this->test->assertEquals( $info23, $table->getPropertyInfo(
$p23 ), "should return what was set" );
}
+ public function testGetPropertyInfoForDataType() {
+ $table = $this->newPropertyInfoStore();
+ $p23 = new PropertyId( 'P23' );
+ $p42 = new PropertyId( 'P42' );
+ $info23 = array( PropertyInfoStore::KEY_DATA_TYPE => 'string' );
+ $info42 = array( PropertyInfoStore::KEY_DATA_TYPE =>
'commonsMedia', 'foo' => 'bar' );
+
+ $this->test->assertCount( 0,
$table->getPropertyInfoForDataType( 'commonsMedia' ), "should initially be
empty" );
+
+ $table->setPropertyInfo( $p23, $info23 );
+ $this->test->assertCount( 0,
$table->getPropertyInfoForDataType( 'commonsMedia' ), "after adding one
property" );
+
+ $table->setPropertyInfo( $p42, $info42 );
+ $this->test->assertCount( 1,
$table->getPropertyInfoForDataType( 'commonsMedia' ), "after adding the second
property" );
+
+ $table->removePropertyInfo( $p23 );
+ $this->test->assertCount( 1,
$table->getPropertyInfoForDataType( 'commonsMedia' ), "after removing one
property" );
+
+ $table->removePropertyInfo( $p42 );
+ $this->test->assertCount( 0,
$table->getPropertyInfoForDataType( 'commonsMedia' ), "after removing the
second property" );
+ }
+
public function testGetAllPropertyInfo() {
$table = $this->newPropertyInfoStore();
$p23 = new PropertyId( 'P23' );
diff --git a/lib/tests/phpunit/store/Sql/PropertyInfoTableTest.php
b/lib/tests/phpunit/store/Sql/PropertyInfoTableTest.php
index 4662873..2a03240 100644
--- a/lib/tests/phpunit/store/Sql/PropertyInfoTableTest.php
+++ b/lib/tests/phpunit/store/Sql/PropertyInfoTableTest.php
@@ -64,6 +64,10 @@
$this->helper->testGetPropertyInfo();
}
+ public function testGetPropertyInfoForDataType() {
+ $this->helper->testGetPropertyInfoForDataType();
+ }
+
public function testGetAllPropertyInfo() {
$this->helper->testGetAllPropertyInfo();
}
diff --git a/repo/Wikibase.i18n.alias.php b/repo/Wikibase.i18n.alias.php
index a449b40..be8a5bc 100644
--- a/repo/Wikibase.i18n.alias.php
+++ b/repo/Wikibase.i18n.alias.php
@@ -22,6 +22,7 @@
'GoToLinkedPage' => array( 'GoToLinkedPage' ),
'ItemDisambiguation' => array( 'ItemDisambiguation' ),
'ListDatatypes' => array( 'ListDatatypes' ),
+ 'ListProperties' => array( 'ListProperties' ),
'SetLabel' => array( 'SetLabel' ),
'SetDescription' => array( 'SetDescription' ),
'SetAliases' => array( 'SetAliases' ),
diff --git a/repo/Wikibase.php b/repo/Wikibase.php
index 5a73d8e..eb89cda 100644
--- a/repo/Wikibase.php
+++ b/repo/Wikibase.php
@@ -180,6 +180,7 @@
$wgSpecialPages['EntitiesWithoutLabel'] =
array( 'Wikibase\Repo\Specials\SpecialEntitiesWithoutPageFactory',
'newSpecialEntitiesWithoutLabel' );
$wgSpecialPages['EntitiesWithoutDescription'] = array(
'Wikibase\Repo\Specials\SpecialEntitiesWithoutPageFactory',
'newSpecialEntitiesWithoutDescription' );
$wgSpecialPages['ListDatatypes']
= 'Wikibase\Repo\Specials\SpecialListDatatypes';
+ $wgSpecialPages['ListProperties']
= 'Wikibase\Repo\Specials\SpecialListProperties';
$wgSpecialPages['DispatchStats']
= 'Wikibase\Repo\Specials\SpecialDispatchStats';
$wgSpecialPages['EntityData']
= 'Wikibase\Repo\Specials\SpecialEntityData';
$wgSpecialPages['MyLanguageFallbackChain'] =
'Wikibase\Repo\Specials\SpecialMyLanguageFallbackChain';
diff --git a/repo/i18n/en.json b/repo/i18n/en.json
index 71e8bd6..461f15a 100644
--- a/repo/i18n/en.json
+++ b/repo/i18n/en.json
@@ -245,6 +245,10 @@
"wikibase-listdatatypes-intro": "This is a list of all data types
available on this installation:",
"wikibase-history-title-with-label": "Revision history of \"$2\" ($1)",
"wikibase-history-title-without-label": "Revision history of ($1)",
+ "special-listproperties": "List of properties by data type",
+ "wikibase-listproperties-legend": "Get list of properties by data type",
+ "wikibase-listproperties-label-datatype": "Data type:",
+ "wikibase-listproperties-submit": "Find",
"special-entitieswithoutdescription": "Entities without description",
"wikibase-entitieswithoutdescription-legend": "Get list of entities
without description",
"special-entitieswithoutlabel": "Entities without label",
diff --git a/repo/includes/DataTypeSelector.php
b/repo/includes/DataTypeSelector.php
index f0ae7fa..9fd9a25 100644
--- a/repo/includes/DataTypeSelector.php
+++ b/repo/includes/DataTypeSelector.php
@@ -55,10 +55,11 @@
*
* @param string $id
* @param string $name
+ * @param string $selectedTypeId
*
* @return string
*/
- public function getHtml( $id = 'datatype', $name = 'datatype' ) {
+ public function getHtml( $id = 'datatype', $name = 'datatype',
$selectedTypeId = '' ) {
$dataTypes = array();
foreach ( $this->dataTypes as $dataType ) {
@@ -70,9 +71,15 @@
$html = '';
foreach ( $dataTypes as $typeId => $typeLabel ) {
+ $attrs = array( 'value' => $typeId );
+
+ if ( $typeId === $selectedTypeId ) {
+ $attrs['selected'] = true;
+ }
+
$html .= Html::element(
'option',
- array( 'value' => $typeId ),
+ $attrs,
$typeLabel
);
}
diff --git a/repo/includes/specials/SpecialListProperties.php
b/repo/includes/specials/SpecialListProperties.php
new file mode 100644
index 0000000..00e56b6
--- /dev/null
+++ b/repo/includes/specials/SpecialListProperties.php
@@ -0,0 +1,159 @@
+<?php
+
+namespace Wikibase\Repo\Specials;
+
+use DataTypes\DataTypeFactory;
+use Html;
+use Linker;
+use MWException;
+use Wikibase\DataModel\Entity\PropertyId;
+use Wikibase\DataTypeSelector;
+use Wikibase\PropertyInfoStore;
+use Wikibase\Repo\WikibaseRepo;
+
+/**
+ * Special page to list properties by data type
+ *
+ * @since 0.5
+ * @licence GNU GPL v2+
+ * @author Bene* < [email protected] >
+ */
+class SpecialListProperties extends SpecialWikibasePage {
+
+ /**
+ * @var DataTypeFactory
+ */
+ private $dataTypeFactory;
+
+ /**
+ * @var PropertyInfoStore
+ */
+ private $propertyInfoStore;
+
+ /**
+ * @var string
+ */
+ private $dataType;
+
+ /**
+ * @since 0.5
+ */
+ public function __construct() {
+ parent::__construct( 'ListProperties' );
+
+ $this->dataTypeFactory =
WikibaseRepo::getDefaultInstance()->getDataTypeFactory();
+ $this->propertyInfoStore =
WikibaseRepo::getDefaultInstance()->getStore()->getPropertyInfoStore();
+ }
+
+ /**
+ * @see SpecialWikibasePage::execute
+ *
+ * @since 0.5
+ *
+ * @param string|null $subPage
+ */
+ public function execute( $subPage ) {
+ parent::execute( $subPage );
+
+ $this->prepareArguments( $subPage );
+ $this->showForm();
+
+ if ( $this->dataType !== null ) {
+ $this->showQuery();
+ }
+ }
+
+ private function prepareArguments( $subPage ) {
+ $request = $this->getRequest();
+
+ $this->dataType = $request->getText( 'datatype', $subPage );
+ if ( !in_array( $this->dataType,
$this->dataTypeFactory->getTypeIds() ) ) {
+ $this->dataType = null;
+ }
+ }
+
+ private function showForm() {
+ $dataTypeSelect = new DataTypeSelector(
+ $this->dataTypeFactory->getTypes(),
+ $this->getLanguage()->getCode()
+ );
+
+ $this->getOutput()->addHTML(
+ Html::openElement(
+ 'form',
+ array(
+ 'action' =>
$this->getPageTitle()->getLocalURL(),
+ 'name' => 'listproperties',
+ 'id' => 'wb-listproperties-form'
+ )
+ ) .
+ Html::input (
+ 'title',
+ $this->getPageTitle()->getPrefixedText(),
+ 'hidden',
+ array()
+ ) .
+ Html::openElement( 'fieldset' ) .
+ Html::element(
+ 'legend',
+ array(),
+ $this->msg( 'wikibase-listproperties-legend'
)->text()
+ ) .
+ Html::openElement( 'p' ) .
+ Html::element(
+ 'label',
+ array(
+ 'for' => 'wb-listproperties-datatype'
+ ),
+ $this->msg(
'wikibase-listproperties-label-datatype' )->text()
+ ) . ' ' .
+ $dataTypeSelect->getHTML( 'wb-listproperties-datatype',
'datatype', $this->dataType ) . ' ' .
+ Html::input(
+ 'submit',
+ $this->msg( 'wikibase-listproperties-submit'
)->text(),
+ 'submit',
+ array(
+ 'id' =>
'wikibase-listproperties-submit',
+ 'class' => 'wb-input-button'
+ )
+ ) .
+ Html::closeElement( 'p' ) .
+ Html::closeElement( 'fieldset' ) .
+ Html::closeElement( 'form' )
+ );
+ }
+
+ private function showQuery() {
+ $propertyInfoForDataType =
$this->propertyInfoStore->getPropertyInfoForDataType( $this->dataType );
+
+ if ( empty( $propertyInfoForDataType ) ) {
+ $this->getOutput()->addWikiMsg( 'specialpage-empty' );
+ return;
+ }
+
+ $html = Html::openElement( 'ul' );
+
+ foreach ( $propertyInfoForDataType as $numericId => $info ) {
+ $row = $this->formatRow( PropertyId::newFromNumber(
$numericId ) );
+ $html .= Html::rawElement( 'li', array(), $row );
+ }
+
+ $html .= Html::closeElement( 'ul' );
+ $this->getOutput()->addHTML( $html );
+ }
+
+ /**
+ * @see SpecialWikibaseQueryPage::formatRow
+ */
+ private function formatRow( PropertyId $propertyId ) {
+ try {
+ $title =
WikibaseRepo::getDefaultInstance()->getEntityContentFactory()->getTitleForId(
$propertyId );
+ return Linker::linkKnown( $title );
+ } catch ( MWException $e ) {
+ wfWarn( "Error formatting result row: " .
$e->getMessage() );
+ return false;
+ }
+ }
+
+}
+
diff --git a/repo/includes/store/sql/SqlStore.php
b/repo/includes/store/sql/SqlStore.php
index 395cbf0..41a820c 100644
--- a/repo/includes/store/sql/SqlStore.php
+++ b/repo/includes/store/sql/SqlStore.php
@@ -81,9 +81,9 @@
private $entityInfoBuilderFactory = null;
/**
- * @var PropertyInfoTable|null
+ * @var PropertyInfoStore|null
*/
- private $propertyInfoTable = null;
+ private $propertyInfoStore = null;
/**
* @var ChangesTable|null
@@ -657,19 +657,19 @@
* @return PropertyInfoStore
*/
public function getPropertyInfoStore() {
- if ( !$this->propertyInfoTable ) {
- $this->propertyInfoTable =
$this->newPropertyInfoTable();
+ if ( !$this->propertyInfoStore ) {
+ $this->propertyInfoStore =
$this->newPropertyInfoStore();
}
- return $this->propertyInfoTable;
+ return $this->propertyInfoStore;
}
/**
- * Creates a new PropertyInfoTable
+ * Creates a new PropertyInfoStore
*
- * @return PropertyInfoTable
+ * @return PropertyInfoStore
*/
- private function newPropertyInfoTable() {
+ private function newPropertyInfoStore() {
$usePropertyInfoTable = WikibaseRepo::getDefaultInstance()->
getSettings()->getSetting( 'usePropertyInfoTable' );
diff --git a/repo/tests/phpunit/includes/specials/SpecialListPropertiesTest.php
b/repo/tests/phpunit/includes/specials/SpecialListPropertiesTest.php
new file mode 100644
index 0000000..07fc67f
--- /dev/null
+++ b/repo/tests/phpunit/includes/specials/SpecialListPropertiesTest.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Wikibase\Test;
+
+use Language;
+use Wikibase\Repo\Specials\SpecialListProperties;
+use Wikibase\Test\SpecialPageTestBase;
+
+/**
+ * @covers Wikibase\Repo\Specials\SpecialListProperties
+ *
+ * @group Wikibase
+ * @group WikibaseRepo
+ * @group SpecialPage
+ * @group WikibaseSpecialPage
+ *
+ * @licence GNU GPL v2+
+ * @author Bene* < [email protected] >
+ */
+class SpecialListPropertiesTest extends SpecialPageTestBase {
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->setMwGlobals( array(
+ 'wgContLang' => Language::factory( 'qqx' )
+ ) );
+ }
+
+ protected function newSpecialPage() {
+ return new SpecialListProperties();
+ }
+
+ public function testExecute() {
+ // This also tests that there is no fatal error, that the
restriction handling is working
+ // and doesn't block. That is, the default should let the user
execute the page.
+ list( $output, ) = $this->executeSpecialPage( '' );
+
+ $this->assertInternalType( 'string', $output );
+ $this->assertContains( 'wikibase-listproperties-summary',
$output );
+ $this->assertContains( 'wikibase-listproperties-legend',
$output );
+
+ list( $output, ) = $this->executeSpecialPage( 'url' );
+
+ $this->assertContains( 'specialpage-empty', $output );
+ }
+
+}
+
--
To view, visit https://gerrit.wikimedia.org/r/203527
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I79a08ec87bf76adba869d4b7eb22098b41fbdb72
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Bene <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits