Current File : /home/jvzmxxx/wiki1/extensions/Wikibase/repo/includes/LinkedData/EntityDataFormatProvider.php
<?php

namespace Wikibase\Repo\LinkedData;

use ApiMain;
use DerivativeContext;
use DerivativeRequest;
use RequestContext;
use Wikimedia\Purtle\RdfWriterFactory;

/**
 * Service for getting information about supported data formats.
 *
 * @since 0.5
 *
 * @license GPL-2.0+
 * @author Daniel Kinzler
 * @author Thomas Pellissier Tanon
 * @author Anja Jentzsch < anja.jentzsch@wikimedia.de >
 * @author Marius Hoch < hoo@online.de >
 */
class EntityDataFormatProvider {

	/**
	 * White list of supported formats.
	 *
	 * @var string[]|null
	 */
	private $formatWhiteList = null;

	/**
	 * @var null|array Associative array from MIME type to format name
	 * @note: initialized by initFormats()
	 */
	private $mimeTypes = null;

	/**
	 * @var null|array Associative array from file extension to format name
	 * @note: initialized by initFormats()
	 */
	private $fileExtensions = null;

	/**
	 * @var RdfWriterFactory
	 */
	private $rdfWriterFactory;

	public function __construct() {
		$this->rdfWriterFactory = new RdfWriterFactory();
	}

	/**
	 * @param string[]|null $formatWhiteList
	 */
	public function setFormatWhiteList( array $formatWhiteList = null ) {
		$this->formatWhiteList = $formatWhiteList;

		// force re-init of format maps
		$this->fileExtensions = null;
		$this->mimeTypes = null;
	}

	/**
	 * @return string[]|null
	 */
	public function getFormatWhiteList() {
		return $this->formatWhiteList;
	}

	/**
	 * Returns the list of supported MIME types that can be used to specify the
	 * output format.
	 *
	 * @return string[]
	 */
	public function getSupportedMimeTypes() {
		$this->initFormats();

		return array_keys( $this->mimeTypes );
	}

	/**
	 * Returns the list of supported file extensions that can be used
	 * to specify a format.
	 *
	 * @return string[]
	 */
	public function getSupportedExtensions() {
		$this->initFormats();

		return array_keys( $this->fileExtensions );
	}

	/**
	 * Returns the list of supported formats using their canonical names.
	 *
	 * @return string[]
	 */
	public function getSupportedFormats() {
		$this->initFormats();

		return array_unique( array_merge(
			array_values( $this->mimeTypes ),
			array_values( $this->fileExtensions )
		) );
	}

	/**
	 * Returns a canonical format name. Used to normalize the format identifier.
	 *
	 * @param string $format the format as a file extension or MIME type.
	 *
	 * @return string|null the canonical format name, or null of the format is not supported
	 */
	public function getFormatName( $format ) {
		$this->initFormats();

		$format = trim( strtolower( $format ) );

		if ( array_key_exists( $format, $this->mimeTypes ) ) {
			return $this->mimeTypes[$format];
		}

		if ( array_key_exists( $format, $this->fileExtensions ) ) {
			return $this->fileExtensions[$format];
		}

		if ( in_array( $format, $this->mimeTypes ) ) {
			return $format;
		}

		if ( in_array( $format, $this->fileExtensions ) ) {
			return $format;
		}

		return null;
	}

	/**
	 * Returns a file extension suitable for $format, or null if no such extension is known.
	 *
	 * @param string $format A canonical format name, as returned by getFormatName() or getSupportedFormats().
	 *
	 * @return string|null
	 */
	public function getExtension( $format ) {
		$this->initFormats();

		$ext = array_search( $format, $this->fileExtensions );
		return $ext === false ? null : $ext;
	}

