mediawiki-extensions-PageIm.../includes/ApiQueryPageImages.php
Amir Sarabadani 8fe805f25e Make sure pithumbsize set width and not height
This unifies image thumbnail sizes so instead of being random image
sizes, it would be only one thumbsize.

Bug: T323223
Change-Id: Ib7a7a5bce3ce10e60819e6ca056fe30f11e969a5
2022-11-21 19:52:44 +01:00

278 lines
8.4 KiB
PHP

<?php
namespace PageImages;
use ApiBase;
use ApiQuery;
use ApiQueryBase;
use MediaWiki\MediaWikiServices;
use Title;
use Wikimedia\ParamValidator\ParamValidator;
use Wikimedia\ParamValidator\TypeDef\IntegerDef;
/**
* Expose image information for a page via a new prop=pageimages API.
*
* @see https://www.mediawiki.org/wiki/Extension:PageImages#API
*
* @license WTFPL
* @author Max Semenik
* @author Ryan Kaldari
* @author Yuvi Panda
* @author Sam Smith
*/
class ApiQueryPageImages extends ApiQueryBase {
/**
* @param ApiQuery $query API query module
* @param string $moduleName Name of this query module
*/
public function __construct( ApiQuery $query, $moduleName ) {
parent::__construct( $query, $moduleName, 'pi' );
}
/**
* Gets the set of titles to get page images for.
*
* Note well that the set of titles comprises the set of "good" titles
* (see {@see ApiPageSet::getGoodTitles}) union the set of "missing"
* titles in the File namespace that might correspond to foreign files.
* The latter are included because titles in the File namespace are
* expected to be found with {@see \RepoGroup::findFile}.
*
* @return Title[] A map of page ID, which will be negative in the case
* of missing titles in the File namespace, to Title object
*/
protected function getTitles() {
$pageSet = $this->getPageSet();
$titles = $pageSet->getGoodTitles();
// T98791: We want foreign files to be treated like local files
// in #execute, so include the set of missing filespace pages,
// which were initially rejected in ApiPageSet#execute.
$missingTitles = $pageSet->getMissingTitlesByNamespace();
$missingFileTitles = $missingTitles[NS_FILE] ?? [];
// $titles is a map of ID to title object, which is ideal,
// whereas $missingFileTitles is a map of title text to ID.
// Do not use array_merge here as it doesn't preserve keys.
foreach ( $missingFileTitles as $dbkey => $id ) {
$titles[$id] = Title::makeTitle( NS_FILE, $dbkey );
}
return $titles;
}
/**
* Evaluates the parameters, performs the requested retrieval of page images,
* and sets up the result
*/
public function execute() {
$params = $this->extractRequestParams();
$prop = array_flip( $params['prop'] );
if ( !count( $prop ) ) {
$this->dieWithError(
[ 'apierror-paramempty', $this->encodeParamName( 'prop' ) ], 'noprop'
);
}
$allTitles = $this->getTitles();
if ( count( $allTitles ) === 0 ) {
return;
}
// Find the offset based on the continue param
$offset = 0;
if ( isset( $params['continue'] ) ) {
// Get the position (not the key) of the 'continue' page within the
// array of titles. Set this as the offset.
$pageIds = array_keys( $allTitles );
$offset = array_search( intval( $params['continue'] ), $pageIds );
// If the 'continue' page wasn't found, die with error
$this->dieContinueUsageIf( !$offset );
}
$limit = $params['limit'];
// Slice the part of the array we want to find images for
$titles = array_slice( $allTitles, $offset, $limit, true );
// Get the next item in the title array and use it to set the continue value
$nextItemArray = array_slice( $allTitles, $offset + $limit, 1, true );
if ( $nextItemArray ) {
$this->setContinueEnumParameter( 'continue', key( $nextItemArray ) );
}
// Find any titles in the file namespace so we can handle those separately
$filePageTitles = [];
foreach ( $titles as $id => $title ) {
if ( $title->inNamespace( NS_FILE ) ) {
$filePageTitles[$id] = $title;
unset( $titles[$id] );
}
}
$size = $params['thumbsize'];
$lang = $params['langcode'];
// Extract page images from the page_props table
if ( count( $titles ) > 0 ) {
$this->addTables( 'page_props' );
$this->addFields( [ 'pp_page', 'pp_propname', 'pp_value' ] );
$this->addWhere( [ 'pp_page' => array_keys( $titles ),
'pp_propname' => PageImages::getPropNames( $params['license'] ) ] );
$res = $this->select( __METHOD__ );
$buffer = [];
$propNameAny = PageImages::getPropName( false );
foreach ( $res as $row ) {
$pageId = $row->pp_page;
if ( !array_key_exists( $pageId, $buffer ) || $row->pp_propname === $propNameAny ) {
$buffer[$pageId] = $row;
}
}
foreach ( $buffer as $pageId => $row ) {
$fileName = $row->pp_value;
$this->setResultValues( $prop, $pageId, $fileName, $size, $lang );
}
// End page props image extraction
}
// Extract images from file namespace pages. In this case we just use
// the file itself rather than searching for a page_image. (Bug 50252)
foreach ( $filePageTitles as $pageId => $title ) {
$fileName = $title->getDBkey();
$this->setResultValues( $prop, $pageId, $fileName, $size, $lang );
}
}
/**
* Get the cache mode for the data generated by this module
*
* @param array $params Ignored parameters
* @return string Always returns "public"
*/
public function getCacheMode( $params ) {
return 'public';
}
/**
* For a given page, set API return values for thumbnail and pageimage as needed
*
* @param array $prop The prop values from the API request
* @param int $pageId The ID of the page
* @param string $fileName The name of the file to transform
* @param int $size The thumbsize value from the API request
* @param string $lang The language code from the API request
*/
protected function setResultValues( array $prop, $pageId, $fileName, $size, $lang ) {
$vals = [];
if ( isset( $prop['thumbnail'] ) || isset( $prop['original'] ) ) {
$file = MediaWikiServices::getInstance()->getRepoGroup()->findFile( $fileName );
if ( $file ) {
if ( isset( $prop['thumbnail'] ) ) {
$thumb = $file->transform( [
'width' => $size,
'lang' => $lang
] );
if ( $thumb && $thumb->getUrl() ) {
// You can request a thumb 1000x larger than the original
// which (in case of bitmap original) will return a Thumb object
// that will lie about its size but have the original as an image.
$reportedSize = $thumb->fileIsSource() ? $file : $thumb;
$vals['thumbnail'] = [
'source' => wfExpandUrl( $thumb->getUrl(), PROTO_CURRENT ),
'width' => $reportedSize->getWidth(),
'height' => $reportedSize->getHeight(),
];
}
}
if ( isset( $prop['original'] ) ) {
$originalSize = [
'width' => $file->getWidth(),
'height' => $file->getHeight()
];
if ( $lang ) {
$file = $file->transform( [
'lang' => $lang,
'width' => $originalSize['width'],
'height' => $originalSize['height']
] );
}
$original_url = wfExpandUrl( $file->getUrl(), PROTO_CURRENT );
$vals['original'] = [
'source' => $original_url,
'width' => $originalSize['width'],
'height' => $originalSize['height']
];
}
}
}
if ( isset( $prop['name'] ) ) {
$vals['pageimage'] = $fileName;
}
$this->getResult()->addValue( [ 'query', 'pages' ], $pageId, $vals );
}
/**
* Return an array describing all possible parameters to this module
* @return array
*/
public function getAllowedParams() {
return [
'prop' => [
ParamValidator::PARAM_TYPE => [ 'thumbnail', 'name', 'original' ],
ParamValidator::PARAM_ISMULTI => true,
ParamValidator::PARAM_DEFAULT => 'thumbnail|name',
],
'thumbsize' => [
ParamValidator::PARAM_TYPE => 'integer',
ParamValidator::PARAM_DEFAULT => 50,
],
'limit' => [
ParamValidator::PARAM_DEFAULT => 50,
ParamValidator::PARAM_TYPE => 'limit',
IntegerDef::PARAM_MIN => 1,
IntegerDef::PARAM_MAX => 50,
IntegerDef::PARAM_MAX2 => 100,
],
'license' => [
ParamValidator::PARAM_TYPE => [ PageImages::LICENSE_FREE, PageImages::LICENSE_ANY ],
ParamValidator::PARAM_ISMULTI => false,
ParamValidator::PARAM_DEFAULT => $this->getConfig()->get( 'PageImagesAPIDefaultLicense' ),
],
'continue' => [
ParamValidator::PARAM_TYPE => 'integer',
ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
],
'langcode' => [
ParamValidator::PARAM_TYPE => 'string',
ParamValidator::PARAM_DEFAULT => null
]
];
}
/**
* @inheritDoc
*/
protected function getExamplesMessages() {
return [
'action=query&prop=pageimages&titles=Albert%20Einstein&pithumbsize=100' =>
'apihelp-query+pageimages-example-1',
];
}
/**
* @see ApiBase::getHelpUrls()
* @return string
*/
public function getHelpUrls() {
return "https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:PageImages#API";
}
}