jenkins-bot has submitted this change and it was merged.
Change subject: Add a "WikibaseClientOtherProjectsSidebar" hook
......................................................................
Add a "WikibaseClientOtherProjectsSidebar" hook
In order to be able to overwrite parts of the sidebar
for Wikimedia specific things.
For now we plan to use this in order to show links to
commons categories in the sidebar.
I figured it would be much safer to validate the data
we get from the hook handler and given the size of the
array it really isn't expensive. If you still think the
data shouldn't be validated for some reason, I'm ok
with removing that part.
Bug: T94989
Change-Id: Ica9b1bac5394cddc021c013da4e6b5a74651c4aa
---
M client/includes/Hooks/OtherProjectsSidebarGenerator.php
M client/tests/phpunit/includes/Hooks/OtherProjectsSidebarGeneratorTest.php
M docs/hooks.txt
3 files changed, 268 insertions(+), 16 deletions(-)
Approvals:
Aude: Looks good to me, approved
jenkins-bot: Verified
diff --git a/client/includes/Hooks/OtherProjectsSidebarGenerator.php
b/client/includes/Hooks/OtherProjectsSidebarGenerator.php
index 85b8a62..285bbb5 100644
--- a/client/includes/Hooks/OtherProjectsSidebarGenerator.php
+++ b/client/includes/Hooks/OtherProjectsSidebarGenerator.php
@@ -2,10 +2,12 @@
namespace Wikibase\Client\Hooks;
+use Hooks;
use Site;
use SiteStore;
use Title;
use Wikibase\DataModel\SiteLink;
+use Wikibase\DataModel\Entity\ItemId;
use Wikibase\Lib\Store\SiteLinkLookup;
/**
@@ -64,16 +66,74 @@
* group and global ids.
*/
public function buildProjectLinkSidebar( Title $title ) {
- return $this->buildSidebarFromSiteLinks( $this->getSiteLinks(
$title ) );
+ $itemId = $this->getItemId( $title );
+ if ( !$itemId ) {
+ return array();
+ }
+
+ $sidebar = $this->buildPreliminarySidebarFromSiteLinks(
$this->getSiteLinks( $itemId ) );
+ $sidebar = $this->runHook( $itemId, $sidebar );
+
+ return $this->sortAndFlattenSidebar( $sidebar );
+ }
+
+ /**
+ * @param ItemId $itemId
+ * @param array $sidebar
+ *
+ * @return array
+ */
+ private function runHook( ItemId $itemId, array $sidebar ) {
+ $newSidebar = $sidebar;
+
+ Hooks::run( 'WikibaseClientOtherProjectsSidebar', array(
$itemId, &$newSidebar ) );
+
+ if ( $newSidebar === $sidebar ) {
+ return $sidebar;
+ }
+
+ if ( !is_array( $newSidebar ) || !$this->isValidSidebar(
$newSidebar ) ) {
+ wfLogWarning( 'Other projects sidebar data invalid
after hook run.' );
+ return $sidebar;
+ }
+
+ return $newSidebar;
+ }
+
+ /**
+ * @param array $sidebar
+ * @return bool
+ */
+ private function isValidSidebar( array $sidebar ) {
+ // Make sure all required array keys are set and are string.
+ foreach ( $sidebar as $siteGroup => $perSiteGroup ) {
+ if ( !is_string( $siteGroup ) || !is_array(
$perSiteGroup ) ) {
+ return false;
+ }
+
+ foreach ( $perSiteGroup as $siteId => $perSite ) {
+ if ( !is_string( $siteId )
+ || !isset( $perSite['msg'] )
+ || !isset( $perSite['class'] )
+ || !isset( $perSite['href'] )
+ || !is_string( $perSite['msg'] )
+ || !is_string( $perSite['class'] )
+ || !is_string( $perSite['href'] )
+ ) {
+ return false;
+ }
+ }
+ }
+
+ return true;
}
/**
* @param SiteLink[] $siteLinks
*
- * @return array[] Array of arrays of attributes describing sidebar
links, sorted by the site's
- * group and global ids.
+ * @return array[] Arrays of link attributes indexed by site group and
by global site id.
*/
- private function buildSidebarFromSiteLinks( array $siteLinks ) {
+ private function buildPreliminarySidebarFromSiteLinks( array $siteLinks
) {
$linksByGroup = array();
foreach ( $siteLinks as $siteLink ) {
@@ -91,7 +151,7 @@
}
}
- return $this->sortAndFlattenSidebar( $linksByGroup );
+ return $linksByGroup;
}
/**
@@ -117,22 +177,25 @@
}
/**
- * @param Title $title
+ * @param ItemId $itemId
*
* @return SiteLink[]
*/
- private function getSiteLinks( Title $title ) {
- $siteLink = new SiteLink( $this->localSiteId,
$title->getFullText() );
- $itemId = $this->siteLinkLookup->getItemIdForSiteLink(
$siteLink );
-
- if ( $itemId === null ) {
- return array();
- }
-
+ private function getSiteLinks( ItemId $itemId ) {
return $this->siteLinkLookup->getSiteLinksForItem( $itemId );
}
/**
+ * @param Title $title
+ *
+ * @return Item|null
+ */
+ private function getItemId( Title $title ) {
+ $siteLink = new SiteLink( $this->localSiteId,
$title->getFullText() );
+ return $this->siteLinkLookup->getItemIdForSiteLink( $siteLink );
+ }
+
+ /**
* @param SiteLink $siteLink
* @param Site $site
*
diff --git
a/client/tests/phpunit/includes/Hooks/OtherProjectsSidebarGeneratorTest.php
b/client/tests/phpunit/includes/Hooks/OtherProjectsSidebarGeneratorTest.php
index b121789..f92a9fb 100644
--- a/client/tests/phpunit/includes/Hooks/OtherProjectsSidebarGeneratorTest.php
+++ b/client/tests/phpunit/includes/Hooks/OtherProjectsSidebarGeneratorTest.php
@@ -85,6 +85,187 @@
}
/**
+ * @dataProvider projectLinkSidebarHookProvider
+ */
+ public function testBuildProjectLinkSidebar_hook(
+ /* callable */ $handler,
+ array $siteIdsToOutput,
+ array $result,
+ $suppressErrors = false
+ ) {
+ $this->setMwGlobals( 'wgHooks', array(
'WikibaseClientOtherProjectsSidebar' => array( $handler ) ) );
+
+ $otherProjectSidebarGenerator = new
OtherProjectsSidebarGenerator(
+ 'enwiki',
+ $this->getSiteLinkLookup(),
+ $this->getSiteStore(),
+ $siteIdsToOutput
+ );
+
+ if ( $suppressErrors ) {
+ \MediaWiki\suppressWarnings();
+ }
+ $this->assertEquals(
+ $result,
+ $otherProjectSidebarGenerator->buildProjectLinkSidebar(
Title::makeTitle( NS_MAIN, 'Nyan Cat' ) )
+ );
+
+ if ( $suppressErrors ) {
+ \MediaWiki\restoreWarnings();
+ }
+ }
+
+ public function projectLinkSidebarHookProvider() {
+ $wiktionaryLink = array(
+ 'msg' => 'wikibase-otherprojects-wiktionary',
+ 'class' => 'wb-otherproject-link
wb-otherproject-wiktionary',
+ 'href' => 'https://en.wiktionary.org/wiki/Nyan_Cat',
+ 'hreflang' => 'en'
+ );
+ $wikiquoteLink = array(
+ 'msg' => 'wikibase-otherprojects-wikiquote',
+ 'class' => 'wb-otherproject-link
wb-otherproject-wikiquote',
+ 'href' => 'https://en.wikiquote.org/wiki/Nyan_Cat',
+ 'hreflang' => 'en'
+ );
+ $wikipediaLink = array(
+ 'msg' => 'wikibase-otherprojects-wikipedia',
+ 'class' => 'wb-otherproject-link
wb-otherproject-wikipedia',
+ 'href' => 'https://en.wikipedia.org/wiki/Nyan_Cat',
+ 'hreflang' => 'en'
+ );
+ $changedWikipedaLink = array(
+ 'msg' => 'wikibase-otherprojects-wikipedia',
+ 'class' => 'wb-otherproject-link
wb-otherproject-wikipedia',
+ 'href' => 'https://en.wikipedia.org/wiki/Cat',
+ 'hreflang' => 'en'
+ );
+ $self = $this; // PHP 5.3 :(
+
+ return array(
+ 'Noop hook, gets the right data' => array(
+ function( ItemId $itemId, array &$sidebar ) use
( $wikipediaLink, $wikiquoteLink, $wiktionaryLink, $self ) {
+ $self->assertSame(
+ array(
+ 'wikiquote' => array(
'enwikiquote' => $wikiquoteLink ),
+ 'wikipedia' => array(
'enwiki' => $wikipediaLink ),
+ 'wiktionary' => array(
'enwiktionary' => $wiktionaryLink )
+ ),
+ $sidebar
+ );
+ $self->assertSame( 'Q123',
$itemId->getSerialization() );
+ },
+ array( 'enwiktionary', 'enwiki', 'enwikiquote'
),
+ array( $wikipediaLink, $wikiquoteLink,
$wiktionaryLink )
+ ),
+ 'Hook changes enwiki link' => array(
+ function( ItemId $itemId, array &$sidebar ) use
( $changedWikipedaLink ) {
+ $sidebar['wikipedia']['enwiki']['href']
= $changedWikipedaLink['href'];
+ },
+ array( 'enwiktionary', 'enwiki', 'enwikiquote'
),
+ array( $changedWikipedaLink, $wikiquoteLink,
$wiktionaryLink )
+ ),
+ 'Hook inserts enwiki link' => array(
+ function( ItemId $itemId, array &$sidebar ) use
( $changedWikipedaLink, $self ) {
+ $self->assertFalse(
+ isset( $sidebar['wikipedia'] ),
+ 'No Wikipedia link present yet'
+ );
+
+ $sidebar['wikipedia']['enwiki'] =
$changedWikipedaLink;
+ },
+ array( 'enwiktionary', 'enwikiquote' ),
+ array( $changedWikipedaLink, $wikiquoteLink,
$wiktionaryLink )
+ ),
+ 'Invalid hook #1, original data is being used' => array(
+ function( ItemId $itemId, array &$sidebar ) {
+ $sidebar = null;
+ },
+ array( 'enwiktionary', 'enwiki', 'enwikiquote'
),
+ array( $wikipediaLink, $wikiquoteLink,
$wiktionaryLink ),
+ true
+ ),
+ 'Invalid hook #2, original data is being used' => array(
+ function( ItemId $itemId, array &$sidebar ) {
+ $sidebar[0]['msg'] = array();
+ },
+ array( 'enwiktionary', 'enwiki', 'enwikiquote'
),
+ array( $wikipediaLink, $wikiquoteLink,
$wiktionaryLink ),
+ true
+ ),
+ 'Invalid hook #3, original data is being used' => array(
+ function( ItemId $itemId, array &$sidebar ) use
( $changedWikipedaLink ) {
+ $sidebar['wikipedia']['enwiki']['href']
= 1.2;
+ },
+ array( 'enwiktionary', 'enwiki', 'enwikiquote'
),
+ array( $wikipediaLink, $wikiquoteLink,
$wiktionaryLink ),
+ true
+ ),
+ 'Invalid hook #4, original data is being used' => array(
+ function( ItemId $itemId, array &$sidebar ) use
( $changedWikipedaLink ) {
+ $sidebar['wikipedia'][] =
$changedWikipedaLink;
+ },
+ array( 'enwiktionary', 'enwiki', 'enwikiquote'
),
+ array( $wikipediaLink, $wikiquoteLink,
$wiktionaryLink ),
+ true
+ ),
+ );
+ }
+
+ public function
testBuildProjectLinkSidebar_hookNotCalledIfPageNotConnected() {
+ $self = $this; // We all love PHP 5.3
+
+ $handler = function() use ( $self ) {
+ $self->assertTrue( false, "Should not get called." );
+ };
+
+ $this->setMwGlobals( 'wgHooks', array(
'WikibaseClientOtherProjectsSidebar' => array( $handler ) ) );
+
+ $lookup = $this->getMock( 'Wikibase\Lib\Store\SiteLinkLookup' );
+ $lookup->expects( $this->any() )
+ ->method( 'getItemIdForSiteLink' )
+ ->will( $this->returnValue( null ) );
+
+ $otherProjectSidebarGenerator = new
OtherProjectsSidebarGenerator(
+ 'enwiki',
+ $lookup,
+ $this->getSiteStore(),
+ array( 'enwiki' )
+ );
+
+ $this->assertSame(
+ array(),
+ $otherProjectSidebarGenerator->buildProjectLinkSidebar(
Title::makeTitle( NS_MAIN, 'Nyan Cat' ) )
+ );
+ }
+
+ public function
testBuildProjectLinkSidebar_hookCalledWithEmptySidebar() {
+ $self = $this; // We all love PHP 5.3
+ $called = false;
+
+ $handler = function( ItemId $itemId, $sidebar ) use ( $self,
&$called ) {
+ $self->assertSame( 'Q123', $itemId->getSerialization()
);
+ $self->assertSame( array(), $sidebar );
+ $called = true;
+ };
+
+ $this->setMwGlobals( 'wgHooks', array(
'WikibaseClientOtherProjectsSidebar' => array( $handler ) ) );
+
+ $otherProjectSidebarGenerator = new
OtherProjectsSidebarGenerator(
+ 'enwiki',
+ $this->getSiteLinkLookup(),
+ $this->getSiteStore(),
+ array( 'unknown-site' )
+ );
+
+ $this->assertSame(
+ array(),
+ $otherProjectSidebarGenerator->buildProjectLinkSidebar(
Title::makeTitle( NS_MAIN, 'Nyan Cat' ) )
+ );
+ $this->assertTrue( $called, 'Hook needs to be called' );
+ }
+
+ /**
* @return SiteStore
*/
private function getSiteStore() {
diff --git a/docs/hooks.txt b/docs/hooks.txt
index 92e76fe..9b51cde 100644
--- a/docs/hooks.txt
+++ b/docs/hooks.txt
@@ -38,10 +38,18 @@
&$dataTypeDefinitions: the array of data type definitions, as defined by
WikibaseClient.datatypes.php.
Hook handlers may add additional definitions. See the datatypes.wiki file
for details.
-'WikibaseHandleChanges': Callend by ChangeHandler::handleChange() to allow
pre-processing
+'WikibaseHandleChanges': Called by ChangeHandler::handleChange() to allow
pre-processing
of changes.
$changes: A list of Change objects
-'WikibaseHandleChange': Callend by ChangeHandler::handleChange() to allow
alternative
+'WikibaseHandleChange': Called by ChangeHandler::handleChange() to allow
alternative
processing of changes.
$change: A Change object
+
+'WikibaseClientOtherProjectsSidebar' Called by OtherProjectsSidebarGenerator
to allow altering
+the other projects sidebar. Only called in case the page we're on is linked
with an item.
+$itemId: Id of the item the page is linked with.
+&$newSidedbar: Array containing the sidebar definition. The array consits of
arrays indexed by
+site groups containing arrays indexed by site id. These arrays represent the
link to the given
+site. They contain the keys "msg", "href" and "class" which contain the
respective attributes
+for the link that is going to be created.
--
To view, visit https://gerrit.wikimedia.org/r/263535
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ica9b1bac5394cddc021c013da4e6b5a74651c4aa
Gerrit-PatchSet: 11
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Hoo man <[email protected]>
Gerrit-Reviewer: Addshore <[email protected]>
Gerrit-Reviewer: Aude <[email protected]>
Gerrit-Reviewer: Daniel Kinzler <[email protected]>
Gerrit-Reviewer: Hoo man <[email protected]>
Gerrit-Reviewer: JanZerebecki <[email protected]>
Gerrit-Reviewer: Thiemo Mättig (WMDE) <[email protected]>
Gerrit-Reviewer: Tpt <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits