Current File : /home/jvzmxxx/wiki/extensions/Wikibase/repo/includes/Api/GetEntities.php
<?php

namespace Wikibase\Repo\Api;

use ApiBase;
use ApiMain;
use Wikibase\DataModel\Entity\EntityId;
use Wikibase\DataModel\Services\Entity\EntityPrefetcher;
use Wikibase\DataModel\Entity\EntityIdParser;
use Wikibase\DataModel\Entity\EntityIdParsingException;
use Wikibase\EntityRevision;
use Wikibase\LanguageFallbackChainFactory;
use Wikibase\Lib\Store\EntityRevisionLookup;
use Wikibase\Lib\Store\RevisionedUnresolvedRedirectException;
use Wikibase\Repo\SiteLinkTargetProvider;
use Wikibase\Repo\WikibaseRepo;
use Wikibase\StringNormalizer;

/**
 * API module to get the data for one or more Wikibase entities.
 *
 * @since 0.1
 *
 * @license GPL-2.0+
 * @author John Erling Blad < jeblad@gmail.com >
 * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 * @author Marius Hoch < hoo@online.de >
 * @author Michał Łazowik
 * @author Addshore
 */
class GetEntities extends ApiBase {

	/**
	 * @var StringNormalizer
	 */
	private $stringNormalizer;

	/**
	 * @var LanguageFallbackChainFactory
	 */
	private $languageFallbackChainFactory;

	/**
	 * @var SiteLinkTargetProvider
	 */
	private $siteLinkTargetProvider;

	/**
	 * @var EntityPrefetcher
	 */
	private $entityPrefetcher;

	/**
	 * @var string[]
	 */
	private $siteLinkGroups;

	/**
	 * @var ApiErrorReporter
	 */
	private $errorReporter;

	/**
	 * @var ResultBuilder
	 */
	private $resultBuilder;

	/**
	 * @var EntityRevisionLookup
	 */
	private $entityRevisionLookup;

	/**
	 * @var EntityIdParser
	 */
	private $idParser;

	/**
	 * @param ApiMain $mainModule
	 * @param string $moduleName
	 * @param string $modulePrefix
	 *
	 * @see ApiBase::__construct
	 */
	public function __construct( ApiMain $mainModule, $moduleName, $modulePrefix = '' ) {
		parent::__construct( $mainModule, $moduleName, $modulePrefix );

		$wikibaseRepo = WikibaseRepo::getDefaultInstance();
		$settings = $wikibaseRepo->getSettings();
		$apiHelperFactory = $wikibaseRepo->getApiHelperFactory( $this->getContext() );

		$this->errorReporter = $apiHelperFactory->getErrorReporter( $this );
		$this->resultBuilder = $apiHelperFactory->getResultBuilder( $this );
		$this->stringNormalizer = $wikibaseRepo->getStringNormalizer();
		$this->languageFallbackChainFactory = $wikibaseRepo->getLanguageFallbackChainFactory();
		$this->entityRevisionLookup = $wikibaseRepo->getEntityRevisionLookup();
		$this->idParser = $wikibaseRepo->getEntityIdParser();

		$this->siteLinkTargetProvider = new SiteLinkTargetProvider(
			$wikibaseRepo->getSiteStore(),
			$settings->getSetting( 'specialSiteLinkGroups' )
		);

		$this->siteLinkGroups = $settings->getSetting( 'siteLinkGroups' );
		$this->entityPrefetcher = $wikibaseRepo->getStore()->getEntityPrefetcher();
	}

	/**
	 * @see ApiBase::execute()
	 */
	public function execute() {
		$params = $this->extractRequestParams();

		if ( !isset( $params['ids'] ) && ( empty( $params['sites'] ) || empty( $params['titles'] ) ) ) {
			$this->errorReporter->dieError(
				'Either provide the item "ids" or pairs of "sites" and "titles" for corresponding pages',
				'param-missing'
			);
		}

		$resolveRedirects = $params['redirects'] === 'yes';

		$entityIds = $this->getEntityIdsFromParams( $params );

		$this->getStats()->updateCount( 'wikibase.repo.api.getentities.entities', count( $entityIds ) );

		$entityRevisions = $this->getEntityRevisionsFromEntityIds( $entityIds, $resolveRedirects );

		foreach ( $entityRevisions as $sourceEntityId => $entityRevision ) {
			$this->handleEntity( $sourceEntityId, $entityRevision, $params );
		}

		$this->resultBuilder->markSuccess( 1 );
	}

