it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
=== Configuration changes in 1.18 ===
+* The WantedPages::getSQL hook has been removed and replaced with
+ WantedPages::getQueryInfo . This may break older extensions.
=== New features in 1.18 ===
* Added a special page, disabled by default, that allows users with the
&$timestamp: new timestamp, change this to override local email
authentification timestamp
-'WantedPages::getSQL': called in WantedPagesPage::getSQL(), can be used to
-alter the SQL query which gets the list of wanted pages
+'WantedPages::getQueryInfo': called in WantedPagesPage::getQueryInfo(), can be
+used to alter the SQL query which gets the list of wanted pages
&$wantedPages: WantedPagesPage object
-&$sql: raw SQL query used to get the list of wanted pages
+&$query: query array, see QueryPage::getQueryInfo() for format documentation
'WatchArticle': before a watch is added to an article
$user: user that will watch
'MostimagesPage' => 'includes/specials/SpecialMostimages.php',
'MostlinkedCategoriesPage' => 'includes/specials/SpecialMostlinkedcategories.php',
'MostlinkedPage' => 'includes/specials/SpecialMostlinked.php',
+ 'MostlinkedTemplatesPage' => 'includes/specials/SpecialMostlinkedtemplates.php',
'MostrevisionsPage' => 'includes/specials/SpecialMostrevisions.php',
'MovePageForm' => 'includes/specials/SpecialMovepage.php',
'SpecialNewpages' => 'includes/specials/SpecialNewpages.php',
'SpecialUserlogout' => 'includes/specials/SpecialUserlogout.php',
'SpecialVersion' => 'includes/specials/SpecialVersion.php',
'SpecialWhatlinkshere' => 'includes/specials/SpecialWhatlinkshere.php',
- 'SpecialWhatLinksHere' => 'includes/specials/SpecialWhatlinkshere.php',
'UncategorizedCategoriesPage' => 'includes/specials/SpecialUncategorizedcategories.php',
+ 'UncategorizedImagesPage' => 'includes/specials/SpecialUncategorizedimages.php',
'UncategorizedPagesPage' => 'includes/specials/SpecialUncategorizedpages.php',
'UncategorizedTemplatesPage' => 'includes/specials/SpecialUncategorizedtemplates.php',
'UndeleteForm' => 'includes/specials/SpecialUndelete.php',
'WantedFilesPage' => 'includes/specials/SpecialWantedfiles.php',
'WantedPagesPage' => 'includes/specials/SpecialWantedpages.php',
'WantedTemplatesPage' => 'includes/specials/SpecialWantedtemplates.php',
- 'WhatLinksHerePage' => 'includes/specials/SpecialWhatlinkshere.php',
'WikiImporter' => 'includes/ImportXMLReader.php',
'WikiRevision' => 'includes/Import.php',
'WithoutInterwikiPage' => 'includes/specials/SpecialWithoutinterwiki.php',
* @ingroup SpecialPage
* @author Rob Church <robchur@gmail.com>
*/
-class ImageQueryPage extends QueryPage {
+abstract class ImageQueryPage extends QueryPage {
/**
* Format and output report results using the given information plus
$out->addHTML( $gallery->toHtml() );
}
}
+
+ // Gotta override this since it's abstract
+ function formatResult( $skin, $result ) { }
/**
* Prepare an image object given a result row
return !empty( $wgNamespacesWithSubpages[$index] );
}
+ /**
+ * Get a list of all namespace indices which are considered to contain content
+ * @return array of namespace indices
+ */
+ public static function getContentNamespaces() {
+ global $wgContentNamespaces;
+ if( !is_array( $wgContentNamespaces ) || $wgContentNamespaces === array() ) {
+ return NS_MAIN;
+ } elseif ( !in_array( NS_MAIN, $wgContentNamespaces ) ) {
+ // always force NS_MAIN to be part of array (to match the algorithm used by isContent)
+ return array_merge( array( NS_MAIN ), $wgContentNamespaces );
+ } else {
+ return $wgContentNamespaces;
+ }
+ }
/**
* Is the namespace first-letter capitalized?
*
*
* @ingroup SpecialPage
*/
-class PageQueryPage extends QueryPage {
+abstract class PageQueryPage extends QueryPage {
/**
* Format the result as a simple link to the page
global $wgQueryPages; // not redundant
$wgQueryPages = array(
// QueryPage subclass Special page name Limit (false for none, none for the default)
-//----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
array( 'AncientPagesPage', 'Ancientpages' ),
array( 'BrokenRedirectsPage', 'BrokenRedirects' ),
array( 'DeadendPagesPage', 'Deadendpages' ),
array( 'DisambiguationsPage', 'Disambiguations' ),
array( 'DoubleRedirectsPage', 'DoubleRedirects' ),
+ array( 'FileDuplicateSearchPage', 'FileDuplicateSearch' ),
array( 'LinkSearchPage', 'LinkSearch' ),
array( 'ListredirectsPage', 'Listredirects' ),
array( 'LonelyPagesPage', 'Lonelypages' ),
array( 'LongPagesPage', 'Longpages' ),
+ array( 'MIMEsearchPage', 'MIMEsearch' ),
array( 'MostcategoriesPage', 'Mostcategories' ),
array( 'MostimagesPage', 'Mostimages' ),
array( 'MostlinkedCategoriesPage', 'Mostlinkedcategories' ),
- array( 'SpecialMostlinkedtemplates', 'Mostlinkedtemplates' ),
+ array( 'MostlinkedtemplatesPage', 'Mostlinkedtemplates' ),
array( 'MostlinkedPage', 'Mostlinked' ),
array( 'MostrevisionsPage', 'Mostrevisions' ),
array( 'FewestrevisionsPage', 'Fewestrevisions' ),
global $wgDisableCounters;
if ( !$wgDisableCounters )
- $wgQueryPages[] = array( 'PopularPagesPage', 'Popularpages' );
+ $wgQueryPages[] = array( 'PopularPagesPage', 'Popularpages' );
/**
* subclasses derive from it.
* @ingroup SpecialPage
*/
-class QueryPage {
+abstract class QueryPage extends SpecialPage {
/**
* Whether or not we want plain listoutput rather than an ordered list
*
var $offset = 0;
var $limit = 0;
+ /**
+ * The number of rows returned by the query. Reading this variable
+ * only makes sense in functions that are run after the query has been
+ * done, such as preprocessResults() and formatRow().
+ */
+ protected $numRows;
+
+ /**
+ * Wheter to show prev/next links
+ */
+ var $shownavigation = true;
+
/**
* A mutator for $this->listoutput;
*
$this->listoutput = $bool;
}
- /**
- * Subclasses return their name here. Make sure the name is also
- * specified in SpecialPage.php and in Language.php as a language message
- * param.
- *
- * @return String
- */
- function getName() {
- return '';
- }
-
/**
* Return title object representing this page
*
}
/**
- * Subclasses return an SQL query here.
+ * Subclasses return an SQL query here, formatted as an array with the
+ * following keys:
+ * tables => Table(s) for passing to Database::select()
+ * fields => Field(s) for passing to Database::select(), may be *
+ * conds => WHERE conditions
+ * options => options
+ * join_conds => JOIN conditions
*
- * Note that the query itself should return the following four columns:
- * 'type' (your special page's name), 'namespace', 'title', and 'value'
+ * Note that the query itself should return the following three columns:
+ * 'namespace', 'title', and 'value'
* *in that order*. 'value' is used for sorting.
*
* These may be stored in the querycache table for expensive queries,
* and that cached data will be returned sometimes, so the presence of
* extra fields can't be relied upon. The cached 'value' column will be
- * an integer; non-numeric values are useful only for sorting the initial
- * query.
+ * an integer; non-numeric values are useful only for sorting the
+ * initial query (except if they're timestamps, see usesTimestamps()).
*
- * Don't include an ORDER or LIMIT clause, this will be added.
+ * Don't include an ORDER or LIMIT clause, they will be added.
+ *
+ * If this function is not overridden or returns something other than
+ * an array, getSQL() will be used instead. This is for backwards
+ * compatibility only and is strongly deprecated.
+ * @return array
+ * @since 1.18
+ */
+ function getQueryInfo() {
+ return null;
+ }
+
+ /**
+ * For back-compat, subclasses may return a raw SQL query here, as a string.
+ * This is stronly deprecated; getQueryInfo() should be overridden instead.
+ * @return string
+ * @deprecated since 1.18
*/
function getSQL() {
- return "SELECT 'sample' as type, 0 as namespace, 'Sample result' as title, 42 as value";
+ throw new MWException( "Bug in a QueryPage: doesn't implement getQueryInfo() nor getQuery() properly" );
+ }
+
+ /**
+ * Subclasses return an array of fields to order by here. Don't append
+ * DESC to the field names, that'll be done automatically if
+ * sortDescending() returns true.
+ * @return array
+ * @since 1.18
+ */
+ function getOrderFields() {
+ return array( 'value' );
+ }
+
+ /**
+ * Does this query return timestamps rather than integers in its
+ * 'value' field? If true, this class will convert 'value' to a
+ * UNIX timestamp for caching.
+ * NOTE: formatRow() may get timestamps in TS_MW (mysql), TS_DB (pgsql)
+ * or TS_UNIX (querycache) format, so be sure to always run them
+ * through wfTimestamp()
+ * @return bool
+ */
+ function usesTimestamps() {
+ return false;
}
/**
return true;
}
- function getOrder() {
- return ' ORDER BY value ' .
- ($this->sortDescending() ? 'DESC' : '');
- }
-
/**
* Is this query expensive (for some definition of expensive)? Then we
* don't let it run in miser mode. $wgDisableQueryPages causes all query
}
/**
- * Whether or not the output of the page in question is retrived from
+ * Is the output of this query cacheable? Non-cacheable expensive pages
+ * will be disabled in miser mode and will not have their results written
+ * to the querycache table.
+ * @return Boolean
+ */
+ public function isCacheable() {
+ return true;
+ }
+
+ /**
+ * Whether or not the output of the page in question is retrieved from
* the database cache.
*
* @return Boolean
* Formats the results of the query for display. The skin is the current
* skin; you can use it for making links. The result is a single row of
* result data. You should be able to grab SQL results off of it.
- * If the function return "false", the line output will be skipped.
+ * If the function returns false, the line output will be skipped.
+ * @param $skin Skin
+ * @param $result object Result row
+ * @return mixed String or false to skip
*
* @param $skin Skin object
* @param $result Object: database row
*/
- function formatResult( $skin, $result ) {
- return '';
- }
+ abstract function formatResult( $skin, $result );
/**
* The content returned by this function will be output before any result
/**
* Some special pages (for example SpecialListusers) might not return the
* current object formatted, but return the previous one instead.
- * Setting this to return true, will call one more time wfFormatResult to
- * be sure that the very last result is formatted and shown.
+ * Setting this to return true will ensure formatResult() is called
+ * one more time to make sure that the very last result is formatted
+ * as well.
*/
function tryLastResult() {
return false;
$fname = get_class( $this ) . '::recache';
$dbw = wfGetDB( DB_MASTER );
$dbr = wfGetDB( DB_SLAVE, array( $this->getName(), __METHOD__, 'vslow' ) );
- if ( !$dbw || !$dbr ) {
+ if ( !$dbw || !$dbr || !$this->isCacheable() ) {
return false;
}
# Clear out any old cached data
$dbw->delete( 'querycache', array( 'qc_type' => $this->getName() ), $fname );
# Do query
- $sql = $this->getSQL() . $this->getOrder();
- if ( $limit !== false )
- $sql = $dbr->limitResult( $sql, $limit, 0 );
- $res = $dbr->query( $sql, $fname );
+ $res = $this->reallyDoQuery( $limit, false );
$num = false;
if ( $res ) {
$num = $dbr->numRows( $res );
$vals = array();
while ( $res && $row = $dbr->fetchObject( $res ) ) {
if ( isset( $row->value ) ) {
- $value = intval( $row->value ); // @bug 14414
+ if ( $this->usesTimestamps() ) {
+ $value = wfTimestamp( TS_UNIX,
+ $row->value );
+ } else {
+ $value = intval( $row->value ); // @bug 14414
+ }
} else {
$value = 0;
}
-
- $vals[] = array('qc_type' => $row->type,
+
+ $vals[] = array( 'qc_type' => $this->getName(),
'qc_namespace' => $row->namespace,
'qc_title' => $row->title,
- 'qc_value' => $value);
+ 'qc_value' => $value );
}
# Save results into the querycache table on the master
if ( count( $vals ) ) {
if ( !$dbw->insert( 'querycache', $vals, __METHOD__ ) ) {
// Set result to false to indicate error
- $res = false;
+ $num = false;
}
}
if ( $ignoreErrors ) {
return $num;
}
+ /**
+ * Run the query and return the result
+ * @param $limit mixed Numerical limit or false for no limit
+ * @param $offset mixed Numerical offset or false for no offset
+ * @return ResultWrapper
+ */
+ function reallyDoQuery( $limit, $offset = false ) {
+ $fname = get_class( $this ) . "::reallyDoQuery";
+ $query = $this->getQueryInfo();
+ $order = $this->getOrderFields();
+ if ( $this->sortDescending() ) {
+ foreach ( $order as &$field ) {
+ $field .= ' DESC';
+ }
+ }
+ if ( is_array( $query ) ) {
+ $tables = isset( $query['tables'] ) ? (array)$query['tables'] : array();
+ $fields = isset( $query['fields'] ) ? (array)$query['fields'] : array();
+ $conds = isset( $query['conds'] ) ? (array)$query['conds'] : array();
+ $options = isset( $query['options'] ) ? (array)$query['options'] : array();
+ $join_conds = isset( $query['join_conds'] ) ? (array)$query['join_conds'] : array();
+ if ( count( $order ) ) {
+ $options['ORDER BY'] = implode( ', ', $order );
+ }
+ if ( $limit !== false ) {
+ $options['LIMIT'] = intval( $limit );
+ }
+ if ( $offset !== false ) {
+ $options['OFFSET'] = intval( $offset );
+ }
+
+ $dbr = wfGetDB( DB_SLAVE );
+ $res = $dbr->select( $tables, $fields, $conds, $fname,
+ $options, $join_conds
+ );
+ } else {
+ // Old-fashioned raw SQL style, deprecated
+ $sql = $this->getSQL();
+ $sql .= ' ORDER BY ' . implode( ', ', $order );
+ $sql = $dbr->limitResult( $sql, $limit, $offset );
+ $res = $dbr->query( $sql );
+ }
+ return $dbr->resultObject( $res );
+ }
+
+ function doQuery( $limit, $offset = false ) {
+ if ( $this->isCached() && $this->isCacheable() ) {
+ return $this->fetchFromCache( $limit, $offset );
+ } else {
+ return $this->reallyDoQuery( $limit, $offset );
+ }
+ }
+
+ /**
+ * Fetch the query results from the query cache
+ * @param $limit mixed Numerical limit or false for no limit
+ * @param $offset mixed Numerical offset or false for no offset
+ * @return ResultWrapper
+ */
+ function fetchFromCache( $limit, $offset = false ) {
+ $dbr = wfGetDB( DB_SLAVE );
+ $options = array ();
+ if ( $limit !== false ) {
+ $options['LIMIT'] = intval( $limit );
+ }
+ if ( $offset !== false ) {
+ $options['OFFSET'] = intval( $offset );
+ }
+ $res = $dbr->select( 'querycache', array( 'qc_type',
+ 'qc_namespace AS namespace',
+ 'qc_title AS title',
+ 'qc_value AS value' ),
+ array( 'qc_type' => $this->getName() ),
+ __METHOD__, $options
+ );
+ return $dbr->resultObject( $res );
+ }
+
/**
* This is the actual workhorse. It does everything needed to make a
* real, honest-to-gosh query page.
- *
- * @param $offset database query offset
- * @param $limit database query limit
- * @param $shownavigation show navigation like "next 200"?
*/
- function doQuery( $offset, $limit, $shownavigation=true ) {
- global $wgUser, $wgOut, $wgLang, $wgContLang;
+ function execute( $par ) {
+ global $wgUser, $wgOut, $wgLang;
- $this->offset = $offset;
- $this->limit = $limit;
+ if ( !$this->userCanExecute( $wgUser ) ) {
+ $this->displayRestrictionError();
+ return;
+ }
+ if ( $this->limit == 0 && $this->offset == 0 )
+ list( $this->limit, $this->offset ) = wfCheckLimits();
$sname = $this->getName();
- $fname = get_class($this) . '::doQuery';
+ $fname = get_class( $this ) . '::doQuery';
$dbr = wfGetDB( DB_SLAVE );
+ $this->setHeaders();
$wgOut->setSyndicated( $this->isSyndicated() );
+ if ( $this->isCached() && !$this->isCacheable() ) {
+ $wgOut->setSyndicated( false );
+ $wgOut->addWikiMsg( 'querypage-disabled' );
+ return 0;
+ }
+
+ // TODO: Use doQuery()
+ // $res = null;
if ( !$this->isCached() ) {
- $sql = $this->getSQL();
+ $res = $this->reallyDoQuery( $this->limit, $this->offset );
} else {
# Get the cached result
- $querycache = $dbr->tableName( 'querycache' );
- $type = $dbr->strencode( $sname );
- $sql =
- "SELECT qc_type as type, qc_namespace as namespace,qc_title as title, qc_value as value
- FROM $querycache WHERE qc_type='$type'";
-
- if( !$this->listoutput ) {
+ $res = $this->fetchFromCache( $this->limit, $this->offset );
+ if ( !$this->listoutput ) {
# Fetch the timestamp of this update
- $tRes = $dbr->select( 'querycache_info', array( 'qci_timestamp' ), array( 'qci_type' => $type ), $fname );
+ $tRes = $dbr->select( 'querycache_info', array( 'qci_timestamp' ), array( 'qci_type' => $sname ), $fname );
$tRow = $dbr->fetchObject( $tRes );
- if( $tRow ) {
+ if ( $tRow ) {
$updated = $wgLang->timeanddate( $tRow->qci_timestamp, true, true );
$updateddate = $wgLang->date( $tRow->qci_timestamp, true, true );
$updatedtime = $wgLang->time( $tRow->qci_timestamp, true, true );
# If updates on this page have been disabled, let the user know
# that the data set won't be refreshed for now
global $wgDisableQueryPageUpdate;
- if( is_array( $wgDisableQueryPageUpdate ) && in_array( $this->getName(), $wgDisableQueryPageUpdate ) ) {
+ if ( is_array( $wgDisableQueryPageUpdate ) && in_array( $this->getName(), $wgDisableQueryPageUpdate ) ) {
$wgOut->addWikiMsg( 'querypage-no-updates' );
}
}
- $sql .= $this->getOrder();
- $sql = $dbr->limitResult($sql, $limit, $offset);
- $res = $dbr->query( $sql );
- $num = $dbr->numRows($res);
+ $this->numRows = $dbr->numRows( $res );
$this->preprocessResults( $dbr, $res );
- $wgOut->addHTML( Xml::openElement( 'div', array('class' => 'mw-spcontent') ) );
+ $wgOut->addHTML( Xml::openElement( 'div', array( 'class' => 'mw-spcontent' ) ) );
# Top header and navigation
- if( $shownavigation ) {
+ if ( $this->shownavigation ) {
$wgOut->addHTML( $this->getPageHeader() );
- if( $num > 0 ) {
- $wgOut->addHTML( '<p>' . wfShowingResults( $offset, $num ) . '</p>' );
+ if ( $this->numRows > 0 ) {
+ $wgOut->addHTML( '<p>' . wfShowingResults( $this->offset, $this->numRows ) . '</p>' );
# Disable the "next" link when we reach the end
- $paging = wfViewPrevNext( $offset, $limit, $wgContLang->specialPage( $sname ),
- wfArrayToCGI( $this->linkParameters() ), ( $num < $limit ) );
+ $paging = wfViewPrevNext( $this->offset, $this->limit,
+ $this->getTitle( $par ),
+ wfArrayToCGI( $this->linkParameters() ), ( $this->numRows < $this->limit ) );
$wgOut->addHTML( '<p>' . $paging . '</p>' );
} else {
# No results to show, so don't bother with "showing X of Y" etc.
$wgUser->getSkin(),
$dbr, # Should use a ResultWrapper for this
$res,
- $dbr->numRows( $res ),
- $offset );
+ $this->numRows,
+ $this->offset );
# Repeat the paging links at the bottom
- if( $shownavigation ) {
+ if ( $this->shownavigation ) {
$wgOut->addHTML( '<p>' . $paging . '</p>' );
}
$wgOut->addHTML( Xml::closeElement( 'div' ) );
- return $num;
+ return $this->numRows;
}
/**
protected function outputResults( $out, $skin, $dbr, $res, $num, $offset ) {
global $wgContLang;
- if( $num > 0 ) {
+ if ( $num > 0 ) {
$html = array();
- if( !$this->listoutput )
+ if ( !$this->listoutput )
$html[] = $this->openList( $offset );
# $res might contain the whole 1,000 rows, so we read up to
# $num [should update this to use a Pager]
- for( $i = 0; $i < $num && $row = $dbr->fetchObject( $res ); $i++ ) {
+ for ( $i = 0; $i < $num && $row = $dbr->fetchObject( $res ); $i++ ) {
$line = $this->formatResult( $skin, $row );
- if( $line ) {
+ if ( $line ) {
$attr = ( isset( $row->usepatrol ) && $row->usepatrol && $row->patrolled == 0 )
? ' class="not-patrolled"'
: '';
}
# Flush the final result
- if( $this->tryLastResult() ) {
+ if ( $this->tryLastResult() ) {
$row = null;
$line = $this->formatResult( $skin, $row );
- if( $line ) {
+ if ( $line ) {
$attr = ( isset( $row->usepatrol ) && $row->usepatrol && $row->patrolled == 0 )
? ' class="not-patrolled"'
: '';
}
}
- if( !$this->listoutput )
+ if ( !$this->listoutput )
$html[] = $this->closeList();
$html = $this->listoutput
$wgOut->addWikiMsg( 'feed-unavailable' );
return;
}
-
+
global $wgFeedLimit;
- if( $limit > $wgFeedLimit ) {
+ if ( $limit > $wgFeedLimit ) {
$limit = $wgFeedLimit;
}
- if( isset($wgFeedClasses[$class]) ) {
+ if ( isset( $wgFeedClasses[$class] ) ) {
$feed = new $wgFeedClasses[$class](
$this->feedTitle(),
$this->feedDesc(),
$feed->outHeader();
$dbr = wfGetDB( DB_SLAVE );
- $sql = $this->getSQL() . $this->getOrder();
- $sql = $dbr->limitResult( $sql, $limit, 0 );
- $res = $dbr->query( $sql, 'QueryPage::doFeed' );
+ $res = $this->reallyDoQuery( $limit, 0 );
foreach ( $res as $obj ) {
$item = $this->feedResult( $obj );
- if( $item ) {
+ if ( $item ) {
$feed->outItem( $item );
}
}
* feedItemDesc()
*/
function feedResult( $row ) {
- if( !isset( $row->title ) ) {
+ if ( !isset( $row->title ) ) {
return null;
}
$title = Title::MakeTitle( intval( $row->namespace ), $row->title );
- if( $title ) {
+ if ( $title ) {
$date = isset( $row->timestamp ) ? $row->timestamp : '';
$comments = '';
- if( $title ) {
+ if ( $title ) {
$talkpage = $title->getTalkPage();
$comments = $talkpage->getFullURL();
}
$title->getFullURL(),
$date,
$this->feedItemAuthor( $row ),
- $comments);
+ $comments );
} else {
return null;
}
// If there are no rows we get an error seeking.
$db->dataSeek( $res, 0 );
}
-
+
/**
* Should formatResult() always check page existence, even if
* the results are fresh? This is a (hopefully temporary)
*/
public function formatResult( $skin, $result ) {
$title = Title::makeTitleSafe( $result->namespace, $result->title );
- if( $title instanceof Title ) {
- if( $this->isCached() || $this->forceExistenceCheck() ) {
+ if ( $title instanceof Title ) {
+ if ( $this->isCached() || $this->forceExistenceCheck() ) {
$pageLink = $title->isKnown()
? '<del>' . $skin->link( $title ) . '</del>'
: $skin->link(
return wfMsgHtml( 'wantedpages-badtitle', $tsafe );
}
}
-
+
/**
* Make a "what links here" link for a given title
*
*/
static public $mList = array(
# Maintenance Reports
- 'BrokenRedirects' => array( 'SpecialPage', 'BrokenRedirects' ),
- 'Deadendpages' => array( 'SpecialPage', 'Deadendpages' ),
- 'DoubleRedirects' => array( 'SpecialPage', 'DoubleRedirects' ),
- 'Longpages' => array( 'SpecialPage', 'Longpages' ),
- 'Ancientpages' => array( 'SpecialPage', 'Ancientpages' ),
- 'Lonelypages' => array( 'SpecialPage', 'Lonelypages' ),
- 'Fewestrevisions' => array( 'SpecialPage', 'Fewestrevisions' ),
- 'Withoutinterwiki' => array( 'SpecialPage', 'Withoutinterwiki' ),
+ 'BrokenRedirects' => array( 'BrokenRedirectsPage' ),
+ 'Deadendpages' => array( 'DeadendpagesPage' ),
+ 'DoubleRedirects' => array( 'DoubleRedirectsPage' ),
+ 'Longpages' => array( 'LongpagesPage' ),
+ 'Ancientpages' => array( 'AncientpagesPage' ),
+ 'Lonelypages' => array( 'LonelypagesPage' ),
+ 'Fewestrevisions' => array( 'FewestrevisionsPage' ),
+ 'Withoutinterwiki' => array( 'WithoutinterwikiPage' ),
'Protectedpages' => 'SpecialProtectedpages',
'Protectedtitles' => 'SpecialProtectedtitles',
- 'Shortpages' => array( 'SpecialPage', 'Shortpages' ),
- 'Uncategorizedcategories' => array( 'SpecialPage', 'Uncategorizedcategories' ),
- 'Uncategorizedimages' => array( 'SpecialPage', 'Uncategorizedimages' ),
- 'Uncategorizedpages' => array( 'SpecialPage', 'Uncategorizedpages' ),
- 'Uncategorizedtemplates' => array( 'SpecialPage', 'Uncategorizedtemplates' ),
- 'Unusedcategories' => array( 'SpecialPage', 'Unusedcategories' ),
- 'Unusedimages' => array( 'SpecialPage', 'Unusedimages' ),
- 'Unusedtemplates' => array( 'SpecialPage', 'Unusedtemplates' ),
- 'Unwatchedpages' => array( 'SpecialPage', 'Unwatchedpages', 'unwatchedpages' ),
- 'Wantedcategories' => array( 'SpecialPage', 'Wantedcategories' ),
- 'Wantedfiles' => array( 'SpecialPage', 'Wantedfiles' ),
- 'Wantedpages' => array( 'IncludableSpecialPage', 'Wantedpages' ),
- 'Wantedtemplates' => array( 'SpecialPage', 'Wantedtemplates' ),
+ 'Shortpages' => array( 'ShortpagesPage' ),
+ 'Uncategorizedcategories' => array( 'UncategorizedcategoriesPage' ),
+ 'Uncategorizedimages' => array( 'UncategorizedimagesPage' ),
+ 'Uncategorizedpages' => array( 'UncategorizedpagesPage' ),
+ 'Uncategorizedtemplates' => array( 'UncategorizedtemplatesPage' ),
+ 'Unusedcategories' => array( 'UnusedcategoriesPage' ),
+ 'Unusedimages' => array( 'UnusedimagesPage' ),
+ 'Unusedtemplates' => array( 'UnusedtemplatesPage' ),
+ 'Unwatchedpages' => array( 'UnwatchedpagesPage' ),
+ 'Wantedcategories' => array( 'WantedcategoriesPage' ),
+ 'Wantedfiles' => array( 'WantedfilesPage' ),
+ 'Wantedpages' => array( 'WantedpagesPage' ),
+ 'Wantedtemplates' => array( 'WantedtemplatesPage' ),
# List of pages
'Allpages' => 'SpecialAllpages',
'Prefixindex' => 'SpecialPrefixindex',
'Categories' => 'SpecialCategories',
- 'Disambiguations' => array( 'SpecialPage', 'Disambiguations' ),
- 'Listredirects' => array( 'SpecialPage', 'Listredirects' ),
+ 'Disambiguations' => array( 'DisambiguationsPage' ),
+ 'Listredirects' => array( 'ListredirectsPage' ),
# Login/create account
'Userlogin' => 'LoginForm',
# Media reports and uploads
'Listfiles' => array( 'SpecialPage', 'Listfiles' ),
'Filepath' => 'SpecialFilepath',
- 'MIMEsearch' => array( 'SpecialPage', 'MIMEsearch' ),
- 'FileDuplicateSearch' => array( 'SpecialPage', 'FileDuplicateSearch' ),
+ 'MIMEsearch' => 'MIMEsearchPage',
+ 'FileDuplicateSearch' => 'FileDuplicateSearchPage',
'Upload' => 'SpecialUpload',
'UploadStash' => 'SpecialUploadStash',
'Unlockdb' => 'SpecialUnlockdb',
# Redirecting special pages
- 'LinkSearch' => array( 'SpecialPage', 'LinkSearch' ),
+ 'LinkSearch' => array( 'LinkSearchPage' ),
'Randompage' => 'Randompage',
'Randomredirect' => 'SpecialRandomredirect',
# High use pages
- 'Mostlinkedcategories' => array( 'SpecialPage', 'Mostlinkedcategories' ),
- 'Mostimages' => array( 'SpecialPage', 'Mostimages' ),
- 'Mostlinked' => array( 'SpecialPage', 'Mostlinked' ),
- 'Mostlinkedtemplates' => array( 'SpecialPage', 'Mostlinkedtemplates' ),
- 'Mostcategories' => array( 'SpecialPage', 'Mostcategories' ),
- 'Mostrevisions' => array( 'SpecialPage', 'Mostrevisions' ),
+ 'Mostlinkedcategories' => array( 'MostlinkedCategoriesPage' ),
+ 'Mostimages' => array( 'MostimagesPage' ),
+ 'Mostlinked' => array( 'MostlinkedPage' ),
+ 'Mostlinkedtemplates' => array( 'MostlinkedTemplatesPage' ),
+ 'Mostcategories' => array( 'MostcategoriesPage' ),
+ 'Mostrevisions' => array( 'MostrevisionsPage' ),
# Page tools
'ComparePages' => 'SpecialComparePages',
self::$mListInitialised = true;
if( !$wgDisableCounters ) {
- self::$mList['Popularpages'] = array( 'SpecialPage', 'Popularpages' );
+ self::$mList['Popularpages'] = array( 'PopularpagesPage' );
}
if( !$wgDisableInternalSearch ) {
*/
class AncientPagesPage extends QueryPage {
- function getName() {
- return "Ancientpages";
+ function __construct( $name = 'Ancientpages' ) {
+ parent::__construct( $name );
}
function isExpensive() {
function isSyndicated() { return false; }
- function getSQL() {
- $db = wfGetDB( DB_SLAVE );
- $page = $db->tableName( 'page' );
- $revision = $db->tableName( 'revision' );
- $epoch = $db->unixTimestamp( 'rev_timestamp' );
+ function getQueryInfo() {
+ return array(
+ 'tables' => array( 'page', 'revision' ),
+ 'fields' => array( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'rev_timestamp AS value' ),
+ 'conds' => array( 'page_namespace' => MWNamespace::getContentNamespaces(),
+ 'page_is_redirect' => 0,
+ 'page_latest=rev_id' )
+ );
+ }
- return
- "SELECT 'Ancientpages' as type,
- page_namespace as namespace,
- page_title as title,
- $epoch as value
- FROM $page, $revision
- WHERE page_namespace=".NS_MAIN." AND page_is_redirect=0
- AND page_latest=rev_id";
+ function usesTimestamps() {
+ return true;
}
function sortDescending() {
$title,
htmlspecialchars( $wgContLang->convert( $title->getPrefixedText() ) )
);
- return wfSpecialList($link, htmlspecialchars($d) );
+ return wfSpecialList( $link, htmlspecialchars($d) );
}
}
-
-function wfSpecialAncientpages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $app = new AncientPagesPage();
-
- $app->doQuery( $offset, $limit );
-}
* @ingroup SpecialPage
*/
class BrokenRedirectsPage extends PageQueryPage {
- var $targets = array();
- function getName() {
- return 'BrokenRedirects';
+ function __construct( $name = 'BrokenRedirects' ) {
+ parent::__construct( $name );
}
-
- function isExpensive( ) { return true; }
+
+ function isExpensive() { return true; }
function isSyndicated() { return false; }
+ function sortDescending() { return false; }
- function getPageHeader( ) {
+ function getPageHeader() {
return wfMsgExt( 'brokenredirectstext', array( 'parse' ) );
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $redirect ) = $dbr->tableNamesN( 'page', 'redirect' );
-
- $sql = "SELECT 'BrokenRedirects' AS type,
- p1.page_namespace AS namespace,
- p1.page_title AS title,
- rd_namespace,
- rd_title
- FROM $redirect AS rd
- JOIN $page p1 ON (rd.rd_from=p1.page_id)
- LEFT JOIN $page AS p2 ON (rd_namespace=p2.page_namespace AND rd_title=p2.page_title )
- WHERE rd_namespace >= 0
- AND p2.page_namespace IS NULL";
- return $sql;
+ function getQueryInfo() {
+ return array(
+ 'tables' => array( 'redirect', 'p1' => 'page',
+ 'p2' => 'page' ),
+ 'fields' => array( 'p1.page_namespace AS namespace',
+ 'p1.page_title AS title',
+ 'rd_namespace',
+ 'rd_title'
+ ),
+ 'conds' => array( 'rd_namespace >= 0',
+ 'p2.page_namespace IS NULL'
+ ),
+ 'join_conds' => array( 'p1' => array( 'LEFT JOIN', array(
+ 'rd_from=p1.page_id',
+ ) ),
+ 'p2' => array( 'LEFT JOIN', array(
+ 'rd_namespace=p2.page_namespace',
+ 'rd_title=p2.page_title'
+ ) )
+ )
+ );
}
- function getOrder() {
- return '';
+ function getOrderFields() {
+ return array ( 'rd_namespace', 'rd_title', 'rd_from' );
}
function formatResult( $skin, $result ) {
return $out;
}
}
-
-/**
- * constructor
- */
-function wfSpecialBrokenRedirects() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $sbr = new BrokenRedirectsPage();
-
- return $sbr->doQuery( $offset, $limit );
-}
*/
class DeadendPagesPage extends PageQueryPage {
- function getName( ) {
- return "Deadendpages";
+ function __construct( $name = 'Deadendpages' ) {
+ parent::__construct( $name );
}
function getPageHeader() {
*
* @return true
*/
- function isExpensive( ) {
- return 1;
+ function isExpensive() {
+ return true;
}
- function isSyndicated() { return false; }
+ function isSyndicated() {
+ return false;
+ }
/**
* @return false
return false;
}
- /**
- * @return string an sqlquery
- */
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $pagelinks ) = $dbr->tableNamesN( 'page', 'pagelinks' );
- return "SELECT 'Deadendpages' as type, page_namespace AS namespace, page_title as title, page_title AS value " .
- "FROM $page LEFT JOIN $pagelinks ON page_id = pl_from " .
- "WHERE pl_from IS NULL " .
- "AND page_namespace = 0 " .
- "AND page_is_redirect = 0";
+ function getQueryInfo() {
+ return array(
+ 'tables' => array( 'page', 'pagelinks' ),
+ 'fields' => array( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value'
+ ),
+ 'conds' => array( 'pl_from IS NULL',
+ 'page_namespace' => MWNamespace::getContentNamespaces(),
+ 'page_is_redirect' => 0
+ ),
+ 'join_conds' => array( 'pagelinks' => array( 'LEFT JOIN', array(
+ 'page_id=pl_from'
+ ) ) )
+ );
+ }
+
+ function getOrderFields() {
+ // For some crazy reason ordering by a constant
+ // causes a filesort
+ if( count( MWNamespace::getContentNamespaces() ) > 1 ) {
+ return array( 'page_namespace', 'page_title' );
+ } else {
+ return array( 'page_title' );
+ }
}
-}
-
-/**
- * Constructor
- */
-function wfSpecialDeadendpages() {
-
- list( $limit, $offset ) = wfCheckLimits();
-
- $depp = new DeadendPagesPage();
-
- return $depp->doQuery( $offset, $limit );
}
*/
class DisambiguationsPage extends PageQueryPage {
- function getName() {
- return 'Disambiguations';
+ function __construct( $name = 'Disambiguations' ) {
+ parent::__construct( $name );
}
- function isExpensive( ) { return true; }
+ function isExpensive() { return true; }
function isSyndicated() { return false; }
-
- function getPageHeader( ) {
+ function getPageHeader() {
return wfMsgExt( 'disambiguations-text', array( 'parse' ) );
}
- function getSQL() {
- global $wgContentNamespaces;
-
+ function getQueryInfo() {
$dbr = wfGetDB( DB_SLAVE );
-
- $dMsgText = wfMsgForContent('disambiguationspage');
-
+ $dMsgText = wfMsgForContent( 'disambiguationspage' );
$linkBatch = new LinkBatch;
# If the text can be treated as a title, use it verbatim.
# Otherwise, pull the titles from the links table
$dp = Title::newFromText($dMsgText);
if( $dp ) {
- if($dp->getNamespace() != NS_TEMPLATE) {
+ if( $dp->getNamespace() != NS_TEMPLATE ) {
# FIXME we assume the disambiguation message is a template but
# the page can potentially be from another namespace :/
wfDebug("Mediawiki:disambiguationspage message does not refer to a template!\n");
$res = $dbr->select(
array('pagelinks', 'page'),
'pl_title',
- array('page_id = pl_from', 'pl_namespace' => NS_TEMPLATE,
- 'page_namespace' => $disPageObj->getNamespace(), 'page_title' => $disPageObj->getDBkey()),
+ array('page_id = pl_from',
+ 'pl_namespace' => NS_TEMPLATE,
+ 'page_namespace' => $disPageObj->getNamespace(),
+ 'page_title' => $disPageObj->getDBkey()),
__METHOD__ );
foreach ( $res as $row ) {
$linkBatch->addObj( Title::makeTitle( NS_TEMPLATE, $row->pl_title ));
}
}
-
- $set = $linkBatch->constructSet( 'lb.tl', $dbr );
+ $set = $linkBatch->constructSet( 'tl', $dbr );
if( $set === false ) {
- # We must always return a valid sql query, but this way DB will always quicly return an empty result
+ # We must always return a valid SQL query, but this way
+ # the DB will always quickly return an empty result
$set = 'FALSE';
wfDebug("Mediawiki:disambiguationspage message does not link to any templates!\n");
}
+
+ // FIXME: What are pagelinks and p2 doing here?
+ return array (
+ 'tables' => array( 'templatelinks', 'p1' => 'page', 'pagelinks', 'p2' => 'page' ),
+ 'fields' => array( 'p1.page_namespace AS namespace',
+ 'p1.page_title AS title',
+ 'pl_from AS value' ),
+ 'conds' => array( $set,
+ 'p1.page_id = tl_from',
+ 'pl_namespace = p1.page_namespace',
+ 'pl_title = p1.page_title',
+ 'p2.page_id = pl_from',
+ 'p2.page_namespace' => MWNamespace::getContentNamespaces() )
+ );
+ }
- list( $page, $pagelinks, $templatelinks) = $dbr->tableNamesN( 'page', 'pagelinks', 'templatelinks' );
-
- if ( $wgContentNamespaces ) {
- $nsclause = 'IN (' . $dbr->makeList( $wgContentNamespaces ) . ')';
- } else {
- $nsclause = '= ' . NS_MAIN;
+ function getOrderFields() {
+ return array( 'tl_namespace', 'tl_title', 'value' );
+ }
+
+ function sortDescending() {
+ return false;
+ }
+
+ /**
+ * Fetch links and cache their existence
+ */
+ function preprocessResults( $db, $res ) {
+ $batch = new LinkBatch;
+ foreach ( $res as $row ) {
+ $batch->add( $row->namespace, $row->title );
}
+ $batch->execute();
- $sql = "SELECT 'Disambiguations' AS \"type\", pb.page_namespace AS namespace,"
- ." pb.page_title AS title, la.pl_from AS value"
- ." FROM {$templatelinks} AS lb, {$page} AS pb, {$pagelinks} AS la, {$page} AS pa"
- ." WHERE $set" # disambiguation template(s)
- .' AND pa.page_id = la.pl_from'
- .' AND pa.page_namespace ' . $nsclause
- .' AND pb.page_id = lb.tl_from'
- .' AND pb.page_namespace = la.pl_namespace'
- .' AND pb.page_title = la.pl_title'
- .' ORDER BY lb.tl_namespace, lb.tl_title';
-
- return $sql;
+ // Back to start for display
+ if ( $db->numRows( $res ) > 0 ) {
+ // If there are no rows we get an error seeking.
+ $db->dataSeek( $res, 0 );
+ }
}
- function getOrder() {
- return '';
- }
function formatResult( $skin, $result ) {
global $wgContLang;
$dp = Title::makeTitle( $result->namespace, $result->title );
$from = $skin->link( $title );
- $edit = $skin->link( $title, wfMsgExt( 'parentheses', array( 'escape' ), wfMsg( 'editlink' ) ) , array(), array( 'redirect' => 'no', 'action' => 'edit' ) );
+ $edit = $skin->link( $title, wfMsgExt( 'parentheses', array( 'escape' ), wfMsg( 'editlink' ) ) ,
+ array(), array( 'redirect' => 'no', 'action' => 'edit' ) );
$arr = $wgContLang->getArrow();
$to = $skin->link( $dp );
return "$from $edit $arr $to";
}
}
-
-/**
- * Constructor
- */
-function wfSpecialDisambiguations() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $sd = new DisambiguationsPage();
-
- return $sd->doQuery( $offset, $limit );
-}
*/
class DoubleRedirectsPage extends PageQueryPage {
- function getName() {
- return 'DoubleRedirects';
+ function __construct( $name = 'DoubleRedirects' ) {
+ parent::__construct( $name );
}
-
- function isExpensive( ) { return true; }
+
+ function isExpensive() { return true; }
function isSyndicated() { return false; }
+ function sortDescending() { return false; }
- function getPageHeader( ) {
+ function getPageHeader() {
return wfMsgExt( 'doubleredirectstext', array( 'parse' ) );
}
- function getSQLText( &$dbr, $namespace = null, $title = null ) {
-
- list( $page, $redirect ) = $dbr->tableNamesN( 'page', 'redirect' );
-
+ function reallyGetQueryInfo( $namespace = null, $title = null ) {
$limitToTitle = !( $namespace === null && $title === null );
- $sql = $limitToTitle ? "SELECT" : "SELECT 'DoubleRedirects' as type," ;
- $sql .=
- " pa.page_namespace as namespace, pa.page_title as title," .
- " pb.page_namespace as nsb, pb.page_title as tb," .
- " pc.page_namespace as nsc, pc.page_title as tc" .
- " FROM $redirect AS ra, $redirect AS rb, $page AS pa, $page AS pb, $page AS pc" .
- " WHERE ra.rd_from=pa.page_id" .
- " AND ra.rd_namespace=pb.page_namespace" .
- " AND ra.rd_title=pb.page_title" .
- " AND rb.rd_from=pb.page_id" .
- " AND rb.rd_namespace=pc.page_namespace" .
- " AND rb.rd_title=pc.page_title";
-
- if( $limitToTitle ) {
- $encTitle = $dbr->addQuotes( $title );
- $sql .= " AND pa.page_namespace=$namespace" .
- " AND pa.page_title=$encTitle";
+ $retval = array (
+ 'tables' => array ( 'ra' => 'redirect',
+ 'rb' => 'redirect', 'pa' => 'page',
+ 'pb' => 'page', 'pc' => 'page' ),
+ 'fields' => array ( 'pa.page_namespace AS namespace',
+ 'pa.page_title AS title',
+ 'pb.page_namespace AS nsb',
+ 'pb.page_title AS tb',
+ 'pc.page_namespace AS nsc',
+ 'pc.page_title AS tc' ),
+ 'conds' => array ( 'ra.rd_from = pa.page_id',
+ 'pb.page_namespace = ra.rd_namespace',
+ 'pb.page_title = ra.rd_title',
+ 'rb.rd_from = pb.page_id',
+ 'pc.page_namespace = rb.rd_namespace',
+ 'pc.page_title = rb.rd_title' )
+ );
+ if ( $limitToTitle ) {
+ $retval['conds']['pa.page_namespace'] = $namespace;
+ $retval['conds']['pa.page_title'] = $title;
}
-
- return $sql;
+ return $retval;
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- return $this->getSQLText( $dbr );
+ function getQueryInfo() {
+ return $this->reallyGetQueryInfo();
}
- function getOrder() {
- return '';
+ function getOrderFields() {
+ return array ( 'ra.rd_namespace', 'ra.rd_title' );
}
function formatResult( $skin, $result ) {
global $wgContLang;
- $fname = 'DoubleRedirectsPage::formatResult';
$titleA = Title::makeTitle( $result->namespace, $result->title );
if ( $result && !isset( $result->nsb ) ) {
$dbr = wfGetDB( DB_SLAVE );
- $sql = $this->getSQLText( $dbr, $result->namespace, $result->title );
- $res = $dbr->query( $sql, $fname );
+ $qi = $this->reallyGetQueryInfo( $result->namespace,
+ $result->title );
+ $res = $dbr->select($qi['tables'], $qi['fields'],
+ $qi['conds'], __METHOD__ );
if ( $res ) {
$result = $dbr->fetchObject( $res );
}
return( "{$linkA} {$edit} {$arr} {$linkB} {$arr} {$linkC}" );
}
}
-
-/**
- * constructor
- */
-function wfSpecialDoubleRedirects() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $sdr = new DoubleRedirectsPage();
-
- return $sdr->doQuery( $offset, $limit );
-
-}
*/
class FewestrevisionsPage extends QueryPage {
- function getName() {
- return 'Fewestrevisions';
+ function __construct( $name = 'Fewestrevisions' ) {
+ parent::__construct( $name );
}
-
+
function isExpensive() {
return true;
}
return false;
}
- function getSql() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $revision, $page ) = $dbr->tableNamesN( 'revision', 'page' );
-
- return "SELECT 'Fewestrevisions' as type,
- page_namespace as namespace,
- page_title as title,
- page_is_redirect as redirect,
- COUNT(*) as value
- FROM $revision
- JOIN $page ON page_id = rev_page
- WHERE page_namespace = " . NS_MAIN . "
- GROUP BY page_namespace, page_title, page_is_redirect
- HAVING COUNT(*) > 1";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'revision', 'page' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'COUNT(*) AS value',
+ 'page_is_redirect AS redirect' ),
+ 'conds' => array ( 'page_namespace' => MWNamespace::getContentNamespaces(),
+ 'page_id = rev_page' ),
+ 'options' => array ( 'HAVING' => 'COUNT(*) > 1',
// ^^^ This was probably here to weed out redirects.
// Since we mark them as such now, it might be
// useful to remove this. People _do_ create pages
// and never revise them, they aren't necessarily
// redirects.
+ 'GROUP BY' => 'page_namespace, page_title, ' .
+ 'page_is_redirect' )
+ );
}
+
function sortDescending() {
return false;
}
+ /**
+ * @param $skin Skin object
+ * @param $result Object: database row
+ */
function formatResult( $skin, $result ) {
global $wgLang, $wgContLang;
return wfSpecialList( $plink, $nlink );
}
}
-
-function wfSpecialFewestrevisions() {
- list( $limit, $offset ) = wfCheckLimits();
- $frp = new FewestrevisionsPage();
- $frp->doQuery( $offset, $limit );
-}
* @ingroup SpecialPage
*/
class FileDuplicateSearchPage extends QueryPage {
- var $hash, $filename;
+ protected $hash, $filename;
- function __construct( $hash, $filename ) {
- $this->hash = $hash;
- $this->filename = $filename;
+ function __construct( $name = 'FileDuplicateSearch' ) {
+ parent::__construct( $name );
}
- function getName() { return 'FileDuplicateSearch'; }
- function isExpensive() { return false; }
function isSyndicated() { return false; }
+ function isCacheable() { return false; }
function linkParameters() {
return array( 'filename' => $this->filename );
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- $image = $dbr->tableName( 'image' );
- $hash = $dbr->addQuotes( $this->hash );
+ function getQueryInfo() {
+ return array(
+ 'tables' => array( 'image' ),
+ 'fields' => array(
+ 'img_name AS title',
+ 'img_sha1 AS value',
+ 'img_user_text',
+ 'img_timestamp'
+ ),
+ 'conds' => array( 'img_sha1' => $this->hash )
+ );
+ }
+
+ function execute( $par ) {
+ global $wgRequest, $wgOut, $wgLang, $wgContLang, $wgScript;
+
+ $this->setHeaders();
+ $this->outputHeader();
+
+ $this->filename = isset( $par ) ? $par : $wgRequest->getText( 'filename' );
+ $this->hash = '';
+ $title = Title::makeTitleSafe( NS_FILE, $this->filename );
+ if( $title && $title->getText() != '' ) {
+ $dbr = wfGetDB( DB_SLAVE );
+ $this->hash = $dbr->selectField( 'image', 'img_sha1', array( 'img_name' => $title->getDBkey() ), __METHOD__ );
+ }
+
+ # Create the input form
+ $wgOut->addHTML(
+ Xml::openElement( 'form', array( 'id' => 'fileduplicatesearch', 'method' => 'get', 'action' => $wgScript ) ) .
+ Html::hidden( 'title', $this->getTitle()->getPrefixedDbKey() ) .
+ Xml::openElement( 'fieldset' ) .
+ Xml::element( 'legend', null, wfMsg( 'fileduplicatesearch-legend' ) ) .
+ Xml::inputLabel( wfMsg( 'fileduplicatesearch-filename' ), 'filename', 'filename', 50, $this->filename ) . ' ' .
+ Xml::submitButton( wfMsg( 'fileduplicatesearch-submit' ) ) .
+ Xml::closeElement( 'fieldset' ) .
+ Xml::closeElement( 'form' )
+ );
+
+ if( $this->hash != '' ) {
+ $align = $wgContLang->alignEnd();
+
+ # Show a thumbnail of the file
+ $img = wfFindFile( $title );
+ if ( $img ) {
+ $thumb = $img->transform( array( 'width' => 120, 'height' => 120 ) );
+ if( $thumb ) {
+ $wgOut->addHTML( '<div style="float:' . $align . '" id="mw-fileduplicatesearch-icon">' .
+ $thumb->toHtml( array( 'desc-link' => false ) ) . '<br />' .
+ wfMsgExt( 'fileduplicatesearch-info', array( 'parse' ),
+ $wgLang->formatNum( $img->getWidth() ),
+ $wgLang->formatNum( $img->getHeight() ),
+ $wgLang->formatSize( $img->getSize() ),
+ $img->getMimeType()
+ ) .
+ '</div>' );
+ }
+ }
- return "SELECT 'FileDuplicateSearch' AS type,
- img_name AS title,
- img_sha1 AS value,
- img_user_text,
- img_timestamp
- FROM $image
- WHERE img_sha1 = $hash
- ";
+ parent::execute( $par );
+
+ # Show a short summary
+ if( $this->numRows == 1 ) {
+ $wgOut->wrapWikiMsg(
+ "<p class='mw-fileduplicatesearch-result-1'>\n$1\n</p>",
+ array( 'fileduplicatesearch-result-1', $this->filename )
+ );
+ } elseif ( $this->numRows > 1 ) {
+ $wgOut->wrapWikiMsg(
+ "<p class='mw-fileduplicatesearch-result-n'>\n$1\n</p>",
+ array( 'fileduplicatesearch-result-n', $this->filename,
+ $wgLang->formatNum( $this->numRows - 1 ) )
+ );
+ }
+ }
}
function formatResult( $skin, $result ) {
return "$plink . . $user . . $time";
}
}
-
-/**
- * Output the HTML search form, and constructs the FileDuplicateSearch object.
- */
-function wfSpecialFileDuplicateSearch( $par = null ) {
- global $wgRequest, $wgOut, $wgLang, $wgContLang, $wgScript;
-
- $hash = '';
- $filename = isset( $par ) ? $par : $wgRequest->getText( 'filename' );
-
- $title = Title::newFromText( $filename );
- if( $title && $title->getText() != '' ) {
- $dbr = wfGetDB( DB_SLAVE );
- $image = $dbr->tableName( 'image' );
- $encFilename = $dbr->addQuotes( htmlspecialchars( $title->getDBkey() ) );
- $sql = "SELECT img_sha1 from $image where img_name = $encFilename";
- $res = $dbr->query( $sql );
- $row = $dbr->fetchRow( $res );
- if( $row !== false ) {
- $hash = $row[0];
- }
- }
-
- # Create the input form
- $wgOut->addHTML(
- Xml::openElement( 'form', array( 'id' => 'fileduplicatesearch', 'method' => 'get', 'action' => $wgScript ) ) .
- Html::hidden( 'title', SpecialPage::getTitleFor( 'FileDuplicateSearch' )->getPrefixedDbKey() ) .
- Xml::openElement( 'fieldset' ) .
- Xml::element( 'legend', null, wfMsg( 'fileduplicatesearch-legend' ) ) .
- Xml::inputLabel( wfMsg( 'fileduplicatesearch-filename' ), 'filename', 'filename', 50, $filename ) . ' ' .
- Xml::submitButton( wfMsg( 'fileduplicatesearch-submit' ) ) .
- Xml::closeElement( 'fieldset' ) .
- Xml::closeElement( 'form' )
- );
-
- if( $hash != '' ) {
- $align = $wgContLang->alignEnd();
-
- # Show a thumbnail of the file
- $img = wfFindFile( $title );
- if ( $img ) {
- $thumb = $img->transform( array( 'width' => 120, 'height' => 120 ) );
- if( $thumb ) {
- $wgOut->addHTML( '<div style="float:' . $align . '" id="mw-fileduplicatesearch-icon">' .
- $thumb->toHtml( array( 'desc-link' => false ) ) . '<br />' .
- wfMsgExt( 'fileduplicatesearch-info', array( 'parse' ),
- $wgLang->formatNum( $img->getWidth() ),
- $wgLang->formatNum( $img->getHeight() ),
- $wgLang->formatSize( $img->getSize() ),
- $img->getMimeType()
- ) .
- '</div>' );
- }
- }
-
- # Do the query
- $wpp = new FileDuplicateSearchPage( $hash, $filename );
- list( $limit, $offset ) = wfCheckLimits();
- $count = $wpp->doQuery( $offset, $limit );
-
- # Show a short summary
- if( $count == 1 ) {
- $wgOut->wrapWikiMsg(
- "<p class='mw-fileduplicatesearch-result-1'>\n$1\n</p>",
- array( 'fileduplicatesearch-result-1', $filename )
- );
- } elseif ( $count > 1 ) {
- $wgOut->wrapWikiMsg(
- "<p class='mw-fileduplicatesearch-result-n'>\n$1\n</p>",
- array( 'fileduplicatesearch-result-n', $filename, $wgLang->formatNum( $count - 1 ) )
- );
- }
- }
-}
/**
* Special:LinkSearch to search the external-links table.
- */
-function wfSpecialLinkSearch( $par ) {
-
- list( $limit, $offset ) = wfCheckLimits();
- global $wgOut, $wgUrlProtocols, $wgMiserMode, $wgLang;
- $target = $GLOBALS['wgRequest']->getVal( 'target', $par );
- $namespace = $GLOBALS['wgRequest']->getIntorNull( 'namespace', null );
-
- $protocols_list[] = '';
- foreach( $wgUrlProtocols as $prot ) {
- $protocols_list[] = $prot;
- }
-
- $target2 = $target;
- $protocol = '';
- $pr_sl = strpos($target2, '//' );
- $pr_cl = strpos($target2, ':' );
- if ( $pr_sl ) {
- // For protocols with '//'
- $protocol = substr( $target2, 0 , $pr_sl+2 );
- $target2 = substr( $target2, $pr_sl+2 );
- } elseif ( !$pr_sl && $pr_cl ) {
- // For protocols without '//' like 'mailto:'
- $protocol = substr( $target2, 0 , $pr_cl+1 );
- $target2 = substr( $target2, $pr_cl+1 );
- } elseif ( $protocol == '' && $target2 != '' ) {
- // default
- $protocol = 'http://';
- }
- if ( !in_array( $protocol, $protocols_list ) ) {
- // unsupported protocol, show original search request
- $target2 = $target;
- $protocol = '';
- }
-
- $self = Title::makeTitle( NS_SPECIAL, 'Linksearch' );
-
- $wgOut->addWikiMsg( 'linksearch-text', '<nowiki>' . $wgLang->commaList( $wgUrlProtocols ) . '</nowiki>' );
- $s = Xml::openElement( 'form', array( 'id' => 'mw-linksearch-form', 'method' => 'get', 'action' => $GLOBALS['wgScript'] ) ) .
- Html::hidden( 'title', $self->getPrefixedDbKey() ) .
- '<fieldset>' .
- Xml::element( 'legend', array(), wfMsg( 'linksearch' ) ) .
- Xml::inputLabel( wfMsg( 'linksearch-pat' ), 'target', 'target', 50, $target ) . ' ';
- if ( !$wgMiserMode ) {
- $s .= Xml::label( wfMsg( 'linksearch-ns' ), 'namespace' ) . ' ' .
- Xml::namespaceSelector( $namespace, '' );
- }
- $s .= Xml::submitButton( wfMsg( 'linksearch-ok' ) ) .
- '</fieldset>' .
- Xml::closeElement( 'form' );
- $wgOut->addHTML( $s );
-
- if( $target != '' ) {
- $searcher = new LinkSearchPage;
- $searcher->setParams( array(
- 'query' => $target2,
- 'namespace' => $namespace,
- 'protocol' => $protocol ) );
- $searcher->doQuery( $offset, $limit );
- }
-}
-
-/**
* @ingroup SpecialPage
*/
class LinkSearchPage extends QueryPage {
$this->mProt = $params['protocol'];
}
- function getName() {
- return 'LinkSearch';
+ function __construct( $name = 'LinkSearch' ) {
+ parent::__construct( $name );
+ }
+
+ function execute( $par ) {
+ global $wgOut, $wgRequest, $wgUrlProtocols, $wgMiserMode, $wgLang, $wgScript;
+ $target = $wgRequest->getVal( 'target', $par );
+ $namespace = $wgRequest->getIntorNull( 'namespace', null );
+
+ $protocols_list[] = '';
+ foreach( $wgUrlProtocols as $prot ) {
+ $protocols_list[] = $prot;
+ }
+
+ $target2 = $target;
+ $protocol = '';
+ $pr_sl = strpos($target2, '//' );
+ $pr_cl = strpos($target2, ':' );
+ if ( $pr_sl ) {
+ // For protocols with '//'
+ $protocol = substr( $target2, 0 , $pr_sl+2 );
+ $target2 = substr( $target2, $pr_sl+2 );
+ } elseif ( !$pr_sl && $pr_cl ) {
+ // For protocols without '//' like 'mailto:'
+ $protocol = substr( $target2, 0 , $pr_cl+1 );
+ $target2 = substr( $target2, $pr_cl+1 );
+ } elseif ( $protocol == '' && $target2 != '' ) {
+ // default
+ $protocol = 'http://';
+ }
+ if ( !in_array( $protocol, $protocols_list ) ) {
+ // unsupported protocol, show original search request
+ $target2 = $target;
+ $protocol = '';
+ }
+
+ $self = $this->getTitle();
+
+ $wgOut->addWikiMsg( 'linksearch-text', '<nowiki>' . $wgLang->commaList( $wgUrlProtocols ) . '</nowiki>' );
+ $s = Xml::openElement( 'form', array( 'id' => 'mw-linksearch-form', 'method' => 'get', 'action' => $GLOBALS['wgScript'] ) ) .
+ Html::hidden( 'title', $self->getPrefixedDbKey() ) .
+ '<fieldset>' .
+ Xml::element( 'legend', array(), wfMsg( 'linksearch' ) ) .
+ Xml::inputLabel( wfMsg( 'linksearch-pat' ), 'target', 'target', 50, $target ) . ' ';
+ if ( !$wgMiserMode ) {
+ $s .= Xml::label( wfMsg( 'linksearch-ns' ), 'namespace' ) . ' ' .
+ Xml::namespaceSelector( $namespace, '' );
+ }
+ $s .= Xml::submitButton( wfMsg( 'linksearch-ok' ) ) .
+ '</fieldset>' .
+ Xml::closeElement( 'form' );
+ $wgOut->addHTML( $s );
+
+ if( $target != '' ) {
+ $this->setParams( array(
+ 'query' => $target2,
+ 'namespace' => $namespace,
+ 'protocol' => $protocol ) );
+ parent::execute( $par );
+ if( $this->mMungedQuery === false )
+ $wgOut->addWikiText( wfMsg( 'linksearch-error' ) );
+ }
}
/**
*/
static function mungeQuery( $query , $prot ) {
$field = 'el_index';
- $rv = LinkFilter::makeLikeArray( $query , $prot );
- if ($rv === false) {
+ $rv = LinkFilter::makeLike( $query , $prot );
+ if ( $rv === false ) {
// LinkFilter doesn't handle wildcard in IP, so we'll have to munge here.
if (preg_match('/^(:?[0-9]{1,3}\.)+\*\s*$|^(:?[0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]*\*\s*$/', $query)) {
- $rv = array( $prot . rtrim($query, " \t*"), $dbr->anyString() );
+ $rv = $prot . rtrim($query, " \t*") . '%';
$field = 'el_to';
}
}
return $params;
}
- function getSQL() {
+ function getQueryInfo() {
global $wgMiserMode;
$dbr = wfGetDB( DB_SLAVE );
- $page = $dbr->tableName( 'page' );
- $externallinks = $dbr->tableName( 'externallinks' );
-
- /* strip everything past first wildcard, so that index-based-only lookup would be done */
- list( $munged, $clause ) = self::mungeQuery( $this->mQuery, $this->mProt );
- $stripped = LinkFilter::keepOneWildcard( $munged );
- $like = $dbr->buildLike( $stripped );
-
- $encSQL = '';
- if ( isset ($this->mNs) && !$wgMiserMode )
- $encSQL = 'AND page_namespace=' . $dbr->addQuotes( $this->mNs );
-
- $use_index = $dbr->useIndexClause( $clause );
- return
- "SELECT
- page_namespace AS namespace,
- page_title AS title,
- el_index AS value,
- el_to AS url
- FROM
- $page,
- $externallinks $use_index
- WHERE
- page_id=el_from
- AND $clause $like
- $encSQL";
+ // strip everything past first wildcard, so that
+ // index-based-only lookup would be done
+ list( $this->mMungedQuery, $clause ) = self::mungeQuery(
+ $this->mQuery, $this->mProt );
+ if( $this->mMungedQuery === false )
+ // Invalid query; return no results
+ return array( 'tables' => 'page', 'fields' => 'page_id', 'conds' => '0=1' );
+
+ $stripped = substr( $this->mMungedQuery, 0, strpos( $this->mMungedQuery, '%' ) + 1 );
+ $encSearch = $dbr->addQuotes( $stripped );
+ $retval = array (
+ 'tables' => array ( 'page', 'externallinks' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'el_index AS value', 'el_to AS url' ),
+ 'conds' => array ( 'page_id = el_from',
+ "$clause LIKE $encSearch" ),
+ 'options' => array( 'USE INDEX' => $clause )
+ );
+ if ( isset( $this->mNs ) && !$wgMiserMode ) {
+ $retval['conds']['page_namespace'] = $this->mNs;
+ }
+ return $retval;
}
function formatResult( $skin, $result ) {
* it as good enough for optimizing sort. The implicit ordering
* from the scan will usually do well enough for our needs.
*/
- function getOrder() {
- return '';
+ function getOrderFields() {
+ return array();
}
}
$tables = array( 'image' );
$fields = array_keys( $this->getFieldNames() );
$fields[] = 'img_user';
- $fields[array_search('thumb', $fields)] = 'img_name as thumb';
+ $fields[array_search('thumb', $fields)] = 'img_name AS thumb';
$options = $join_conds = array();
# Depends on $wgMiserMode
# Need to rewrite this one
foreach ( $fields as &$field ) {
if ( $field == 'count' ) {
- $field = 'COUNT(oi_archive_name) as count';
+ $field = 'COUNT(oi_archive_name) AS count';
}
}
unset( $field );
*/
class ListredirectsPage extends QueryPage {
- function getName() { return( 'Listredirects' ); }
- function isExpensive() { return( true ); }
- function isSyndicated() { return( false ); }
- function sortDescending() { return( false ); }
+ function __construct( $name = 'Listredirects' ) {
+ parent::__construct( $name );
+ }
+
+ function isExpensive() { return true; }
+ function isSyndicated() { return false; }
+ function sortDescending() { return false; }
+
+ function getQueryInfo() {
+ return array(
+ 'tables' => array( 'p1' => 'page', 'redirect', 'p2' => 'page' ),
+ 'fields' => array( 'p1.page_namespace AS namespace',
+ 'p1.page_title AS title',
+ 'rd_namespace',
+ 'rd_title',
+ 'p2.page_id AS redirid' ),
+ 'conds' => array( 'p1.page_is_redirect' => 1 ),
+ 'join_conds' => array( 'redirect' => array(
+ 'LEFT JOIN', 'rd_from=p1.page_id' ),
+ 'p2' => array( 'LEFT JOIN', array(
+ 'p2.page_namespace=rd_namespace',
+ 'p2.page_title=rd_title' ) ) )
+ );
+ }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- $page = $dbr->tableName( 'page' );
- $sql = "SELECT 'Listredirects' AS type, page_title AS title, page_namespace AS namespace,
- 0 AS value FROM $page WHERE page_is_redirect = 1";
- return( $sql );
+ function getOrderFields() {
+ return array ( 'p1.page_namespace', 'p1.page_title' );
}
function formatResult( $skin, $result ) {
}
}
}
-
-function wfSpecialListredirects() {
- list( $limit, $offset ) = wfCheckLimits();
- $lrp = new ListredirectsPage();
- $lrp->doQuery( $offset, $limit );
-}
*/
class LonelyPagesPage extends PageQueryPage {
- function getName() {
- return "Lonelypages";
+ function __construct( $name = 'Lonelypages' ) {
+ parent::__construct( $name );
}
+
function getPageHeader() {
return wfMsgExt( 'lonelypagestext', array( 'parse' ) );
}
}
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $pagelinks, $templatelinks ) = $dbr->tableNamesN( 'page', 'pagelinks', 'templatelinks' );
-
- return
- "SELECT 'Lonelypages' AS type,
- page_namespace AS namespace,
- page_title AS title,
- page_title AS value
- FROM $page
- LEFT JOIN $pagelinks
- ON page_namespace=pl_namespace AND page_title=pl_title
- LEFT JOIN $templatelinks
- ON page_namespace=tl_namespace AND page_title=tl_title
- WHERE pl_namespace IS NULL
- AND page_namespace=".NS_MAIN."
- AND page_is_redirect=0
- AND tl_namespace IS NULL";
-
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'page', 'pagelinks',
+ 'templatelinks' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value' ),
+ 'conds' => array ( 'pl_namespace IS NULL',
+ 'page_namespace' => MWNamespace::getContentNamespaces(),
+ 'page_is_redirect' => 0,
+ 'tl_namespace IS NULL' ),
+ 'join_conds' => array (
+ 'pagelinks' => array (
+ 'LEFT JOIN', array (
+ 'pl_namespace = page_namespace',
+ 'pl_title = page_title' ) ),
+ 'templatelinks' => array (
+ 'LEFT JOIN', array (
+ 'tl_namespace = page_namespace',
+ 'tl_title = page_title' ) ) )
+ );
+ }
+
+ function getOrderFields() {
+ // For some crazy reason ordering by a constant
+ // causes a filesort in MySQL 5
+ if( count( MWNamespace::getContentNamespaces() ) > 1 ) {
+ return array( 'page_namespace', 'page_title' );
+ } else {
+ return array( 'page_title' );
+ }
}
-}
-
-/**
- * Constructor
- */
-function wfSpecialLonelypages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $lpp = new LonelyPagesPage();
-
- return $lpp->doQuery( $offset, $limit );
}
*/
class LongPagesPage extends ShortPagesPage {
- function getName() {
- return "Longpages";
+ function __construct( $name = 'Longpages' ) {
+ parent::__construct( $name );
}
function sortDescending() {
return true;
}
}
-
-/**
- * constructor
- */
-function wfSpecialLongpages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $lpp = new LongPagesPage();
-
- $lpp->doQuery( $offset, $limit );
-}
* @ingroup SpecialPage
*/
class MIMEsearchPage extends QueryPage {
- var $major, $minor;
+ protected $major, $minor;
- function __construct( $major, $minor ) {
- $this->major = $major;
- $this->minor = $minor;
+ function __construct( $name = 'MIMEsearch' ) {
+ parent::__construct( $name );
}
- function getName() { return 'MIMEsearch'; }
-
- /**
- * Due to this page relying upon extra fields being passed in the SELECT it
- * will fail if it's set as expensive and misermode is on
- */
function isExpensive() { return true; }
function isSyndicated() { return false; }
+ function isCacheable() { return false; }
function linkParameters() {
- $arr = array( $this->major, $this->minor );
- $mime = implode( '/', $arr );
- return array( 'mime' => $mime );
+ return array( 'mime' => "{$this->major}/{$this->minor}" );
}
+
+ public function getQueryInfo() {
+ return array(
+ 'tables' => array( 'image' ),
+ 'fields' => array( "'" . NS_FILE . "' AS namespace",
+ 'img_name AS title',
+ 'img_major_mime AS value',
+ 'img_size',
+ 'img_width',
+ 'img_height',
+ 'img_user_text',
+ 'img_timestamp' ),
+ 'conds' => array( 'img_major_mime' => $this->major,
+ 'img_minor_mime' => $this->minor )
+ );
+ }
+
+ function execute( $par ) {
+ global $wgRequest, $wgOut;
+ $mime = $par ? $par : $wgRequest->getText( 'mime' );
+
+ $this->setHeaders();
+ $this->outputHeader();
+ $wgOut->addHTML(
+ Xml::openElement( 'form', array( 'id' => 'specialmimesearch', 'method' => 'get', 'action' => SpecialPage::getTitleFor( 'MIMEsearch' )->getLocalUrl() ) ) .
+ Xml::openElement( 'fieldset' ) .
+ Html::hidden( 'title', SpecialPage::getTitleFor( 'MIMEsearch' )->getPrefixedText() ) .
+ Xml::element( 'legend', null, wfMsg( 'mimesearch' ) ) .
+ Xml::inputLabel( wfMsg( 'mimetype' ), 'mime', 'mime', 20, $mime ) . ' ' .
+ Xml::submitButton( wfMsg( 'ilsubmit' ) ) .
+ Xml::closeElement( 'fieldset' ) .
+ Xml::closeElement( 'form' )
+ );
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- $image = $dbr->tableName( 'image' );
- $major = $dbr->addQuotes( $this->major );
- $minor = $dbr->addQuotes( $this->minor );
-
- return
- "SELECT 'MIMEsearch' AS type,
- " . NS_FILE . " AS namespace,
- img_name AS title,
- img_major_mime AS value,
-
- img_size,
- img_width,
- img_height,
- img_user_text,
- img_timestamp
- FROM $image
- WHERE img_major_mime = $major AND img_minor_mime = $minor
- ";
+ list( $this->major, $this->minor ) = self::parseMIME( $mime );
+ if ( $this->major == '' || $this->minor == '' || !self::isValidType( $this->major ) ) {
+ return;
+ }
+ parent::execute( $par );
}
+
function formatResult( $skin, $result ) {
global $wgContLang, $wgLang;
);
$download = $skin->makeMediaLinkObj( $nt, wfMsgHtml( 'download' ) );
- $bytes = wfMsgExt( 'nbytes', array( 'parsemag', 'escape'),
+ $bytes = wfMsgExt( 'nbytes', array( 'parsemag', 'escape' ),
$wgLang->formatNum( $result->img_size ) );
$dimensions = htmlspecialchars( wfMsg( 'widthheight',
$wgLang->formatNum( $result->img_width ),
return "($download) $plink . . $dimensions . . $bytes . . $user . . $time";
}
-}
-
-/**
- * Output the HTML search form, and constructs the MIMEsearchPage object.
- */
-function wfSpecialMIMEsearch( $par = null ) {
- global $wgRequest, $wgOut;
-
- $mime = isset( $par ) ? $par : $wgRequest->getText( 'mime' );
-
- $wgOut->addHTML(
- Xml::openElement( 'form', array( 'id' => 'specialmimesearch', 'method' => 'get', 'action' => SpecialPage::getTitleFor( 'MIMEsearch' )->getLocalUrl() ) ) .
- Xml::openElement( 'fieldset' ) .
- Html::hidden( 'title', SpecialPage::getTitleFor( 'MIMEsearch' )->getPrefixedText() ) .
- Xml::element( 'legend', null, wfMsg( 'mimesearch' ) ) .
- Xml::inputLabel( wfMsg( 'mimetype' ), 'mime', 'mime', 20, $mime ) . ' ' .
- Xml::submitButton( wfMsg( 'ilsubmit' ) ) .
- Xml::closeElement( 'fieldset' ) .
- Xml::closeElement( 'form' )
- );
-
- list( $major, $minor ) = wfSpecialMIMEsearchParse( $mime );
- if ( $major == '' or $minor == '' or !wfSpecialMIMEsearchValidType( $major ) )
- return;
- $wpp = new MIMEsearchPage( $major, $minor );
-
- list( $limit, $offset ) = wfCheckLimits();
- $wpp->doQuery( $offset, $limit );
-}
-
-function wfSpecialMIMEsearchParse( $str ) {
- // searched for an invalid MIME type.
- if( strpos( $str, '/' ) === false) {
- return array ('', '');
+
+ protected static function parseMIME( $str ) {
+ // searched for an invalid MIME type.
+ if( strpos( $str, '/' ) === false ) {
+ return array( '', '' );
+ }
+
+ list( $major, $minor ) = explode( '/', $str, 2 );
+
+ return array(
+ ltrim( $major, ' ' ),
+ rtrim( $minor, ' ' )
+ );
+ }
+
+ protected static function isValidType( $type ) {
+ // From maintenance/tables.sql => img_major_mime
+ $types = array(
+ 'unknown',
+ 'application',
+ 'audio',
+ 'image',
+ 'text',
+ 'video',
+ 'message',
+ 'model',
+ 'multipart'
+ );
+ return in_array( $type, $types );
}
-
- list( $major, $minor ) = explode( '/', $str, 2 );
-
- return array(
- ltrim( $major, ' ' ),
- rtrim( $minor, ' ' )
- );
-}
-
-function wfSpecialMIMEsearchValidType( $type ) {
- // From maintenance/tables.sql => img_major_mime
- $types = array(
- 'unknown',
- 'application',
- 'audio',
- 'image',
- 'text',
- 'video',
- 'message',
- 'model',
- 'multipart'
- );
-
- return in_array( $type, $types );
}
*/
class MostcategoriesPage extends QueryPage {
- function getName() { return 'Mostcategories'; }
+ function __construct( $name = 'Mostcategories' ) {
+ parent::__construct( $name );
+ }
+
function isExpensive() { return true; }
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $categorylinks, $page) = $dbr->tableNamesN( 'categorylinks', 'page' );
- return
- "
- SELECT
- 'Mostcategories' as type,
- page_namespace as namespace,
- page_title as title,
- COUNT(*) as value
- FROM $categorylinks
- LEFT JOIN $page ON cl_from = page_id
- WHERE page_namespace = " . NS_MAIN . "
- GROUP BY page_namespace, page_title
- HAVING COUNT(*) > 1
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'categorylinks', 'page' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'COUNT(*) AS value' ),
+ 'conds' => array ( 'page_namespace' => MWNamespace::getContentNamespaces() ),
+ 'options' => array ( 'HAVING' => 'COUNT(*) > 1',
+ 'GROUP BY' => 'page_namespace, page_title' ),
+ 'join_conds' => array ( 'page' => array ( 'LEFT JOIN',
+ 'page_id = cl_from' ) )
+ );
}
function formatResult( $skin, $result ) {
return wfSpecialList( $link, $count );
}
}
-
-/**
- * constructor
- */
-function wfSpecialMostcategories() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new MostcategoriesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
*/
class MostimagesPage extends ImageQueryPage {
- function getName() { return 'Mostimages'; }
+ function __construct( $name = 'Mostimages' ) {
+ parent::__construct( $name );
+ }
+
function isExpensive() { return true; }
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- $imagelinks = $dbr->tableName( 'imagelinks' );
- return
- "
- SELECT
- 'Mostimages' as type,
- " . NS_FILE . " as namespace,
- il_to as title,
- COUNT(*) as value
- FROM $imagelinks
- GROUP BY il_to
- HAVING COUNT(*) > 1
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'imagelinks' ),
+ 'fields' => array ( "'" . NS_FILE . "' AS namespace",
+ 'il_to AS title',
+ 'COUNT(*) AS value' ),
+ 'options' => array ( 'GROUP BY' => 'il_to',
+ 'HAVING' => 'COUNT(*) > 1' )
+ );
}
function getCellHtml( $row ) {
}
}
-
-/**
- * Constructor
- */
-function wfSpecialMostimages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new MostimagesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
*/
class MostlinkedPage extends QueryPage {
- function getName() { return 'Mostlinked'; }
+ function __construct( $name = 'Mostlinked' ) {
+ parent::__construct( $name );
+ }
+
function isExpensive() { return true; }
function isSyndicated() { return false; }
- function getSQL() {
- global $wgMiserMode;
-
- $dbr = wfGetDB( DB_SLAVE );
-
- # In miser mode, reduce the query cost by adding a threshold for large wikis
- if ( $wgMiserMode ) {
- $numPages = SiteStats::pages();
- if ( $numPages > 10000 ) {
- $cutoff = 100;
- } elseif ( $numPages > 100 ) {
- $cutoff = intval( sqrt( $numPages ) );
- } else {
- $cutoff = 1;
- }
- } else {
- $cutoff = 1;
- }
-
- list( $pagelinks, $page ) = $dbr->tableNamesN( 'pagelinks', 'page' );
- return
- "SELECT 'Mostlinked' AS type,
- pl_namespace AS namespace,
- pl_title AS title,
- COUNT(*) AS value
- FROM $pagelinks
- LEFT JOIN $page ON pl_namespace=page_namespace AND pl_title=page_title
- GROUP BY pl_namespace, pl_title
- HAVING COUNT(*) > $cutoff";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'pagelinks', 'page' ),
+ 'fields' => array ( 'pl_namespace AS namespace',
+ 'pl_title AS title',
+ 'COUNT(*) AS value',
+ 'page_namespace' ),
+ 'options' => array ( 'HAVING' => 'COUNT(*) > 1',
+ 'GROUP BY' => 'pl_namespace, pl_title, '.
+ 'page_namespace' ),
+ 'join_conds' => array ( 'page' => array ( 'LEFT JOIN',
+ array ( 'page_namespace = pl_namespace',
+ 'page_title = pl_title' ) ) )
+ );
}
/**
return wfSpecialList( $link, $wlh );
}
}
-
-/**
- * constructor
- */
-function wfSpecialMostlinked() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new MostlinkedPage();
-
- $wpp->doQuery( $offset, $limit );
-}
*/
class MostlinkedCategoriesPage extends QueryPage {
- function getName() { return 'Mostlinkedcategories'; }
+ function __construct( $name = 'Mostlinkedcategories' ) {
+ parent::__construct( $name );
+ }
+
function isExpensive() { return true; }
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- $categorylinks = $dbr->tableName( 'categorylinks' );
- $name = $dbr->addQuotes( $this->getName() );
- return
- "
- SELECT
- $name as type,
- " . NS_CATEGORY . " as namespace,
- cl_to as title,
- COUNT(*) as value
- FROM $categorylinks
- GROUP BY cl_to
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'categorylinks' ),
+ 'fields' => array ( 'cl_to AS title',
+ 'COUNT(*) AS value' ),
+ 'options' => array ( 'GROUP BY' => 'cl_to' )
+ );
}
function sortDescending() { return true; }
function preprocessResults( $db, $res ) {
$batch = new LinkBatch;
foreach ( $res as $row ) {
- $batch->add( $row->namespace, $row->title );
+ $batch->add( NS_CATEGORY, $row->title );
}
$batch->execute();
// Back to start for display
- if ( $db->numRows( $res ) > 0 )
+ if ( $db->numRows( $res ) > 0 ) {
// If there are no rows we get an error seeking.
$db->dataSeek( $res, 0 );
+ }
}
function formatResult( $skin, $result ) {
global $wgLang, $wgContLang;
- $nt = Title::makeTitle( $result->namespace, $result->title );
+ $nt = Title::makeTitle( NS_CATEGORY, $result->title );
$text = $wgContLang->convert( $nt->getText() );
$plink = $skin->link( $nt, htmlspecialchars( $text ) );
- $nlinks = wfMsgExt( 'nmembers', array( 'parsemag', 'escape'),
+ $nlinks = wfMsgExt( 'nmembers', array( 'parsemag', 'escape' ),
$wgLang->formatNum( $result->value ) );
- return wfSpecialList($plink, $nlinks);
+ return wfSpecialList( $plink, $nlinks );
}
}
-
-/**
- * constructor
- */
-function wfSpecialMostlinkedCategories() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new MostlinkedCategoriesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
*
* @ingroup SpecialPage
*/
-class SpecialMostlinkedtemplates extends QueryPage {
+class MostlinkedTemplatesPage extends QueryPage {
- /**
- * Name of the report
- *
- * @return String
- */
- public function getName() {
- return 'Mostlinkedtemplates';
+ function __construct( $name = 'Mostlinkedtemplates' ) {
+ parent::__construct( $name );
}
/**
return true;
}
- /**
- * Generate SQL for the report
- *
- * @return String
- */
- public function getSql() {
- $dbr = wfGetDB( DB_SLAVE );
- $templatelinks = $dbr->tableName( 'templatelinks' );
- $name = $dbr->addQuotes( $this->getName() );
- return "SELECT {$name} AS type,
- " . NS_TEMPLATE . " AS namespace,
- tl_title AS title,
- COUNT(*) AS value
- FROM {$templatelinks}
- WHERE tl_namespace = " . NS_TEMPLATE . "
- GROUP BY tl_title";
+ public function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'templatelinks' ),
+ 'fields' => array ( 'tl_namespace AS namespace',
+ 'tl_title AS title',
+ 'COUNT(*) AS value' ),
+ 'conds' => array ( 'tl_namespace' => NS_TEMPLATE ),
+ 'options' => array( 'GROUP BY' => 'tl_title' )
+ );
}
/**
* @return String
*/
public function formatResult( $skin, $result ) {
- $title = Title::makeTitleSafe( $result->namespace, $result->title );
+ $title = Title::makeTitle( $result->namespace, $result->title );
return wfSpecialList(
$skin->link( $title ),
}
}
-/**
- * Execution function
- *
- * @param $par Mixed: parameters passed to the page
- */
-function wfSpecialMostlinkedtemplates( $par = false ) {
- list( $limit, $offset ) = wfCheckLimits();
- $mlt = new SpecialMostlinkedtemplates();
- $mlt->doQuery( $offset, $limit );
-}
* @ingroup SpecialPage
* @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
*/
-
-/**
- * A special page to show pages with highest revision count
- *
- * @ingroup SpecialPage
- */
-class MostrevisionsPage extends QueryPage {
-
- function getName() { return 'Mostrevisions'; }
- function isExpensive() { return true; }
- function isSyndicated() { return false; }
-
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $revision, $page ) = $dbr->tableNamesN( 'revision', 'page' );
- return
- "
- SELECT
- 'Mostrevisions' as type,
- page_namespace as namespace,
- page_title as title,
- COUNT(*) as value
- FROM $revision
- JOIN $page ON page_id = rev_page
- WHERE page_namespace = " . NS_MAIN . "
- GROUP BY page_namespace, page_title
- HAVING COUNT(*) > 1
- ";
+class MostrevisionsPage extends FewestrevisionsPage {
+ function __construct( $name = 'Mostrevisions' ) {
+ parent::__construct( $name );
}
-
- function formatResult( $skin, $result ) {
- global $wgLang, $wgContLang;
-
- $nt = Title::makeTitle( $result->namespace, $result->title );
- $text = $wgContLang->convert( $nt->getPrefixedText() );
-
- $plink = $skin->linkKnown( $nt, $text );
-
- $nl = wfMsgExt( 'nrevisions', array( 'parsemag', 'escape'),
- $wgLang->formatNum( $result->value ) );
- $nlink = $skin->linkKnown(
- $nt,
- $nl,
- array(),
- array( 'action' => 'history' )
- );
-
- return wfSpecialList($plink, $nlink);
+
+ function sortDescending() {
+ return true;
}
}
-
-/**
- * constructor
- */
-function wfSpecialMostrevisions() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new MostrevisionsPage();
-
- $wpp->doQuery( $offset, $limit );
-}
$info = array(
'tables' => array( 'recentchanges', 'page' ),
- 'fields' => 'rc_namespace,rc_title, rc_cur_id, rc_user,rc_user_text,rc_comment,
- rc_timestamp,rc_patrolled,rc_id,page_len as length, page_latest as rev_id, ts_tags',
+ 'fields' => array( 'rc_namespace', 'rc_title', 'rc_cur_id', 'rc_user', 'rc_user_text', 'rc_comment',
+ 'rc_timestamp', 'rc_patrolled', 'rc_id', 'page_len AS length', 'page_latest AS rev_id', 'ts_tags'),
'conds' => $conds,
'options' => array( 'USE INDEX' => array('recentchanges' => $rcIndexes) ),
'join_conds' => array(
*/
class PopularPagesPage extends QueryPage {
- function getName() {
- return "Popularpages";
+ function __construct( $name = 'Popularpages' ) {
+ parent::__construct( $name );
}
function isExpensive() {
}
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- $page = $dbr->tableName( 'page' );
-
- $query =
- "SELECT 'Popularpages' as type,
- page_namespace as namespace,
- page_title as title,
- page_counter as value
- FROM $page ";
- $where =
- "WHERE page_is_redirect=0 AND page_namespace";
-
- global $wgContentNamespaces;
- if( empty( $wgContentNamespaces ) ) {
- $where .= '='.NS_MAIN;
- } else if( count( $wgContentNamespaces ) > 1 ) {
- $where .= ' in (' . implode( ', ', $wgContentNamespaces ) . ')';
- } else {
- $where .= '='.$wgContentNamespaces[0];
- }
-
- return $query . $where;
+ function getQueryInfo() {
+ return array (
+ 'tables' => array( 'page' ),
+ 'fields' => array( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_counter AS value'),
+ 'conds' => array( 'page_is_redirect' => 0,
+ 'page_namespace' => MWNamespace::getContentNamespaces() ) );
}
function formatResult( $skin, $result ) {
return wfSpecialList($link, $nv);
}
}
-
-/**
- * Constructor
- */
-function wfSpecialPopularpages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $ppp = new PopularPagesPage();
-
- return $ppp->doQuery( $offset, $limit );
-}
*/
class ShortPagesPage extends QueryPage {
- function getName() {
- return 'Shortpages';
+ function __construct( $name = 'Shortpages' ) {
+ parent::__construct( $name );
}
+ // inexpensive?
/**
* This query is indexed as of 1.5
*/
return false;
}
- function getSQL() {
- global $wgContentNamespaces;
-
- $dbr = wfGetDB( DB_SLAVE );
- $page = $dbr->tableName( 'page' );
- $name = $dbr->addQuotes( $this->getName() );
-
- $forceindex = $dbr->useIndexClause("page_len");
-
- if ($wgContentNamespaces)
- $nsclause = "page_namespace IN (" . $dbr->makeList($wgContentNamespaces) . ")";
- else
- $nsclause = "page_namespace = " . NS_MAIN;
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'page' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_len AS value' ),
+ 'conds' => array ( 'page_namespace' => MWNamespace::getContentNamespaces(),
+ 'page_is_redirect' => 0 ),
+ 'options' => array ( 'USE INDEX' => 'page_len' )
+ );
+ }
- return
- "SELECT $name as type,
- page_namespace as namespace,
- page_title as title,
- page_len AS value
- FROM $page $forceindex
- WHERE $nsclause AND page_is_redirect=0";
+ function getOrderFields() {
+ return array( 'page_len' );
}
function preprocessResults( $db, $res ) {
global $wgLang, $wgContLang;
$dm = $wgContLang->getDirMark();
- $title = Title::makeTitleSafe( $result->namespace, $result->title );
+ $title = Title::makeTitle( $result->namespace, $result->title );
if ( !$title ) {
return '<!-- Invalid title ' . htmlspecialchars( "{$result->namespace}:{$result->title}" ). '-->';
}
: "<del>({$hlink}) {$dm}{$plink} {$dm}[{$size}]</del>";
}
}
-
-/**
- * constructor
- */
-function wfSpecialShortpages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $spp = new ShortPagesPage();
-
- return $spp->doQuery( $offset, $limit );
-}
Xml::tags( 'th', null, wfMsgExt( 'tags-hitcount-header', 'parseinline' ) )
);
$dbr = wfGetDB( DB_SLAVE );
- $res = $dbr->select( 'change_tag', array( 'ct_tag', 'count(*) as hitcount' ), array(), __METHOD__, array( 'GROUP BY' => 'ct_tag', 'ORDER BY' => 'hitcount DESC' ) );
+ $res = $dbr->select( 'change_tag', array( 'ct_tag', 'count(*) AS hitcount' ),
+ array(), __METHOD__, array( 'GROUP BY' => 'ct_tag', 'ORDER BY' => 'hitcount DESC' ) );
foreach ( $res as $row ) {
$html .= $this->doTagRow( $row->ct_tag, $row->hitcount );
* @ingroup SpecialPage
*/
class UncategorizedCategoriesPage extends UncategorizedPagesPage {
- function __construct() {
+ function __construct( $name = 'Uncategorizedcategories' ) {
+ parent::__construct( $name );
$this->requestedNamespace = NS_CATEGORY;
}
-
- function getName() {
- return "Uncategorizedcategories";
- }
-}
-
-/**
- * constructor
- */
-function wfSpecialUncategorizedcategories() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $lpp = new UncategorizedCategoriesPage();
-
- return $lpp->doQuery( $offset, $limit );
}
*
* @ingroup SpecialPage
*/
+// FIXME: Use an instance of UncategorizedPagesPage or something
class UncategorizedImagesPage extends ImageQueryPage {
- function getName() {
- return 'Uncategorizedimages';
+ function __construct( $name = 'Uncategorizedimages' ) {
+ parent::__construct( $name );
}
function sortDescending() {
function isSyndicated() {
return false;
}
-
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $categorylinks ) = $dbr->tableNamesN( 'page', 'categorylinks' );
- $ns = NS_FILE;
-
- return "SELECT 'Uncategorizedimages' AS type, page_namespace AS namespace,
- page_title AS title, page_title AS value
- FROM {$page} LEFT JOIN {$categorylinks} ON page_id = cl_from
- WHERE cl_from IS NULL AND page_namespace = {$ns} AND page_is_redirect = 0";
+
+ function getQueryInfo() {
+ return array (
+ 'tables' => array( 'page', 'categorylinks' ),
+ 'fields' => array( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value' ),
+ 'conds' => array( 'cl_from IS NULL',
+ 'page_namespace' => NS_FILE,
+ 'page_is_redirect' => 0 ),
+ 'join_conds' => array( 'categorylinks' => array(
+ 'LEFT JOIN', 'cl_from=page_id' ) )
+ );
}
}
-
-function wfSpecialUncategorizedimages() {
- $uip = new UncategorizedImagesPage();
- list( $limit, $offset ) = wfCheckLimits();
- return $uip->doQuery( $offset, $limit );
-}
*
* @ingroup SpecialPage
*/
+// FIXME: Make $requestedNamespace selectable, unify all subclasses into one
class UncategorizedPagesPage extends PageQueryPage {
- var $requestedNamespace = NS_MAIN;
+ protected $requestedNamespace = false;
- function getName() {
- return "Uncategorizedpages";
+ function __construct( $name = 'Uncategorizedpages' ) {
+ parent::__construct( $name );
}
function sortDescending() {
}
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $categorylinks ) = $dbr->tableNamesN( 'page', 'categorylinks' );
- $name = $dbr->addQuotes( $this->getName() );
-
- return
- "
- SELECT
- $name as type,
- page_namespace AS namespace,
- page_title AS title,
- page_title AS value
- FROM $page
- LEFT JOIN $categorylinks ON page_id=cl_from
- WHERE cl_from IS NULL AND page_namespace={$this->requestedNamespace} AND page_is_redirect=0
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'page', 'categorylinks' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value' ),
+ // default for page_namespace is all content namespaces (if requestedNamespace is false)
+ // otherwise, page_namespace is requestedNamespace
+ 'conds' => array ( 'cl_from IS NULL',
+ 'page_namespace' => ( $this->requestedNamespace!==false ? $this->requestedNamespace : MWNamespace::getContentNamespaces() ),
+ 'page_is_redirect' => 0 ),
+ 'join_conds' => array ( 'categorylinks' => array (
+ 'LEFT JOIN', 'cl_from = page_id' ) )
+ );
+ }
+
+ function getOrderFields() {
+ // For some crazy reason ordering by a constant
+ // causes a filesort
+ if( $this->requestedNamespace === false && count( MWNamespace::getContentNamespaces() ) > 1 )
+ return array( 'page_namespace', 'page_title' );
+ return array( 'page_title' );
}
-}
-
-/**
- * constructor
- */
-function wfSpecialUncategorizedpages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $lpp = new UncategorizedPagesPage();
-
- return $lpp->doQuery( $offset, $limit );
}
* @ingroup SpecialPage
*/
class UncategorizedTemplatesPage extends UncategorizedPagesPage {
-
- var $requestedNamespace = NS_TEMPLATE;
-
- public function getName() {
- return 'Uncategorizedtemplates';
+ public function __construct( $name = 'Uncategorizedtemplates' ) {
+ parent::__construct( $name );
+ $this->requestedNamespace = NS_TEMPLATE;
}
-
-}
-
-/**
- * Main execution point
- */
-function wfSpecialUncategorizedtemplates() {
- list( $limit, $offset ) = wfCheckLimits();
- $utp = new UncategorizedTemplatesPage();
- $utp->doQuery( $offset, $limit );
}
function isExpensive() { return true; }
- function getName() {
- return 'Unusedcategories';
+ function __construct( $name = 'Unusedcategories' ) {
+ parent::__construct( $name );
}
function getPageHeader() {
return wfMsgExt( 'unusedcategoriestext', array( 'parse' ) );
}
- function getSQL() {
- $NScat = NS_CATEGORY;
- $dbr = wfGetDB( DB_SLAVE );
- list( $categorylinks, $page ) = $dbr->tableNamesN( 'categorylinks', 'page' );
- return "SELECT 'Unusedcategories' as type,
- {$NScat} as namespace, page_title as title, page_title as value
- FROM $page
- LEFT JOIN $categorylinks ON page_title=cl_to
- WHERE cl_from IS NULL
- AND page_namespace = {$NScat}
- AND page_is_redirect = 0";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'page', 'categorylinks' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value' ),
+ 'conds' => array ( 'cl_from IS NULL',
+ 'page_namespace' => NS_CATEGORY,
+ 'page_is_redirect' => 0 ),
+ 'join_conds' => array ( 'categorylinks' => array (
+ 'LEFT JOIN', 'cl_to = page_title' ) )
+ );
}
function formatResult( $skin, $result ) {
return $skin->link( $title, $title->getText() );
}
}
-
-/** constructor */
-function wfSpecialUnusedCategories() {
- list( $limit, $offset ) = wfCheckLimits();
- $uc = new UnusedCategoriesPage();
- return $uc->doQuery( $offset, $limit );
-}
* @ingroup SpecialPage
*/
class UnusedimagesPage extends ImageQueryPage {
-
- function isExpensive() { return true; }
-
- function getName() {
- return 'Unusedimages';
+ function __construct( $name = 'Unusedimages' ) {
+ parent::__construct( $name );
}
-
+
+ function isExpensive() {
+ return true;
+ }
+
function sortDescending() {
return false;
}
- function isSyndicated() { return false; }
+
+ function isSyndicated() {
+ return false;
+ }
- function getSQL() {
+ function getQueryInfo() {
global $wgCountCategorizedImagesAsUsed;
-
- $dbr = wfGetDB( DB_SLAVE );
-
- $epoch = $dbr->unixTimestamp( 'img_timestamp' );
+ $retval = array (
+ 'tables' => array ( 'image', 'imagelinks' ),
+ 'fields' => array ( "'" . NS_FILE . "' AS namespace",
+ 'img_name AS title',
+ 'img_timestamp AS value',
+ 'img_user', 'img_user_text',
+ 'img_description' ),
+ 'conds' => array ( 'il_to IS NULL' ),
+ 'join_conds' => array ( 'imagelinks' => array (
+ 'LEFT JOIN', 'il_to = img_name' ) )
+ );
if ( $wgCountCategorizedImagesAsUsed ) {
- list( $page, $image, $imagelinks, $categorylinks ) = $dbr->tableNamesN( 'page', 'image', 'imagelinks', 'categorylinks' );
-
- return "SELECT 'Unusedimages' as type, 6 as namespace, img_name as title, $epoch as value,
- img_user, img_user_text, img_description
- FROM ((($page AS I LEFT JOIN $categorylinks AS L ON I.page_id = L.cl_from)
- LEFT JOIN $imagelinks AS P ON I.page_title = P.il_to)
- INNER JOIN $image AS G ON I.page_title = G.img_name)
- WHERE I.page_namespace = ".NS_FILE." AND L.cl_from IS NULL AND P.il_to IS NULL";
- } else {
- list( $image, $imagelinks ) = $dbr->tableNamesN( 'image','imagelinks' );
-
- return "SELECT 'Unusedimages' as type, 6 as namespace, img_name as title, $epoch as value,
- img_user, img_user_text, img_description
- FROM $image LEFT JOIN $imagelinks ON img_name=il_to WHERE il_to IS NULL ";
+ // Order is significant
+ $retval['tables'] = array ( 'image', 'page', 'categorylinks',
+ 'imagelinks' );
+ $retval['conds']['page_namespace'] = NS_FILE;
+ $retval['conds'][] = 'cl_from IS NULL';
+ $retval['conds'][] = 'img_name = page_title';
+ $retval['join_conds']['categorylinks'] = array (
+ 'LEFT JOIN', 'cl_from = page_id' );
+ $retval['join_conds']['imagelinks'] = array (
+ 'LEFT JOIN', 'il_to = page_title' );
}
+ return $retval;
+ }
+
+ function usesTimestamps() {
+ return true;
}
function getPageHeader() {
}
}
-
-/**
- * Entry point
- */
-function wfSpecialUnusedimages() {
- list( $limit, $offset ) = wfCheckLimits();
- $uip = new UnusedimagesPage();
-
- return $uip->doQuery( $offset, $limit );
-}
*/
class UnusedtemplatesPage extends QueryPage {
- function getName() { return( 'Unusedtemplates' ); }
+ function __construct( $name = 'Unusedtemplates' ) {
+ parent::__construct( $name );
+ }
+
function isExpensive() { return true; }
function isSyndicated() { return false; }
function sortDescending() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $templatelinks) = $dbr->tableNamesN( 'page', 'templatelinks' );
- $sql = "SELECT 'Unusedtemplates' AS type, page_title AS title,
- page_namespace AS namespace, 0 AS value
- FROM $page
- LEFT JOIN $templatelinks
- ON page_namespace = tl_namespace AND page_title = tl_title
- WHERE page_namespace = 10 AND tl_from IS NULL
- AND page_is_redirect = 0";
- return $sql;
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'page', 'templatelinks' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value' ),
+ 'conds' => array ( 'page_namespace' => NS_TEMPLATE,
+ 'tl_from IS NULL',
+ 'page_is_redirect' => 0 ),
+ 'join_conds' => array ( 'templatelinks' => array (
+ 'LEFT JOIN', array ( 'tl_title = page_title',
+ 'tl_namespace = page_namespace' ) ) )
+ );
}
-
+
function formatResult( $skin, $result ) {
$title = Title::makeTitle( NS_TEMPLATE, $result->title );
$pageLink = $skin->linkKnown(
}
-function wfSpecialUnusedtemplates() {
- list( $limit, $offset ) = wfCheckLimits();
- $utp = new UnusedtemplatesPage();
- $utp->doQuery( $offset, $limit );
-}
*/
class UnwatchedpagesPage extends QueryPage {
- function getName() { return 'Unwatchedpages'; }
+ function __construct( $name = 'Unwatchedpages' ) {
+ parent::__construct( $name, 'unwatchedpages' );
+ }
+
function isExpensive() { return true; }
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $watchlist ) = $dbr->tableNamesN( 'page', 'watchlist' );
- $mwns = NS_MEDIAWIKI;
- return
- "
- SELECT
- 'Unwatchedpages' as type,
- page_namespace as namespace,
- page_title as title,
- page_namespace as value
- FROM $page
- LEFT JOIN $watchlist ON wl_namespace = page_namespace AND page_title = wl_title
- WHERE wl_title IS NULL AND page_is_redirect = 0 AND page_namespace<>$mwns
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'page', 'watchlist' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_namespace AS value' ),
+ 'conds' => array ( 'wl_title IS NULL',
+ 'page_is_redirect' => 0,
+ "page_namespace != '" . NS_MEDIAWIKI .
+ "'" ),
+ 'join_conds' => array ( 'watchlist' => array (
+ 'LEFT JOIN', array ( 'wl_title = page_title',
+ 'wl_namespace = page_namespace' ) ) )
+ );
}
function sortDescending() { return false; }
+
+ function getOrderFields() {
+ return array( 'page_namespace', 'page_title' );
+ }
function formatResult( $skin, $result ) {
global $wgContLang;
return wfSpecialList( $plink, $wlink );
}
}
-
-/**
- * constructor
- */
-function wfSpecialUnwatchedpages() {
- global $wgUser, $wgOut;
-
- if ( ! $wgUser->isAllowed( 'unwatchedpages' ) )
- return $wgOut->permissionRequired( 'unwatchedpages' );
-
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new UnwatchedpagesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
*/
class WantedCategoriesPage extends WantedQueryPage {
- function getName() {
- return 'Wantedcategories';
+ function __construct( $name = 'Wantedcategories' ) {
+ parent::__construct( $name );
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $categorylinks, $page ) = $dbr->tableNamesN( 'categorylinks', 'page' );
- $name = $dbr->addQuotes( $this->getName() );
- return
- "
- SELECT
- $name as type,
- " . NS_CATEGORY . " as namespace,
- cl_to as title,
- COUNT(*) as value
- FROM $categorylinks
- LEFT JOIN $page ON cl_to = page_title AND page_namespace = ". NS_CATEGORY ."
- WHERE page_title IS NULL
- GROUP BY cl_to
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'categorylinks', 'page' ),
+ 'fields' => array ( "'" . NS_CATEGORY . "' AS namespace",
+ 'cl_to AS title',
+ 'COUNT(*) AS value' ),
+ 'conds' => array ( 'page_title IS NULL' ),
+ 'options' => array ( 'GROUP BY' => 'cl_to' ),
+ 'join_conds' => array ( 'page' => array ( 'LEFT JOIN',
+ array ( 'page_title = cl_to',
+ 'page_namespace' => NS_CATEGORY ) ) )
+ );
}
function formatResult( $skin, $result ) {
return wfSpecialList($plink, $nlinks);
}
}
-
-/**
- * constructor
- */
-function wfSpecialWantedCategories() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new WantedCategoriesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
*/
class WantedFilesPage extends WantedQueryPage {
- function getName() {
- return 'Wantedfiles';
+ function __construct( $name = 'Wantedfiles' ) {
+ parent::__construct( $name );
}
-
+
/**
* KLUGE: The results may contain false positives for files
* that exist e.g. in a shared repo. Setting this at least
return true;
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $imagelinks, $image ) = $dbr->tableNamesN( 'imagelinks', 'image' );
- $name = $dbr->addQuotes( $this->getName() );
- return
- "
- SELECT
- $name as type,
- " . NS_FILE . " as namespace,
- il_to as title,
- COUNT(*) as value
- FROM $imagelinks
- LEFT JOIN $image ON il_to = img_name
- WHERE img_name IS NULL
- GROUP BY il_to
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'imagelinks', 'image' ),
+ 'fields' => array ( "'" . NS_FILE . "' AS namespace",
+ 'il_to AS title',
+ 'COUNT(*) AS value' ),
+ 'conds' => array ( 'img_name IS NULL' ),
+ 'options' => array ( 'GROUP BY' => 'il_to' ),
+ 'join_conds' => array ( 'image' =>
+ array ( 'LEFT JOIN',
+ array ( 'il_to = img_name' )
+ )
+ )
+ );
}
}
-
-/**
- * constructor
- */
-function wfSpecialWantedFiles() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new WantedFilesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
* @ingroup SpecialPage
*/
class WantedPagesPage extends WantedQueryPage {
- var $nlinks;
-
- function __construct( $inc = false, $nlinks = true ) {
- $this->setListoutput( $inc );
- $this->nlinks = $nlinks;
+ function __construct( $name = 'Wantedpages' ) {
+ parent::__construct( $name );
}
+
+ function execute( $par ) {
+ $inc = $this->including();
- function getName() {
- return 'Wantedpages';
+ if ( $inc ) {
+ @list( $limit, $nlinks ) = explode( '/', $par, 2 );
+ $this->limit = (int)$limit;
+ // FIXME: nlinks is ignored
+ $nlinks = $nlinks === 'nlinks';
+ $this->offset = 0;
+ } else {
+ $nlinks = true;
+ }
+ $this->setListOutput( $inc );
+ $this->shownavigation = !$inc;
+ parent::execute( $par );
}
- function getSQL() {
+ function getQueryInfo() {
global $wgWantedPagesThreshold;
$count = $wgWantedPagesThreshold - 1;
- $dbr = wfGetDB( DB_SLAVE );
- $pagelinks = $dbr->tableName( 'pagelinks' );
- $page = $dbr->tableName( 'page' );
- $sql = "SELECT 'Wantedpages' AS type,
- pl_namespace AS namespace,
- pl_title AS title,
- COUNT(*) AS value
- FROM $pagelinks
- LEFT JOIN $page AS pg1
- ON pl_namespace = pg1.page_namespace AND pl_title = pg1.page_title
- LEFT JOIN $page AS pg2
- ON pl_from = pg2.page_id
- WHERE pg1.page_namespace IS NULL
- AND pl_namespace NOT IN ( " . NS_USER . ", ". NS_USER_TALK . ")
- AND pg2.page_namespace != " . NS_MEDIAWIKI . "
- GROUP BY pl_namespace, pl_title
- HAVING COUNT(*) > $count";
-
- wfRunHooks( 'WantedPages::getSQL', array( &$this, &$sql ) );
- return $sql;
- }
-}
-
-/**
- * constructor
- */
-function wfSpecialWantedpages( $par = null, $specialPage ) {
- $inc = $specialPage->including();
-
- if ( $inc ) {
- @list( $limit, $nlinks ) = explode( '/', $par, 2 );
- $limit = (int)$limit;
- $nlinks = $nlinks === 'nlinks';
- $offset = 0;
- } else {
- list( $limit, $offset ) = wfCheckLimits();
- $nlinks = true;
- }
-
- $wpp = new WantedPagesPage( $inc, $nlinks );
-
- $wpp->doQuery( $offset, $limit, !$inc );
+ $query = array (
+ 'tables' => array ( 'pagelinks', 'pg1' => 'page',
+ 'pg2' => 'page' ),
+ 'fields' => array ( 'pl_namespace AS namespace',
+ 'pl_title AS title',
+ 'COUNT(*) AS value' ),
+ 'conds' => array ( 'pg1.page_namespace IS NULL',
+ "pl_namespace NOT IN ( '" . NS_USER .
+ "', '" . NS_USER_TALK . "' )",
+ "pg2.page_namespace != '" .
+ NS_MEDIAWIKI . "'" ),
+ 'options' => array ( 'HAVING' => "COUNT(*) > $count",
+ 'GROUP BY' => 'pl_namespace, pl_title' ),
+ 'join_conds' => array ( 'page AS pg1' => array (
+ 'LEFT JOIN', array (
+ 'pg1.page_namespace = pl_namespace',
+ 'pg1.page_title = pl_title' ) ),
+ 'page AS pg2' => array ( 'LEFT JOIN',
+ 'pg2.page_id = pl_from' ) )
+ );
+ // Replacement WantedPages::getSQL
+ wfRunHooks( 'WantedPages::getQueryInfo',
+ array( &$this, &$query ) );
+ return $query;
+ }
}
*/
class WantedTemplatesPage extends WantedQueryPage {
- function getName() {
- return 'Wantedtemplates';
+ function __construct( $name = 'Wantedtemplates' ) {
+ parent::__construct( $name );
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $templatelinks, $page ) = $dbr->tableNamesN( 'templatelinks', 'page' );
- $name = $dbr->addQuotes( $this->getName() );
- return
- "
- SELECT $name as type,
- tl_namespace as namespace,
- tl_title as title,
- COUNT(*) as value
- FROM $templatelinks LEFT JOIN
- $page ON tl_title = page_title AND tl_namespace = page_namespace
- WHERE page_title IS NULL AND tl_namespace = ". NS_TEMPLATE ."
- GROUP BY tl_namespace, tl_title
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'templatelinks', 'page' ),
+ 'fields' => array ( 'tl_namespace AS namespace',
+ 'tl_title AS title',
+ 'COUNT(*) AS value' ),
+ 'conds' => array ( 'page_title IS NULL',
+ 'tl_namespace' => NS_TEMPLATE ),
+ 'options' => array (
+ 'GROUP BY' => 'tl_namespace, tl_title' ),
+ 'join_conds' => array ( 'page' => array ( 'LEFT JOIN',
+ array ( 'page_namespace = tl_namespace',
+ 'page_title = tl_title' ) ) )
+ );
}
}
-
-/**
- * constructor
- */
-function wfSpecialWantedTemplates() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new WantedTemplatesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
class WithoutInterwikiPage extends PageQueryPage {
private $prefix = '';
- function getName() {
- return 'Withoutinterwiki';
+ function __construct( $name = 'Withoutinterwiki' ) {
+ parent::__construct( $name );
+ }
+
+ function execute( $par ) {
+ global $wgRequest;
+ $this->prefix = Title::capitalize( $wgRequest->getVal( 'prefix', $par ), NS_MAIN );
+ parent::execute( $par );
}
function getPageHeader() {
function sortDescending() {
return false;
}
+
+ function getOrderFields() {
+ return array( 'page_namespace', 'page_title' );
+ }
function isExpensive() {
return true;
return false;
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $langlinks ) = $dbr->tableNamesN( 'page', 'langlinks' );
- $prefix = $this->prefix ? 'AND page_title' . $dbr->buildLike( $this->prefix , $dbr->anyString() ) : '';
- return
- "SELECT 'Withoutinterwiki' AS type,
- page_namespace AS namespace,
- page_title AS title,
- page_title AS value
- FROM $page
- LEFT JOIN $langlinks
- ON ll_from = page_id
- WHERE ll_title IS NULL
- AND page_namespace=" . NS_MAIN . "
- AND page_is_redirect = 0
- {$prefix}";
- }
-
- function setPrefix( $prefix = '' ) {
- $this->prefix = $prefix;
+ function getQueryInfo() {
+ $query = array (
+ 'tables' => array ( 'page', 'langlinks' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value' ),
+ 'conds' => array ( 'll_title IS NULL',
+ 'page_namespace' => NS_MAIN,
+ 'page_is_redirect' => 0 ),
+ 'join_conds' => array ( 'langlinks' => array (
+ 'LEFT JOIN', 'll_from = page_id' ) )
+ );
+ if ( $this->prefix ) {
+ $dbr = wfGetDb( DB_SLAVE );
+ $query['conds'][] = 'page_title ' . $dbr->buildLike( $this->prefix, $dbr->anyString() );
+ }
+ return $query;
}
-
-}
-
-function wfSpecialWithoutinterwiki() {
- global $wgRequest;
- list( $limit, $offset ) = wfCheckLimits();
- // Only searching the mainspace anyway
- $prefix = Title::capitalize( $wgRequest->getVal( 'prefix' ), NS_MAIN );
- $wip = new WithoutInterwikiPage();
- $wip->setPrefix( $prefix );
- $wip->doQuery( $offset, $limit );
}
'pager-newer-n' => '{{PLURAL:$1|newer 1|newer $1}}',
'pager-older-n' => '{{PLURAL:$1|older 1|older $1}}',
'suppress' => 'Oversight',
+'querypage-disabled' => 'This special page is disabled for performance reasons.',
# Book sources
'booksources' => 'Book sources',
'pager-newer-n' => "This is part of the navigation message on the top and bottom of Special pages which are lists of things in date order, e.g. the User's contributions page. It is passed as the second argument of {{msg-mw|Viewprevnext}}. $1 is the number of items shown per page.",
'pager-older-n' => "This is part of the navigation message on the top and bottom of Special pages which are lists of things in date order, e.g. the User's contributions page. It is passed as the first argument of {{msg-mw|Viewprevnext}}. $1 is the number of items shown per page.",
'suppress' => '{{Identical|Oversight}}',
+'querypage-disabled' => "On special pages that use expensive database queries but are not cacheable, this message is displayed when 'miser mode' is on (i.e. no expensive queries allowed).",
# Book sources
'booksources' => 'Name of special page displayed in [[Special:SpecialPages]]',
'pager-newer-n',
'pager-older-n',
'suppress',
+ 'querypage-disabled',
),
'booksources' => array(
'booksources',