	/**
	 * Returns a MIME type suitable for $format, or null if no such extension is known.
	 *
	 * @param string $format A canonical format name, as returned by getFormatName() or getSupportedFormats().
	 *
	 * @return string|null
	 */
	public function getMimeType( $format ) {
		$this->initFormats();

		$type = array_search( $format, $this->mimeTypes );

		return $type === false ? null : $type;
	}

	/**
	 * Initializes the internal mapping of MIME types and file extensions to format names.
	 */
	private function initFormats() {
		if ( $this->mimeTypes !== null && $this->fileExtensions !== null ) {
			return;
		}

		$this->mimeTypes = array();
		$this->fileExtensions = array();

		$api = $this->newApiMain( "dummy" );
		$formatNames = $api->getModuleManager()->getNames( 'format' );

		foreach ( $formatNames as $name ) {
			if ( $this->formatWhiteList !== null && !in_array( $name, $this->formatWhiteList ) ) {
				continue;
			}

			$mimes = self::getApiMimeTypes( $name );
			$ext = self::getApiFormatName( $name );

			foreach ( $mimes as $mime ) {
				if ( !isset( $this->mimeTypes[$mime] ) ) {
					$this->mimeTypes[$mime] = $name;
				}
			}

			$this->fileExtensions[ $ext ] = $name;
		}

		$formats = $this->rdfWriterFactory->getSupportedFormats();

		foreach ( $formats as $name ) {
			// check whitelist, and don't override API formats
			if ( ( $this->formatWhiteList !== null
					&& !in_array( $name, $this->formatWhiteList ) )
				|| in_array( $name, $this->mimeTypes )
				|| in_array( $name, $this->fileExtensions )
			) {
				continue;
			}

			// use all mime types. to improve content negotiation
			foreach ( $this->rdfWriterFactory->getMimeTypes( $name ) as $mime ) {
				if ( !isset( $this->mimeTypes[$mime] ) ) {
					$this->mimeTypes[$mime] = $name;
				}
			}

			// only one file extension, to keep purging simple
			$ext = $this->rdfWriterFactory->getFileExtension( $name );
			if ( !isset( $this->fileExtensions[$ext] ) ) {
				$this->fileExtensions[$ext] = $name;
			}
		}
	}

	/**
	 * Normalizes the format specifier; Converts mime types to API format names.
	 *
	 * @param String $format the format as supplied in the request
	 *
	 * @return String|null the normalized format name, or null if the format is unknown
	 */
	private static function getApiFormatName( $format ) {
		$format = trim( strtolower( $format ) );

		if ( $format === 'application/vnd.php.serialized' ) {
			$format = 'php';
		} elseif ( $format === 'text/text' || $format === 'text/plain' ) {
			$format = 'txt';
		} else {
			// hack: just trip the major part of the mime type
			$format = preg_replace( '@^(text|application)?/@', '', $format );
		}

		return $format;
	}

	/**
	 * Converts API format names to MIME types.
	 *
	 * @param String $format the API format name
	 *
	 * @return String[]|null the MIME types for the given format
	 */
	private static function getApiMimeTypes( $format ) {
		$format = trim( strtolower( $format ) );
		$type = null;

		switch ( $format ) {
			case 'php':
				return array( 'application/vnd.php.serialized' );

			case 'txt':
				return array( "text/text", "text/plain" );

			case 'javascript':
				return array( "text/javascript" );

			default:
				return array( "application/$format" );
		}
	}

	/**
	 * Returns an ApiMain module that acts as a context for the formatting and serialization.
	 *
	 * @param String $format The desired output format, as a format name that ApiBase understands.
	 *
	 * @return ApiMain
	 */
	private function newApiMain( $format ) {
		// Fake request params to ApiMain, with forced format parameters.
		// We can override additional parameters here, as needed.
		$params = array(
			'format' => $format,
		);

		$context = new DerivativeContext( RequestContext::getMain() ); //XXX: ugly

		$req = new DerivativeRequest( $context->getRequest(), $params );
		$context->setRequest( $req );

		$api = new ApiMain( $context );
		return $api;
	}

}