| Current File : /home/jvzmxxx/wiki1/extensions/Wikibase/client/includes/LangLinkHandler.php |
<?php
namespace Wikibase;
use ParserOutput;
use Site;
use SiteStore;
use Title;
use Wikibase\Client\Hooks\LanguageLinkBadgeDisplay;
use Wikibase\DataModel\Entity\Item;
use Wikibase\DataModel\Services\Lookup\EntityLookup;
use Wikibase\DataModel\SiteLink;
use Wikibase\Lib\Store\SiteLinkLookup;
/**
* @todo split this up and find a better home for stuff that adds
* parser output properties and extension data.
*
* @since 0.1
*
* @license GPL-2.0+
* @author Nikola Smolenski <smolensk@eunet.rs>
* @author Daniel Kinzler
* @author Katie Filbert < aude.wiki@gmail.com >
*/
class LangLinkHandler {
/**
* @var LanguageLinkBadgeDisplay
*/
private $badgeDisplay;
/**
* @var NamespaceChecker
*/
private $namespaceChecker;
/**
* @var SiteLinkLookup
*/
private $siteLinkLookup;
/**
* @var EntityLookup
*/
private $entityLookup;
/**
* @var SiteStore
*/
private $siteStore;
/**
* @var string
*/
private $siteId;
/**
* @var string
*/
private $siteGroup;
/**
* @param LanguageLinkBadgeDisplay $badgeDisplay
* @param NamespaceChecker $namespaceChecker determines which namespaces wikibase is enabled on
* @param SiteLinkLookup $siteLinkLookup A site link lookup service
* @param EntityLookup $entityLookup An entity lookup service
* @param SiteStore $siteStore
* @param string $siteId The global site ID for the local wiki
* @param string $siteGroup The ID of the site group to use for showing language links.
*/
public function __construct(
LanguageLinkBadgeDisplay $badgeDisplay,
NamespaceChecker $namespaceChecker,
SiteLinkLookup $siteLinkLookup,
EntityLookup $entityLookup,
SiteStore $siteStore,
$siteId,
$siteGroup
) {
$this->badgeDisplay = $badgeDisplay;
$this->namespaceChecker = $namespaceChecker;
$this->siteLinkLookup = $siteLinkLookup;
$this->entityLookup = $entityLookup;
$this->siteStore = $siteStore;
$this->siteId = $siteId;
$this->siteGroup = $siteGroup;
}
/**
* Finds the corresponding item on the repository and returns the item's site links.
*
* @since 0.1
*
* @param Title $title
*
* @return SiteLink[] A map of SiteLinks, indexed by global site id.
*/
public function getEntityLinks( Title $title ) {
$links = array();
$itemId = $this->siteLinkLookup->getItemIdForLink(
$this->siteId,
$title->getPrefixedText()
);
if ( $itemId !== null ) {
//NOTE: SiteLinks we could get from $this->siteLinkLookup do not contain badges,
// so we have to fetch the links from the Item.
/* @var Item $item */
$item = $this->entityLookup->getEntity( $itemId );
if ( $item ) {
$links = iterator_to_array( $item->getSiteLinkList() );
$links = $this->indexLinksBySiteId( $links );
} else {
wfLogWarning( __METHOD__ . ": Could not load item " . $itemId->getSerialization()
. " for " . $title->getPrefixedText() );
}
}
return $links;
}
/**
* @param SiteLink[] $links
*
* @return SiteLink[] The SiteLinks in $links, indexed by site ID
*/
private function indexLinksBySiteId( array $links ) {
$indexed = array();
foreach ( $links as $link ) {
$key = $link->getSiteId();
$indexed[$key] = $link;
}
return $indexed;
}
/**
* @param SiteLink[] $links
*
* @return SiteLink[] The SiteLinks in $links, indexed by interwiki prefix.
*/
private function indexLinksByInterwiki( array $links ) {
$indexed = array();
foreach ( $links as $link ) {
$siteId = $link->getSiteId();
$site = $this->siteStore->getSite( $siteId );
if ( !$site ) {
continue;
}
$navIds = $site->getNavigationIds();
$key = reset( $navIds );
if ( $key !== false ) {
$indexed[$key] = $link;
}
}
return $indexed;
}
/**
* Checks if a page have interwiki links from Wikidata repo?
* Disabled for a page when either:
* - Wikidata not enabled for namespace
* - nel parser function = * (suppress all repo links)
*
* @since 0.1
*
* @param Title $title
* @param ParserOutput $out
*
* @return bool
*/
public function useRepoLinks( Title $title, ParserOutput $out ) {
// use repoLinks in only the namespaces specified in settings
if ( $this->namespaceChecker->isWikibaseEnabled( $title->getNamespace() ) === true ) {
$nel = $this->getNoExternalLangLinks( $out );
if ( in_array( '*', $nel ) ) {
return false;
}
return true;
}
return false;
}
/**
* Returns a filtered version of $repoLinks, containing only links that should be considered
* for combining with the local inter-language links. This takes into account the
* {{#noexternallanglinks}} parser function, and also removed any link to
* this wiki itself.
*
* This function does not remove links to wikis for which there is already an
* inter-language link defined in the local wikitext. This is done later
* by getEffectiveRepoLinks().
*
* @since 0.1
*
* @param ParserOutput $out
* @param array $repoLinks An array that uses global site IDs as keys.
*
* @return SiteLink[] A filtered copy of $repoLinks, with any inappropriate
* entries removed.
*/
public function suppressRepoLinks( ParserOutput $out, array $repoLinks ) {
$nel = $this->getNoExternalLangLinks( $out );
foreach ( $nel as $code ) {
if ( $code === '*' ) {
// all are suppressed
return array();
}
$sites = $this->siteStore->getSites();
if ( $sites->hasNavigationId( $code ) ) {
$site = $sites->getSiteByNavigationId( $code );
$wiki = $site->getGlobalId();
unset( $repoLinks[$wiki] );
}
}
unset( $repoLinks[$this->siteId] ); // remove self-link
return $repoLinks;
}
/**
* Filters the given list of links by site group:
* Any links pointing to a site that is not in $allowedGroups will be removed.
*
* @since 0.4
*
* @param array $repoLinks An array that uses global site IDs as keys.
* @param string[] $allowedGroups A list of allowed site groups
*
* @return array A filtered copy of $repoLinks, retaining only the links
* pointing to a site in an allowed group.
*/
public function filterRepoLinksByGroup( array $repoLinks, array $allowedGroups ) {
foreach ( $repoLinks as $wiki => $link ) {
if ( !$this->siteStore->getSite( $wiki ) ) {
unset( $repoLinks[$wiki] );
continue;
}
$site = $this->siteStore->getSite( $wiki );
if ( !in_array( $site->getGroup(), $allowedGroups ) ) {
unset( $repoLinks[$wiki] );
continue;
}
}
return $repoLinks;
}
/**
* Get the noexternallanglinks page property from the ParserOutput,
* which is set by the {{#noexternallanglinks}} parser function.
*
* @see NoLangLinkHandler::getNoExternalLangLinks
*
* @param ParserOutput $out
*
* @return string[] A list of language codes, identifying which repository links to ignore.
* Empty if {{#noexternallanglinks}} was not used on the page.
*/
public function getNoExternalLangLinks( ParserOutput $out ) {
return NoLangLinkHandler::getNoExternalLangLinks( $out );
}
/**
* Converts a list of interwiki links into an associative array that maps
* global site IDs to the respective target pages on the designated wikis.
*
* @param string[] $flatLinks
*
* @return string[] An associative array, using site IDs for keys
* and the target pages on the respective wiki as the associated value.
*/
private function localLinksToArray( array $flatLinks ) {
$links = array();
foreach ( $flatLinks as $s ) {
$parts = explode( ':', $s, 2 );
if ( count( $parts ) === 2 ) {
$lang = $parts[0];
$page = $parts[1];
$sites = $this->siteStore->getSites();
if ( $sites->hasNavigationId( $lang ) ) {
$site = $sites->getSiteByNavigationId( $lang );
$wiki = $site->getGlobalId();
$links[$wiki] = $page;
} else {
wfWarn( "Failed to map interlanguage prefix $lang to a global site ID." );
}
}
}
return $links;
}
/**
* Look up sitelinks for the given title on the repository and filter them
* taking into account any applicable configuration and any use of the
* {{#noexternallanglinks}} function on the page.
*
* The result is an associative array of links that should be added to the
* current page, excluding any target sites for which there already is a
* link on the page.
*
* @since 0.4
*
* @param Title $title The page's title
* @param ParserOutput $out Parsed representation of the page
*
* @return SiteLink[] An associative array, using site IDs for keys
* and the target pages in the respective languages as the associated value.
*/
public function getEffectiveRepoLinks( Title $title, ParserOutput $out ) {
if ( !$this->useRepoLinks( $title, $out ) ) {
return array();
}
$allowedGroups = array( $this->siteGroup );
$onPageLinks = $out->getLanguageLinks();
$onPageLinks = $this->localLinksToArray( $onPageLinks );
$repoLinks = $this->getEntityLinks( $title );
$repoLinks = $this->filterRepoLinksByGroup( $repoLinks, $allowedGroups );
$repoLinks = $this->suppressRepoLinks( $out, $repoLinks );
$repoLinks = array_diff_key( $repoLinks, $onPageLinks ); // remove local links
return $repoLinks;
}
/**
* Look up sitelinks for the given title on the repository and add them
* to the ParserOutput object, taking into account any applicable
* configuration and any use of the {{#noexternallanglinks}} function on the page.
*
* The language links are not sorted, call sortLanguageLinks() to do that.
*
* @since 0.4
*
* @param Title $title The page's title
* @param ParserOutput $out Parsed representation of the page
*/
public function addLinksFromRepository( Title $title, ParserOutput $out ) {
$repoLinks = $this->getEffectiveRepoLinks( $title, $out );
$this->addLinksToOutput( $repoLinks, $out );
$repoLinksByInterwiki = $this->indexLinksByInterwiki( $repoLinks );
$this->badgeDisplay->attachBadgesToOutput( $repoLinksByInterwiki, $out );
}
/**
* Adds the given SiteLinks to the given ParserOutput.
*
* @param SiteLink[] $links
* @param ParserOutput $out
*/
private function addLinksToOutput( array $links, ParserOutput $out ) {
foreach ( $links as $siteId => $siteLink ) {
$page = $siteLink->getPageName();
$targetSite = $this->siteStore->getSite( $siteId );
if ( !$targetSite ) {
wfLogWarning( "Unknown wiki '$siteId' used as sitelink target" );
continue;
}
$interwikiCode = $this->getInterwikiCodeFromSite( $targetSite );
if ( $interwikiCode ) {
$link = "$interwikiCode:$page";
$out->addLanguageLink( $link );
} else {
wfWarn( "No interlanguage prefix found for $siteId." );
}
}
}
/**
* Extracts the local interwiki code, which in case of the
* wikimedia site groups, is always set to the language code.
*
* @fixme put somewhere more sane and use site identifiers data,
* so that this works in non-wikimedia cases where the assumption
* is not true.
*
* @param Site $site
*
* @return string
*/
public function getInterwikiCodeFromSite( Site $site ) {
return $site->getLanguageCode();
}
}