	/**
	 * Get a unique array of EntityIds from api request params
	 *
	 * @param array $params
	 *
	 * @return EntityId[]
	 */
	private function getEntityIdsFromParams( array $params ) {
		$fromIds = $this->getEntityIdsFromIdParam( $params );
		$fromSiteTitleCombinations = $this->getItemIdsFromSiteTitleParams( $params );
		$ids = array_merge( $fromIds, $fromSiteTitleCombinations );
		return array_unique( $ids );
	}

	/**
	 * @param array $params
	 *
	 * @return EntityId[]
	 */
	private function getEntityIdsFromIdParam( array $params ) {
		$ids = array();
		if ( isset( $params['ids'] ) ) {
			foreach ( $params['ids'] as $id ) {
				try {
					$ids[] = $this->idParser->parse( $id );
				} catch ( EntityIdParsingException $e ) {
					$this->errorReporter->dieError(
						"Invalid id: $id", 'no-such-entity', 0, array( 'id' => $id ) );
				}
			}
		}
		return $ids;
	}

	/**
	 * @param array $params
	 * @return EntityId[]
	 */
	private function getItemIdsFromSiteTitleParams( array $params ) {
		$ids = array();
		if ( !empty( $params['sites'] ) && !empty( $params['titles'] ) ) {
			$itemByTitleHelper = $this->getItemByTitleHelper();
			list( $ids, $missingItems ) = $itemByTitleHelper->getItemIds( $params['sites'], $params['titles'], $params['normalize'] );
			$this->addMissingItemsToResult( $missingItems );
		}
		return $ids;
	}

	/**
	 * @return ItemByTitleHelper
	 */
	private function getItemByTitleHelper() {
		$wikibaseRepo = WikibaseRepo::getDefaultInstance();
		$siteLinkStore = $wikibaseRepo->getStore()->newSiteLinkStore();
		return new ItemByTitleHelper(
			$this->resultBuilder,
			$siteLinkStore,
			$wikibaseRepo->getSiteStore(),
			$this->stringNormalizer
		);
	}

	/**
	 * @param array[] $missingItems Array of arrays, Each internal array has a key 'site' and 'title'
	 */
	private function addMissingItemsToResult( array $missingItems ) {
		foreach ( $missingItems as $missingItem ) {
			$this->resultBuilder->addMissingEntity( null, $missingItem );
		}
	}

	/**
	 * Returns props based on request parameters
	 *
	 * @param array $params
	 *
	 * @return array
	 */
	private function getPropsFromParams( array $params ) {
		if ( in_array( 'sitelinks/urls', $params['props'] ) ) {
			$params['props'][] = 'sitelinks';
		}

		return $params['props'];
	}

	/**
	 * @param EntityId[] $entityIds
	 * @param bool $resolveRedirects
	 *
	 * @return EntityRevision[]
	 */
	private function getEntityRevisionsFromEntityIds( array $entityIds, $resolveRedirects = false ) {
		$revisionArray = array();

		$this->entityPrefetcher->prefetch( $entityIds );

		foreach ( $entityIds as $entityId ) {
			$sourceEntityId = $entityId->getSerialization();
			$entityRevision = $this->getEntityRevision( $entityId, $resolveRedirects );

			$revisionArray[$sourceEntityId] = $entityRevision;
		}

		return $revisionArray;
	}

	/**
	 * @param EntityId $entityId
	 * @param bool $resolveRedirects
	 *
	 * @return null|EntityRevision
	 */
	private function getEntityRevision( EntityId $entityId, $resolveRedirects = false ) {
		$entityRevision = null;

		try {
			$entityRevision = $this->entityRevisionLookup->getEntityRevision( $entityId );
		} catch ( RevisionedUnresolvedRedirectException $ex ) {
			if ( $resolveRedirects ) {
				$entityId = $ex->getRedirectTargetId();
				$entityRevision = $this->getEntityRevision( $entityId, false );
			}
		}

		return $entityRevision;
	}

	/**
	 * Adds the given EntityRevision to the API result.
	 *
	 * @param string|null $sourceEntityId
	 * @param EntityRevision|null $entityRevision
	 * @param array $params
	 */
	private function handleEntity(
		$sourceEntityId,
		EntityRevision $entityRevision = null,
		array $params = array()
	) {
		if ( $entityRevision === null ) {
			$this->resultBuilder->addMissingEntity( $sourceEntityId, array( 'id' => $sourceEntityId ) );
		} else {
			list( $languageCodeFilter, $fallbackChains ) = $this->getLanguageCodesAndFallback( $params );
			$this->resultBuilder->addEntityRevision(
				$sourceEntityId,
				$entityRevision,
				$this->getPropsFromParams( $params ),
				$params['sitefilter'],
				$languageCodeFilter,
				$fallbackChains
			);
		}
	}

