wiki.techinc.nl/includes/api/ApiQueryLangLinks.php
Brad Jorsch c013ec02b9 (bug 36400) API: Fix sorting for iwlinks, langlinks
The iwlinks and langlinks modules continue parameters imply ordering by
page then prefix then title. But in certain modes, the actual queries
use a different ordering, which may result in skipped or repeated
results.

This changeset fixes that. To do so, it needs to re-add an index
iwl_prefix_from_title which was mistakenly removed in 2010 (r69721). And
while it's doing that, it cleans up errors in the sqlite and postgresql
handling of the iwlinks indexes too.

Also, per Asher, make the iwl_prefix_from_title and
iwl_prefix_title_from indexes non-UNIQUE.

Change-Id: I607e8bf9183a2d8152a6127a81c83a0b5bba0c61
2013-04-03 13:22:20 -04:00

188 lines
5.3 KiB
PHP

<?php
/**
*
*
* Created on May 13, 2007
*
* Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
/**
* A query module to list all langlinks (links to corresponding foreign language pages).
*
* @ingroup API
*/
class ApiQueryLangLinks extends ApiQueryBase {
public function __construct( $query, $moduleName ) {
parent::__construct( $query, $moduleName, 'll' );
}
public function execute() {
if ( $this->getPageSet()->getGoodTitleCount() == 0 ) {
return;
}
$params = $this->extractRequestParams();
if ( isset( $params['title'] ) && !isset( $params['lang'] ) ) {
$this->dieUsageMsg( array( 'missingparam', 'lang' ) );
}
$this->addFields( array(
'll_from',
'll_lang',
'll_title'
) );
$this->addTables( 'langlinks' );
$this->addWhereFld( 'll_from', array_keys( $this->getPageSet()->getGoodTitles() ) );
if ( !is_null( $params['continue'] ) ) {
$cont = explode( '|', $params['continue'] );
$this->dieContinueUsageIf( count( $cont ) != 2 );
$op = $params['dir'] == 'descending' ? '<' : '>';
$llfrom = intval( $cont[0] );
$lllang = $this->getDB()->addQuotes( $cont[1] );
$this->addWhere(
"ll_from $op $llfrom OR " .
"(ll_from = $llfrom AND " .
"ll_lang $op= $lllang)"
);
}
// Note that, since (ll_from, ll_lang) is a unique key, we don't need
// to sort by ll_title to ensure deterministic ordering.
$sort = ( $params['dir'] == 'descending' ? ' DESC' : '' );
if ( isset( $params['lang'] ) ) {
$this->addWhereFld( 'll_lang', $params['lang'] );
if ( isset( $params['title'] ) ) {
$this->addWhereFld( 'll_title', $params['title'] );
}
$this->addOption( 'ORDER BY', 'll_from' . $sort );
} else {
// Don't order by ll_from if it's constant in the WHERE clause
if ( count( $this->getPageSet()->getGoodTitles() ) == 1 ) {
$this->addOption( 'ORDER BY', 'll_lang' . $sort );
} else {
$this->addOption( 'ORDER BY', array(
'll_from' . $sort,
'll_lang' . $sort
));
}
}
$this->addOption( 'LIMIT', $params['limit'] + 1 );
$res = $this->select( __METHOD__ );
$count = 0;
foreach ( $res as $row ) {
if ( ++$count > $params['limit'] ) {
// We've reached the one extra which shows that
// there are additional pages to be had. Stop here...
$this->setContinueEnumParameter( 'continue', "{$row->ll_from}|{$row->ll_lang}" );
break;
}
$entry = array( 'lang' => $row->ll_lang );
if ( $params['url'] ) {
$title = Title::newFromText( "{$row->ll_lang}:{$row->ll_title}" );
if ( $title ) {
$entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
}
}
ApiResult::setContent( $entry, $row->ll_title );
$fit = $this->addPageSubItem( $row->ll_from, $entry );
if ( !$fit ) {
$this->setContinueEnumParameter( 'continue', "{$row->ll_from}|{$row->ll_lang}" );
break;
}
}
}
public function getCacheMode( $params ) {
return 'public';
}
public function getAllowedParams() {
return array(
'limit' => array(
ApiBase::PARAM_DFLT => 10,
ApiBase::PARAM_TYPE => 'limit',
ApiBase::PARAM_MIN => 1,
ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
),
'continue' => null,
'url' => false,
'lang' => null,
'title' => null,
'dir' => array(
ApiBase::PARAM_DFLT => 'ascending',
ApiBase::PARAM_TYPE => array(
'ascending',
'descending'
)
),
);
}
public function getParamDescription() {
return array(
'limit' => 'How many langlinks to return',
'continue' => 'When more results are available, use this to continue',
'url' => 'Whether to get the full URL',
'lang' => 'Language code',
'title' => "Link to search for. Must be used with {$this->getModulePrefix()}lang",
'dir' => 'The direction in which to list',
);
}
public function getResultProperties() {
return array(
'' => array(
'lang' => 'string',
'url' => array(
ApiBase::PROP_TYPE => 'string',
ApiBase::PROP_NULLABLE => true
),
'*' => 'string'
)
);
}
public function getDescription() {
return 'Returns all interlanguage links from the given page(s)';
}
public function getPossibleErrors() {
return array_merge( parent::getPossibleErrors(), array(
array( 'missingparam', 'lang' ),
) );
}
public function getExamples() {
return array(
'api.php?action=query&prop=langlinks&titles=Main%20Page&redirects=' => 'Get interlanguage links from the [[Main Page]]',
);
}
public function getHelpUrls() {
return 'https://www.mediawiki.org/wiki/API:Properties#langlinks_.2F_ll';
}
}