MediaWiki master
QueryPage.php
Go to the documentation of this file.
1<?php
24namespace MediaWiki\SpecialPage;
25
26use Exception;
27use LogicException;
68use MWDebug;
69use Skin;
70use stdClass;
77use Xml;
78
88abstract class QueryPage extends SpecialPage {
90 protected $listoutput = false;
91
93 protected $offset = 0;
94
96 protected $limit = 0;
97
105 protected $numRows;
106
110 protected $cachedTimestamp = null;
111
115 protected $shownavigation = true;
116
118 private $loadBalancer = null;
119
121 private $databaseProvider = null;
122
124 private $linkBatchFactory = null;
125
136 public static function getPages() {
137 static $qp = null;
138
139 if ( $qp === null ) {
140 $qp = [
141 [ SpecialAncientPages::class, 'Ancientpages' ],
142 [ SpecialBrokenRedirects::class, 'BrokenRedirects' ],
143 [ SpecialDeadendPages::class, 'Deadendpages' ],
144 [ SpecialDoubleRedirects::class, 'DoubleRedirects' ],
145 [ SpecialListDuplicatedFiles::class, 'ListDuplicatedFiles' ],
146 [ SpecialLinkSearch::class, 'LinkSearch' ],
147 [ SpecialListRedirects::class, 'Listredirects' ],
148 [ SpecialLonelyPages::class, 'Lonelypages' ],
149 [ SpecialLongPages::class, 'Longpages' ],
150 [ SpecialMediaStatistics::class, 'MediaStatistics', SpecialMediaStatistics::MAX_LIMIT ],
151 [ SpecialMIMESearch::class, 'MIMEsearch' ],
152 [ SpecialMostCategories::class, 'Mostcategories' ],
153 [ SpecialMostImages::class, 'Mostimages' ],
154 [ SpecialMostInterwikis::class, 'Mostinterwikis' ],
155 [ SpecialMostLinkedCategories::class, 'Mostlinkedcategories' ],
156 [ SpecialMostLinkedTemplates::class, 'Mostlinkedtemplates' ],
157 [ SpecialMostLinked::class, 'Mostlinked' ],
158 [ SpecialMostRevisions::class, 'Mostrevisions' ],
159 [ SpecialFewestRevisions::class, 'Fewestrevisions' ],
160 [ SpecialShortPages::class, 'Shortpages' ],
161 [ SpecialUncategorizedCategories::class, 'Uncategorizedcategories' ],
162 [ SpecialUncategorizedPages::class, 'Uncategorizedpages' ],
163 [ SpecialUncategorizedImages::class, 'Uncategorizedimages' ],
164 [ SpecialUncategorizedTemplates::class, 'Uncategorizedtemplates' ],
165 [ SpecialUnusedCategories::class, 'Unusedcategories' ],
166 [ SpecialUnusedImages::class, 'Unusedimages' ],
167 [ SpecialWantedCategories::class, 'Wantedcategories' ],
168 [ SpecialWantedFiles::class, 'Wantedfiles' ],
169 [ SpecialWantedPages::class, 'Wantedpages' ],
170 [ SpecialWantedTemplates::class, 'Wantedtemplates' ],
171 [ SpecialUnwatchedPages::class, 'Unwatchedpages' ],
172 [ SpecialUnusedTemplates::class, 'Unusedtemplates' ],
173 [ SpecialWithoutInterwiki::class, 'Withoutinterwiki' ],
174 ];
175 ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )->onWgQueryPages( $qp );
176 }
177
178 return $qp;
179 }
180
185 final protected function setLinkBatchFactory( LinkBatchFactory $linkBatchFactory ) {
186 $this->linkBatchFactory = $linkBatchFactory;
187 }
188
193 final protected function getLinkBatchFactory(): LinkBatchFactory {
194 if ( $this->linkBatchFactory === null ) {
195 // Fallback if not provided
196 // TODO Change to wfWarn in a future release
197 $this->linkBatchFactory = MediaWikiServices::getInstance()->getLinkBatchFactory();
198 }
199 return $this->linkBatchFactory;
200 }
201
207 public static function getDisabledQueryPages( Config $config ) {
208 $disableQueryPageUpdate = $config->get( MainConfigNames::DisableQueryPageUpdate );
209
210 if ( !is_array( $disableQueryPageUpdate ) ) {
211 return [];
212 }
213
214 $pages = [];
215 foreach ( $disableQueryPageUpdate as $name => $runMode ) {
216 if ( is_int( $name ) ) {
217 // The run mode may be omitted
218 $pages[$runMode] = 'disabled';
219 } else {
220 $pages[$name] = $runMode;
221 }
222 }
223 return $pages;
224 }
225
231 protected function setListoutput( $bool ) {
232 $this->listoutput = $bool;
233 }
234
262 public function getQueryInfo() {
263 // @phan-suppress-next-line PhanTypeMismatchReturnProbablyReal null needed for b/c checks
264 return null;
265 }
266
273 protected function getSQL() {
274 wfDeprecated( __METHOD__, '1.39' );
275 throw new LogicException( "Bug in a QueryPage: doesn't implement getQueryInfo() nor "
276 . "getQuery() properly" );
277 }
278
287 protected function getOrderFields() {
288 return [ 'value' ];
289 }
290
302 public function usesTimestamps() {
303 return false;
304 }
305
312 protected function sortDescending() {
313 return true;
314 }
315
336 public function isExpensive() {
337 return $this->getConfig()->get( MainConfigNames::DisableQueryPages );
338 }
339
348 public function isCacheable() {
349 return true;
350 }
351
359 public function isCached() {
360 return $this->isExpensive() && $this->getConfig()->get( MainConfigNames::MiserMode );
361 }
362
369 public function isSyndicated() {
370 return true;
371 }
372
382 abstract protected function formatResult( $skin, $result );
383
390 protected function getPageHeader() {
391 return '';
392 }
393
401 protected function showEmptyText() {
402 $this->getOutput()->addWikiMsg( 'specialpage-empty' );
403 }
404
413 protected function linkParameters() {
414 return [];
415 }
416
427 public function recache( $limit, $ignoreErrors = true ) {
428 if ( !$this->isCacheable() ) {
429 return 0;
430 }
431
432 $fname = static::class . '::recache';
433 $dbw = $this->getDatabaseProvider()->getPrimaryDatabase();
434
435 try {
436 // Do query
437 $res = $this->reallyDoQuery( $limit, false );
438 $num = false;
439 if ( $res ) {
440 $num = $res->numRows();
441 // Fetch results
442 $vals = [];
443 foreach ( $res as $i => $row ) {
444 if ( isset( $row->value ) ) {
445 if ( $this->usesTimestamps() ) {
446 $value = (int)wfTimestamp( TS_UNIX, $row->value );
447 } else {
448 $value = intval( $row->value ); // T16414
449 }
450 } else {
451 $value = $i;
452 }
453
454 $vals[] = [
455 'qc_type' => $this->getName(),
456 'qc_namespace' => $row->namespace,
457 'qc_title' => $row->title,
458 'qc_value' => $value
459 ];
460 }
461
462 $dbw->doAtomicSection(
463 $fname,
464 function ( IDatabase $dbw, $fname ) use ( $vals ) {
465 // Clear out any old cached data
467 ->deleteFrom( 'querycache' )
468 ->where( [ 'qc_type' => $this->getName() ] )
469 ->caller( $fname )->execute();
470 // Update the querycache_info record for the page
472 ->insertInto( 'querycache_info' )
473 ->row( [ 'qci_type' => $this->getName(), 'qci_timestamp' => $dbw->timestamp() ] )
474 ->onDuplicateKeyUpdate()
475 ->uniqueIndexFields( [ 'qci_type' ] )
476 ->set( [ 'qci_timestamp' => $dbw->timestamp() ] )
477 ->caller( $fname )->execute();
478 }
479 );
480 // Save results into the querycache table on the primary DB
481 if ( count( $vals ) ) {
482 foreach ( array_chunk( $vals, 500 ) as $chunk ) {
484 ->insertInto( 'querycache' )
485 ->rows( $chunk )
486 ->caller( $fname )->execute();
487 }
488 }
489 }
490 } catch ( DBError $e ) {
491 if ( !$ignoreErrors ) {
492 throw $e; // report query error
493 }
494 $num = false; // set result to false to indicate error
495 }
496
497 return $num;
498 }
499
505 protected function getRecacheDB() {
506 return $this->getDBLoadBalancer()
507 ->getConnectionRef( ILoadBalancer::DB_REPLICA, 'vslow' );
508 }
509
516 public function delete( LinkTarget $title ) {
517 if ( $this->isCached() ) {
518 $dbw = $this->getDatabaseProvider()->getPrimaryDatabase();
519 $dbw->newDeleteQueryBuilder()
520 ->deleteFrom( 'querycache' )
521 ->where( [
522 'qc_type' => $this->getName(),
523 'qc_namespace' => $title->getNamespace(),
524 'qc_title' => $title->getDBkey(),
525 ] )
526 ->caller( __METHOD__ )->execute();
527 }
528 }
529
535 public function deleteAllCachedData() {
536 $fname = static::class . '::' . __FUNCTION__;
537 $dbw = $this->getDatabaseProvider()->getPrimaryDatabase();
538 $dbw->newDeleteQueryBuilder()
539 ->deleteFrom( 'querycache' )
540 ->where( [ 'qc_type' => $this->getName() ] )
541 ->caller( $fname )->execute();
542 $dbw->newDeleteQueryBuilder()
543 ->deleteFrom( 'querycachetwo' )
544 ->where( [ 'qcc_type' => $this->getName() ] )
545 ->caller( $fname )->execute();
546 $dbw->newDeleteQueryBuilder()
547 ->deleteFrom( 'querycache_info' )
548 ->where( [ 'qci_type' => $this->getName() ] )
549 ->caller( $fname )->execute();
550 }
551
560 public function reallyDoQuery( $limit, $offset = false ) {
561 $fname = static::class . '::reallyDoQuery';
562 $dbr = $this->getRecacheDB();
563 $query = $this->getQueryInfo();
564 $order = $this->getOrderFields();
565
566 if ( $this->sortDescending() ) {
567 foreach ( $order as &$field ) {
568 $field .= ' DESC';
569 }
570 }
571
572 if ( is_array( $query ) ) {
573 $tables = isset( $query['tables'] ) ? (array)$query['tables'] : [];
574 $fields = isset( $query['fields'] ) ? (array)$query['fields'] : [];
575 $conds = isset( $query['conds'] ) ? (array)$query['conds'] : [];
576 $options = isset( $query['options'] ) ? (array)$query['options'] : [];
577 $join_conds = isset( $query['join_conds'] ) ? (array)$query['join_conds'] : [];
578
579 if ( $order ) {
580 $options['ORDER BY'] = $order;
581 }
582
583 if ( $limit !== false ) {
584 $options['LIMIT'] = intval( $limit );
585 }
586
587 if ( $offset !== false ) {
588 $options['OFFSET'] = intval( $offset );
589 }
590
591 $res = $dbr->select( $tables, $fields, $conds, $fname,
592 $options, $join_conds
593 );
594 } else {
595 // Old-fashioned raw SQL style, deprecated
596 MWDebug::detectDeprecatedOverride(
597 $this,
598 __CLASS__,
599 'getSQL',
600 '1.39'
601 );
602 $sql = $this->getSQL();
603 $sql .= ' ORDER BY ' . implode( ', ', $order );
604 $sql = $dbr->limitResult( $sql, $limit, $offset );
605 // phpcs:ignore MediaWiki.Usage.DbrQueryUsage.DbrQueryFound
606 $res = $dbr->query( $sql, $fname );
607 }
608
609 return $res;
610 }
611
618 public function doQuery( $offset = false, $limit = false ) {
619 if ( $this->isCached() && $this->isCacheable() ) {
620 return $this->fetchFromCache( $limit, $offset );
621 } else {
622 return $this->reallyDoQuery( $limit, $offset );
623 }
624 }
625
635 public function fetchFromCache( $limit, $offset = false ) {
636 $dbr = $this->getDatabaseProvider()->getReplicaDatabase();
637 $queryBuilder = $dbr->newSelectQueryBuilder()
638 ->select( [ 'qc_type', 'namespace' => 'qc_namespace', 'title' => 'qc_title', 'value' => 'qc_value' ] )
639 ->from( 'querycache' )
640 ->where( [ 'qc_type' => $this->getName() ] );
641
642 if ( $limit !== false ) {
643 $queryBuilder->limit( intval( $limit ) );
644 }
645
646 if ( $offset !== false ) {
647 $queryBuilder->offset( intval( $offset ) );
648 }
649
650 $order = $this->getCacheOrderFields();
651 if ( $this->sortDescending() ) {
652 $queryBuilder->orderBy( $order, SelectQueryBuilder::SORT_DESC );
653 } else {
654 $queryBuilder->orderBy( $order );
655 }
656
657 return $queryBuilder->caller( __METHOD__ )->fetchResultSet();
658 }
659
667 protected function getCacheOrderFields() {
668 return [ 'value' ];
669 }
670
674 public function getCachedTimestamp() {
675 if ( $this->cachedTimestamp === null ) {
676 $dbr = $this->getDatabaseProvider()->getReplicaDatabase();
677 $fname = static::class . '::getCachedTimestamp';
678 $this->cachedTimestamp = $dbr->newSelectQueryBuilder()
679 ->select( 'qci_timestamp' )
680 ->from( 'querycache_info' )
681 ->where( [ 'qci_type' => $this->getName() ] )
682 ->caller( $fname )->fetchField();
683 }
684 return $this->cachedTimestamp;
685 }
686
699 protected function getLimitOffset() {
700 [ $limit, $offset ] = $this->getRequest()
701 ->getLimitOffsetForUser( $this->getUser() );
702 if ( $this->getConfig()->get( MainConfigNames::MiserMode ) ) {
703 $maxResults = $this->getMaxResults();
704 // Can't display more than max results on a page
705 $limit = min( $limit, $maxResults );
706 // Can't skip over more than the end of $maxResults
707 $offset = min( $offset, $maxResults + 1 );
708 }
709 return [ $limit, $offset ];
710 }
711
720 protected function getDBLimit( $uiLimit, $uiOffset ) {
721 $maxResults = $this->getMaxResults();
722 if ( $this->getConfig()->get( MainConfigNames::MiserMode ) ) {
723 $limit = min( $uiLimit + 1, $maxResults - $uiOffset );
724 return max( $limit, 0 );
725 } else {
726 return $uiLimit + 1;
727 }
728 }
729
740 protected function getMaxResults() {
741 // Max of 10000, unless we store more than 10000 in query cache.
742 return max( $this->getConfig()->get( MainConfigNames::QueryCacheLimit ), 10000 );
743 }
744
751 public function execute( $par ) {
752 $this->checkPermissions();
753
754 $this->setHeaders();
755 $this->outputHeader();
756
757 $out = $this->getOutput();
758
759 if ( $this->isCached() && !$this->isCacheable() ) {
760 $out->addWikiMsg( 'querypage-disabled' );
761 return;
762 }
763
764 $out->setSyndicated( $this->isSyndicated() );
765
766 if ( $this->limit == 0 && $this->offset == 0 ) {
767 [ $this->limit, $this->offset ] = $this->getLimitOffset();
768 }
769 $dbLimit = $this->getDBLimit( $this->limit, $this->offset );
770 // @todo Use doQuery()
771 if ( !$this->isCached() ) {
772 // select one extra row for navigation
773 $res = $this->reallyDoQuery( $dbLimit, $this->offset );
774 } else {
775 // Get the cached result, select one extra row for navigation
776 $res = $this->fetchFromCache( $dbLimit, $this->offset );
777 if ( !$this->listoutput ) {
778 // Fetch the timestamp of this update
779 $ts = $this->getCachedTimestamp();
780 $lang = $this->getLanguage();
781 $maxResults = $lang->formatNum( $this->getConfig()->get(
783
784 if ( $ts ) {
785 $user = $this->getUser();
786 $updated = $lang->userTimeAndDate( $ts, $user );
787 $updateddate = $lang->userDate( $ts, $user );
788 $updatedtime = $lang->userTime( $ts, $user );
789 $out->addMeta( 'Data-Cache-Time', $ts );
790 $out->addJsConfigVars( 'dataCacheTime', $ts );
791 $out->addWikiMsg( 'perfcachedts', $updated, $updateddate, $updatedtime, $maxResults );
792 } else {
793 $out->addWikiMsg( 'perfcached', $maxResults );
794 }
795
796 // If updates on this page have been disabled, let the user know
797 // that the data set won't be refreshed for now
798 $disabledQueryPages = self::getDisabledQueryPages( $this->getConfig() );
799 if ( isset( $disabledQueryPages[$this->getName()] ) ) {
800 $runMode = $disabledQueryPages[$this->getName()];
801 if ( $runMode === 'disabled' ) {
802 $out->wrapWikiMsg(
803 "<div class=\"mw-querypage-no-updates\">\n$1\n</div>",
804 'querypage-no-updates'
805 );
806 } else {
807 // Messages used here: querypage-updates-periodical
808 $out->wrapWikiMsg(
809 "<div class=\"mw-querypage-updates-" . $runMode . "\">\n$1\n</div>",
810 'querypage-updates-' . $runMode
811 );
812 }
813 }
814 }
815 }
816
817 $this->numRows = $res->numRows();
818
819 $dbr = $this->getRecacheDB();
820 $this->preprocessResults( $dbr, $res );
821
822 $out->addHTML( Xml::openElement( 'div', [ 'class' => 'mw-spcontent' ] ) );
823
824 // Top header and navigation
825 if ( $this->shownavigation ) {
826 $out->addHTML( $this->getPageHeader() );
827 if ( $this->numRows > 0 ) {
828 $out->addHTML( $this->msg( 'showingresultsinrange' )->numParams(
829 min( $this->numRows, $this->limit ), // do not show the one extra row, if exist
830 $this->offset + 1, ( min( $this->numRows, $this->limit ) + $this->offset ) )->parseAsBlock() );
831 // Disable the "next" link when we reach the end
832 $miserMaxResults = $this->getConfig()->get( MainConfigNames::MiserMode )
833 && ( $this->offset + $this->limit >= $this->getMaxResults() );
834 $atEnd = ( $this->numRows <= $this->limit ) || $miserMaxResults;
835 $paging = $this->buildPrevNextNavigation( $this->offset,
836 $this->limit, $this->linkParameters(), $atEnd, $par );
837 $out->addHTML( '<p>' . $paging . '</p>' );
838 } else {
839 // No results to show, so don't bother with "showing X of Y" etc.
840 // -- just let the user know and give up now
841 $this->showEmptyText();
842 $out->addHTML( Xml::closeElement( 'div' ) );
843 return;
844 }
845 }
846
847 // The actual results; specialist subclasses will want to handle this
848 // with more than a straight list, so we hand them the info, plus
849 // an OutputPage, and let them get on with it
850 $this->outputResults( $out,
851 $this->getSkin(),
852 $dbr, // Should use IResultWrapper for this
853 $res,
854 min( $this->numRows, $this->limit ), // do not format the one extra row, if exist
855 $this->offset );
856
857 // Repeat the paging links at the bottom
858 if ( $this->shownavigation ) {
859 // @phan-suppress-next-line PhanPossiblyUndeclaredVariable paging is set when used here
860 $out->addHTML( '<p>' . $paging . '</p>' );
861 }
862
863 $out->addHTML( Xml::closeElement( 'div' ) );
864 }
865
879 protected function outputResults( $out, $skin, $dbr, $res, $num, $offset ) {
880 if ( $num > 0 ) {
881 $html = [];
882 if ( !$this->listoutput ) {
883 $html[] = $this->openList( $offset );
884 }
885
886 // $res might contain the whole 1,000 rows, so we read up to
887 // $num [should update this to use a Pager]
888 for ( $i = 0; $i < $num && $row = $res->fetchObject(); $i++ ) {
889 $line = $this->formatResult( $skin, $row );
890 if ( $line ) {
891 $html[] = $this->listoutput
892 ? $line
893 : "<li>{$line}</li>\n";
894 }
895 }
896
897 if ( !$this->listoutput ) {
898 $html[] = $this->closeList();
899 }
900
901 $html = $this->listoutput
902 ? $this->getContentLanguage()->listToText( $html )
903 : implode( '', $html );
904
905 $out->addHTML( $html );
906 }
907 }
908
913 protected function openList( $offset ) {
914 return "\n<ol start='" . ( $offset + 1 ) . "' class='special'>\n";
915 }
916
920 protected function closeList() {
921 return "</ol>\n";
922 }
923
930 protected function preprocessResults( $db, $res ) {
931 }
932
945 protected function executeLBFromResultWrapper( IResultWrapper $res, $ns = null ) {
946 if ( !$res->numRows() ) {
947 return;
948 }
949
950 $batch = $this->getLinkBatchFactory()->newLinkBatch();
951 foreach ( $res as $row ) {
952 $batch->add( $ns ?? (int)$row->namespace, $row->title );
953 }
954 $batch->execute();
955
956 $res->seek( 0 );
957 }
958
963 final protected function setDBLoadBalancer( ILoadBalancer $loadBalancer ) {
964 $this->loadBalancer = $loadBalancer;
965 }
966
971 final protected function getDBLoadBalancer(): ILoadBalancer {
972 if ( $this->loadBalancer === null ) {
973 // Fallback if not provided
974 // TODO Change to wfWarn in a future release
975 $this->loadBalancer = MediaWikiServices::getInstance()->getDBLoadBalancer();
976 }
977 return $this->loadBalancer;
978 }
979
984 final protected function setDatabaseProvider( IConnectionProvider $databaseProvider ) {
985 $this->databaseProvider = $databaseProvider;
986 }
987
992 final protected function getDatabaseProvider(): IConnectionProvider {
993 if ( $this->databaseProvider === null ) {
994 $this->databaseProvider = MediaWikiServices::getInstance()->getConnectionProvider();
995 }
996 return $this->databaseProvider;
997 }
998}
999
1004class_alias( QueryPage::class, 'QueryPage' );
getUser()
getRequest()
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:81
Debug toolbar.
Definition MWDebug.php:42
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
A class containing constants representing the names of configuration variables.
const DisableQueryPages
Name constant for the DisableQueryPages setting, for use with Config::get()
const QueryCacheLimit
Name constant for the QueryCacheLimit setting, for use with Config::get()
const MiserMode
Name constant for the MiserMode setting, for use with Config::get()
const DisableQueryPageUpdate
Name constant for the DisableQueryPageUpdate setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
This is one of the Core classes and should be read at least once by any new developers.
This is a class for doing query pages; since they're almost all the same, we factor out some of the f...
Definition QueryPage.php:88
getPageHeader()
The content returned by this function will be output before any result.
linkParameters()
If using extra form wheely-dealies, return a set of parameters here as an associative array.
bool $shownavigation
Whether to show prev/next links.
bool $listoutput
Whether or not we want plain listoutput rather than an ordered list.
Definition QueryPage.php:90
getOrderFields()
Subclasses return an array of fields to order by here.
preprocessResults( $db, $res)
Do any necessary preprocessing of the result object.
setDatabaseProvider(IConnectionProvider $databaseProvider)
getLimitOffset()
Returns limit and offset, as returned by $this->getRequest()->getLimitOffsetForUser().
int $offset
The offset and limit in use, as passed to the query() function.
Definition QueryPage.php:93
getDBLimit( $uiLimit, $uiOffset)
What is limit to fetch from DB.
isCached()
Whether or not the output of the page in question is retrieved from the database cache.
execute( $par)
This is the actual workhorse.
setListoutput( $bool)
A mutator for $this->listoutput;.
executeLBFromResultWrapper(IResultWrapper $res, $ns=null)
Creates a new LinkBatch object, adds all pages from the passed result wrapper (MUST include title and...
getMaxResults()
Get max number of results we can return in miser mode.
isExpensive()
Should this query page only be updated offline on large wikis?
static getPages()
Get a list of query page classes and their associated special pages, for periodic updates.
fetchFromCache( $limit, $offset=false)
Fetch the query results from the query cache.
setDBLoadBalancer(ILoadBalancer $loadBalancer)
string null false $cachedTimestamp
deleteAllCachedData()
Remove all cached value This is needed when the page is no longer using the cache.
showEmptyText()
Outputs some kind of an informative message (via OutputPage) to let the user know that the query retu...
recache( $limit, $ignoreErrors=true)
Clear the cache and save new results.
doQuery( $offset=false, $limit=false)
Somewhat deprecated, you probably want to be using execute()
outputResults( $out, $skin, $dbr, $res, $num, $offset)
Format and output report results using the given information plus OutputPage.
getRecacheDB()
Get a DB connection to be used for slow recache queries.
static getDisabledQueryPages(Config $config)
Get a list of disabled query pages and their run mode.
sortDescending()
Override to sort by increasing values.
int $numRows
The number of rows returned by the query.
usesTimestamps()
Does this query return timestamps rather than integers in its 'value' field? If true,...
isSyndicated()
Sometimes we don't want to build rss / atom feeds.
getQueryInfo()
Subclasses return an SQL query here, formatted as an array with the following keys: tables => Table(s...
setLinkBatchFactory(LinkBatchFactory $linkBatchFactory)
formatResult( $skin, $result)
Formats the results of the query for display.
getCacheOrderFields()
Return the order fields for fetchFromCache.
isCacheable()
Is the output of this query cacheable? Non-cacheable expensive pages will be disabled in miser mode a...
getSQL()
For back-compat, subclasses may return a raw SQL query here, as a string.
reallyDoQuery( $limit, $offset=false)
Run the query and return the result.
Parent class for all special pages.
Implements Special:Ancientpages.
A special page listing redirects to non existent page.
A special page that list pages that contain no link to other pages.
A special page listing redirects to redirecting page.
Special page for listing the articles with the fewest revisions.
Special:LinkSearch to search the external-links table.
Special:ListDuplicatedFiles Lists all files where the current version is a duplicate of the current v...
Special:Listredirects - Lists all the redirects on the wiki.
A special page looking for articles with no article linking to them, thus being lonely.
Searches the database for files of the requested MIME type, comparing this with the 'img_major_mime' ...
A special page that list pages that have highest category count.
A special page that lists most used images.
A special page that listed pages that have highest interwiki count.
A querypage to show categories ordered in descending order by the pages in them.
Special page lists templates with a large number of transclusion links, i.e.
A special page to show pages ordered by the number of pages linking to them.
SpecialShortpages extends QueryPage.
A special page that lists uncategorized categories.
Special page lists images which haven't been categorised.
A special page looking for page without any category.
Special page lists all uncategorised pages in the template namespace.
A special page that lists unused images.
A special page that lists unused templates.
A special page that displays a list of pages that are not on anyone's watchlist.
A querypage to list the most wanted categories - implements Special:Wantedcategories.
Querypage that lists the most wanted files.
A special page that lists most linked pages that does not exist.
A querypage to list the most wanted templates.
Special page lists pages without language links.
The base class for all skins.
Definition Skin.php:58
Database error base class.
Definition DBError.php:36
Build SELECT queries with a fluent interface.
Module of static functions for generating XML.
Definition Xml.php:33
Interface for configuration instances.
Definition Config.php:32
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
Represents the target of a wiki link.
Provide primary and replica IDatabase connections.
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:36
newDeleteQueryBuilder()
Get an DeleteQueryBuilder bound to this connection.
newInsertQueryBuilder()
Get an InsertQueryBuilder bound to this connection.
This class is a delegate to ILBFactory for a given database cluster.
Result wrapper for grabbing data queried from an IDatabase object.
numRows()
Get the number of rows in a result object.
seek( $pos)
Change the position of the cursor in a result object.
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by ConvertibleTimestamp to the format used for ins...