	/**
	 * @param array $params
	 *
	 * @return array
	 *     0 => string[] languageCodes that the user wants returned
	 *     1 => LanguageFallbackChain[] Keys are requested lang codes
	 */
	private function getLanguageCodesAndFallback( array $params ) {
		$languageCodes = ( is_array( $params['languages'] ) ? $params['languages'] : array() );
		$fallbackChains = array();

		if ( $params['languagefallback'] ) {
			$fallbackMode = LanguageFallbackChainFactory::FALLBACK_ALL;
			foreach ( $languageCodes as $languageCode ) {
				$fallbackChains[$languageCode] = $this->languageFallbackChainFactory
					->newFromLanguageCode( $languageCode, $fallbackMode );
			}
		}

		return array( array_unique( $languageCodes ), $fallbackChains );
	}

	/**
	 * @see ApiBase::getAllowedParams
	 */
	protected function getAllowedParams() {
		$sites = $this->siteLinkTargetProvider->getSiteList( $this->siteLinkGroups );

		return array_merge( parent::getAllowedParams(), array(
			'ids' => array(
				self::PARAM_TYPE => 'string',
				self::PARAM_ISMULTI => true,
			),
			'sites' => array(
				self::PARAM_TYPE => $sites->getGlobalIdentifiers(),
				self::PARAM_ISMULTI => true,
				self::PARAM_ALLOW_DUPLICATES => true
			),
			'titles' => array(
				self::PARAM_TYPE => 'string',
				self::PARAM_ISMULTI => true,
				self::PARAM_ALLOW_DUPLICATES => true
			),
			'redirects' => array(
				self::PARAM_TYPE => array( 'yes', 'no' ),
				self::PARAM_DFLT => 'yes',
			),
			'props' => array(
				self::PARAM_TYPE => array( 'info', 'sitelinks', 'sitelinks/urls', 'aliases', 'labels',
					'descriptions', 'claims', 'datatype' ),
				self::PARAM_DFLT => 'info|sitelinks|aliases|labels|descriptions|claims|datatype',
				self::PARAM_ISMULTI => true,
			),
			'languages' => array(
				self::PARAM_TYPE => WikibaseRepo::getDefaultInstance()->getTermsLanguages()->getLanguages(),
				self::PARAM_ISMULTI => true,
			),
			'languagefallback' => array(
				self::PARAM_TYPE => 'boolean',
				self::PARAM_DFLT => false
			),
			'normalize' => array(
				self::PARAM_TYPE => 'boolean',
				self::PARAM_DFLT => false
			),
			'sitefilter' => array(
				self::PARAM_TYPE => $sites->getGlobalIdentifiers(),
				self::PARAM_ISMULTI => true,
				self::PARAM_ALLOW_DUPLICATES => true
			),
		) );
	}

	/**
	 * @see ApiBase::getExamplesMessages
	 */
	protected function getExamplesMessages() {
		return array(
			"action=wbgetentities&ids=Q42"
			=> "apihelp-wbgetentities-example-1",
			"action=wbgetentities&ids=P17"
			=> "apihelp-wbgetentities-example-2",
			"action=wbgetentities&ids=Q42|P17"
			=> "apihelp-wbgetentities-example-3",
			"action=wbgetentities&ids=Q42&languages=en"
			=> "apihelp-wbgetentities-example-4",
			"action=wbgetentities&ids=Q42&languages=ii&languagefallback="
			=> "apihelp-wbgetentities-example-5",
			"action=wbgetentities&ids=Q42&props=labels"
			=> "apihelp-wbgetentities-example-6",
			"action=wbgetentities&ids=P17|P3&props=datatype"
			=> "apihelp-wbgetentities-example-7",
			"action=wbgetentities&ids=Q42&props=aliases&languages=en"
			=> "apihelp-wbgetentities-example-8",
			"action=wbgetentities&ids=Q1|Q42&props=descriptions&languages=en|de|fr"
			=> "apihelp-wbgetentities-example-9",
			'action=wbgetentities&sites=enwiki&titles=Berlin&languages=en'
			=> 'apihelp-wbgetentities-example-10',
			'action=wbgetentities&sites=enwiki&titles=berlin&normalize='
			=> 'apihelp-wbgetentities-example-11',
			'action=wbgetentities&ids=Q42&props=sitelinks'
			=> 'apihelp-wbgetentities-example-12',
			'action=wbgetentities&ids=Q42&sitefilter=enwiki'
			=> 'apihelp-wbgetentities-example-13'
		);
	}

}