MediaWiki master
QueryPage.php
Go to the documentation of this file.
1<?php
24namespace MediaWiki\SpecialPage;
25
26use Exception;
68use Skin;
69use stdClass;
77
87abstract class QueryPage extends SpecialPage {
89 protected $listoutput = false;
90
92 protected $offset = 0;
93
95 protected $limit = 0;
96
104 protected $numRows;
105
109 protected $cachedTimestamp = null;
110
114 protected $shownavigation = true;
115
117 private $loadBalancer = null;
118
120 private $databaseProvider = null;
121
123 private $linkBatchFactory = null;
124
135 public static function getPages() {
136 static $qp = null;
137
138 if ( $qp === null ) {
139 $qp = [
140 [ SpecialAncientPages::class, 'Ancientpages' ],
141 [ SpecialBrokenRedirects::class, 'BrokenRedirects' ],
142 [ SpecialDeadendPages::class, 'Deadendpages' ],
143 [ SpecialDoubleRedirects::class, 'DoubleRedirects' ],
144 [ SpecialListDuplicatedFiles::class, 'ListDuplicatedFiles' ],
145 [ SpecialLinkSearch::class, 'LinkSearch' ],
146 [ SpecialListRedirects::class, 'Listredirects' ],
147 [ SpecialLonelyPages::class, 'Lonelypages' ],
148 [ SpecialLongPages::class, 'Longpages' ],
149 [ SpecialMediaStatistics::class, 'MediaStatistics', SpecialMediaStatistics::MAX_LIMIT ],
150 [ SpecialMIMESearch::class, 'MIMEsearch' ],
151 [ SpecialMostCategories::class, 'Mostcategories' ],
152 [ SpecialMostImages::class, 'Mostimages' ],
153 [ SpecialMostInterwikis::class, 'Mostinterwikis' ],
154 [ SpecialMostLinkedCategories::class, 'Mostlinkedcategories' ],
155 [ SpecialMostLinkedTemplates::class, 'Mostlinkedtemplates' ],
156 [ SpecialMostLinked::class, 'Mostlinked' ],
157 [ SpecialMostRevisions::class, 'Mostrevisions' ],
158 [ SpecialFewestRevisions::class, 'Fewestrevisions' ],
159 [ SpecialShortPages::class, 'Shortpages' ],
160 [ SpecialUncategorizedCategories::class, 'Uncategorizedcategories' ],
161 [ SpecialUncategorizedPages::class, 'Uncategorizedpages' ],
162 [ SpecialUncategorizedImages::class, 'Uncategorizedimages' ],
163 [ SpecialUncategorizedTemplates::class, 'Uncategorizedtemplates' ],
164 [ SpecialUnusedCategories::class, 'Unusedcategories' ],
165 [ SpecialUnusedImages::class, 'Unusedimages' ],
166 [ SpecialWantedCategories::class, 'Wantedcategories' ],
167 [ SpecialWantedFiles::class, 'Wantedfiles' ],
168 [ SpecialWantedPages::class, 'Wantedpages' ],
169 [ SpecialWantedTemplates::class, 'Wantedtemplates' ],
170 [ SpecialUnwatchedPages::class, 'Unwatchedpages' ],
171 [ SpecialUnusedTemplates::class, 'Unusedtemplates' ],
172 [ SpecialWithoutInterwiki::class, 'Withoutinterwiki' ],
173 ];
174 ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )->onWgQueryPages( $qp );
175 }
176
177 return $qp;
178 }
179
184 final protected function setLinkBatchFactory( LinkBatchFactory $linkBatchFactory ) {
185 $this->linkBatchFactory = $linkBatchFactory;
186 }
187
192 final protected function getLinkBatchFactory(): LinkBatchFactory {
193 if ( $this->linkBatchFactory === null ) {
194 // Fallback if not provided
195 // TODO Change to wfWarn in a future release
196 $this->linkBatchFactory = MediaWikiServices::getInstance()->getLinkBatchFactory();
197 }
198 return $this->linkBatchFactory;
199 }
200
206 public static function getDisabledQueryPages( Config $config ) {
207 $disableQueryPageUpdate = $config->get( MainConfigNames::DisableQueryPageUpdate );
208
209 if ( !is_array( $disableQueryPageUpdate ) ) {
210 return [];
211 }
212
213 $pages = [];
214 foreach ( $disableQueryPageUpdate as $name => $runMode ) {
215 if ( is_int( $name ) ) {
216 // The run mode may be omitted
217 $pages[$runMode] = 'disabled';
218 } else {
219 $pages[$name] = $runMode;
220 }
221 }
222 return $pages;
223 }
224
230 protected function setListoutput( $bool ) {
231 $this->listoutput = $bool;
232 }
233
257 abstract public function getQueryInfo();
258
267 protected function getOrderFields() {
268 return [ 'value' ];
269 }
270
282 public function usesTimestamps() {
283 return false;
284 }
285
292 protected function sortDescending() {
293 return true;
294 }
295
316 public function isExpensive() {
317 return $this->getConfig()->get( MainConfigNames::DisableQueryPages );
318 }
319
328 public function isCacheable() {
329 return true;
330 }
331
339 public function isCached() {
340 return $this->isExpensive() && $this->getConfig()->get( MainConfigNames::MiserMode );
341 }
342
349 public function isSyndicated() {
350 return true;
351 }
352
362 abstract protected function formatResult( $skin, $result );
363
370 protected function getPageHeader() {
371 return '';
372 }
373
381 protected function showEmptyText() {
382 $this->getOutput()->addWikiMsg( 'specialpage-empty' );
383 }
384
393 protected function linkParameters() {
394 return [];
395 }
396
407 public function recache( $limit, $unused = true ) {
408 if ( !$this->isCacheable() ) {
409 return 0;
410 }
411
412 $fname = static::class . '::recache';
413 $dbw = $this->getDatabaseProvider()->getPrimaryDatabase();
414
415 // Do query
416 $res = $this->reallyDoQuery( $limit, false );
417 $num = false;
418 if ( $res ) {
419 $num = $res->numRows();
420 // Fetch results
421 $vals = [];
422 foreach ( $res as $i => $row ) {
423 if ( isset( $row->value ) ) {
424 if ( $this->usesTimestamps() ) {
425 $value = (int)wfTimestamp( TS_UNIX, $row->value );
426 } else {
427 $value = intval( $row->value ); // T16414
428 }
429 } else {
430 $value = $i;
431 }
432
433 $vals[] = [
434 'qc_type' => $this->getName(),
435 'qc_namespace' => $row->namespace,
436 'qc_title' => $row->title,
437 'qc_value' => $value
438 ];
439 }
440
441 $dbw->doAtomicSection(
442 $fname,
443 function ( IDatabase $dbw, $fname ) use ( $vals ) {
444 // Clear out any old cached data
446 ->deleteFrom( 'querycache' )
447 ->where( [ 'qc_type' => $this->getName() ] )
448 ->caller( $fname )->execute();
449 // Update the querycache_info record for the page
451 ->insertInto( 'querycache_info' )
452 ->row( [ 'qci_type' => $this->getName(), 'qci_timestamp' => $dbw->timestamp() ] )
453 ->onDuplicateKeyUpdate()
454 ->uniqueIndexFields( [ 'qci_type' ] )
455 ->set( [ 'qci_timestamp' => $dbw->timestamp() ] )
456 ->caller( $fname )->execute();
457 }
458 );
459 // Save results into the querycache table on the primary DB
460 if ( count( $vals ) ) {
461 foreach ( array_chunk( $vals, 500 ) as $chunk ) {
463 ->insertInto( 'querycache' )
464 ->rows( $chunk )
465 ->caller( $fname )->execute();
466 }
467 }
468 }
469
470 return $num;
471 }
472
478 protected function getRecacheDB() {
479 return $this->getDBLoadBalancer()
480 ->getConnection( ILoadBalancer::DB_REPLICA, 'vslow' );
481 }
482
489 public function delete( LinkTarget $title ) {
490 if ( $this->isCached() ) {
491 $dbw = $this->getDatabaseProvider()->getPrimaryDatabase();
492 $dbw->newDeleteQueryBuilder()
493 ->deleteFrom( 'querycache' )
494 ->where( [
495 'qc_type' => $this->getName(),
496 'qc_namespace' => $title->getNamespace(),
497 'qc_title' => $title->getDBkey(),
498 ] )
499 ->caller( __METHOD__ )->execute();
500 }
501 }
502
508 public function deleteAllCachedData() {
509 $fname = static::class . '::' . __FUNCTION__;
510 $dbw = $this->getDatabaseProvider()->getPrimaryDatabase();
511 $dbw->newDeleteQueryBuilder()
512 ->deleteFrom( 'querycache' )
513 ->where( [ 'qc_type' => $this->getName() ] )
514 ->caller( $fname )->execute();
515 $dbw->newDeleteQueryBuilder()
516 ->deleteFrom( 'querycachetwo' )
517 ->where( [ 'qcc_type' => $this->getName() ] )
518 ->caller( $fname )->execute();
519 $dbw->newDeleteQueryBuilder()
520 ->deleteFrom( 'querycache_info' )
521 ->where( [ 'qci_type' => $this->getName() ] )
522 ->caller( $fname )->execute();
523 }
524
533 public function reallyDoQuery( $limit, $offset = false ) {
534 $fname = static::class . '::reallyDoQuery';
535 $dbr = $this->getRecacheDB();
536 $query = $this->getQueryInfo();
537 $order = $this->getOrderFields();
538
539 if ( $this->sortDescending() ) {
540 foreach ( $order as &$field ) {
541 $field .= ' DESC';
542 }
543 }
544
545 $tables = isset( $query['tables'] ) ? (array)$query['tables'] : [];
546 $fields = isset( $query['fields'] ) ? (array)$query['fields'] : [];
547 $conds = isset( $query['conds'] ) ? (array)$query['conds'] : [];
548 $options = isset( $query['options'] ) ? (array)$query['options'] : [];
549 $join_conds = isset( $query['join_conds'] ) ? (array)$query['join_conds'] : [];
550
551 $queryBuilder = $dbr->newSelectQueryBuilder()
552 ->tables( $tables )
553 ->fields( $fields )
554 ->conds( $conds )
555 ->caller( $fname )
556 ->options( $options )
557 ->joinConds( $join_conds );
558 if ( $order ) {
559 $queryBuilder->orderBy( $order );
560 }
561
562 if ( $limit !== false ) {
563 $queryBuilder->limit( intval( $limit ) );
564 }
565
566 if ( $offset !== false ) {
567 $queryBuilder->offset( intval( $offset ) );
568 }
569
570 return $queryBuilder->fetchResultSet();
571 }
572
579 public function doQuery( $offset = false, $limit = false ) {
580 if ( $this->isCached() && $this->isCacheable() ) {
581 return $this->fetchFromCache( $limit, $offset );
582 } else {
583 return $this->reallyDoQuery( $limit, $offset );
584 }
585 }
586
596 public function fetchFromCache( $limit, $offset = false ) {
597 $dbr = $this->getDatabaseProvider()->getReplicaDatabase();
598 $queryBuilder = $dbr->newSelectQueryBuilder()
599 ->select( [ 'qc_type', 'namespace' => 'qc_namespace', 'title' => 'qc_title', 'value' => 'qc_value' ] )
600 ->from( 'querycache' )
601 ->where( [ 'qc_type' => $this->getName() ] );
602
603 if ( $limit !== false ) {
604 $queryBuilder->limit( intval( $limit ) );
605 }
606
607 if ( $offset !== false ) {
608 $queryBuilder->offset( intval( $offset ) );
609 }
610
611 $order = $this->getCacheOrderFields();
612 if ( $this->sortDescending() ) {
613 $queryBuilder->orderBy( $order, SelectQueryBuilder::SORT_DESC );
614 } else {
615 $queryBuilder->orderBy( $order );
616 }
617
618 return $queryBuilder->caller( __METHOD__ )->fetchResultSet();
619 }
620
628 protected function getCacheOrderFields() {
629 return [ 'value' ];
630 }
631
635 public function getCachedTimestamp() {
636 if ( $this->cachedTimestamp === null ) {
637 $dbr = $this->getDatabaseProvider()->getReplicaDatabase();
638 $fname = static::class . '::getCachedTimestamp';
639 $this->cachedTimestamp = $dbr->newSelectQueryBuilder()
640 ->select( 'qci_timestamp' )
641 ->from( 'querycache_info' )
642 ->where( [ 'qci_type' => $this->getName() ] )
643 ->caller( $fname )->fetchField();
644 }
645 return $this->cachedTimestamp;
646 }
647
660 protected function getLimitOffset() {
661 [ $limit, $offset ] = $this->getRequest()
662 ->getLimitOffsetForUser( $this->getUser() );
663 if ( $this->getConfig()->get( MainConfigNames::MiserMode ) ) {
664 $maxResults = $this->getMaxResults();
665 // Can't display more than max results on a page
666 $limit = min( $limit, $maxResults );
667 // Can't skip over more than the end of $maxResults
668 $offset = min( $offset, $maxResults + 1 );
669 }
670 return [ $limit, $offset ];
671 }
672
681 protected function getDBLimit( $uiLimit, $uiOffset ) {
682 $maxResults = $this->getMaxResults();
683 if ( $this->getConfig()->get( MainConfigNames::MiserMode ) ) {
684 $limit = min( $uiLimit + 1, $maxResults - $uiOffset );
685 return max( $limit, 0 );
686 } else {
687 return $uiLimit + 1;
688 }
689 }
690
701 protected function getMaxResults() {
702 // Max of 10000, unless we store more than 10000 in query cache.
703 return max( $this->getConfig()->get( MainConfigNames::QueryCacheLimit ), 10000 );
704 }
705
712 public function execute( $par ) {
713 $this->checkPermissions();
714
715 $this->setHeaders();
716 $this->outputHeader();
717
718 $out = $this->getOutput();
719
720 if ( $this->isCached() && !$this->isCacheable() ) {
721 $out->addWikiMsg( 'querypage-disabled' );
722 return;
723 }
724
725 $out->setSyndicated( $this->isSyndicated() );
726
727 if ( $this->limit == 0 && $this->offset == 0 ) {
728 [ $this->limit, $this->offset ] = $this->getLimitOffset();
729 }
730 $dbLimit = $this->getDBLimit( $this->limit, $this->offset );
731 // @todo Use doQuery()
732 if ( !$this->isCached() ) {
733 // select one extra row for navigation
734 $res = $this->reallyDoQuery( $dbLimit, $this->offset );
735 } else {
736 // Get the cached result, select one extra row for navigation
737 $res = $this->fetchFromCache( $dbLimit, $this->offset );
738 if ( !$this->listoutput ) {
739 // Fetch the timestamp of this update
740 $ts = $this->getCachedTimestamp();
741 $lang = $this->getLanguage();
742 $maxResults = $lang->formatNum( $this->getConfig()->get(
744
745 if ( $ts ) {
746 $user = $this->getUser();
747 $updated = $lang->userTimeAndDate( $ts, $user );
748 $updateddate = $lang->userDate( $ts, $user );
749 $updatedtime = $lang->userTime( $ts, $user );
750 $out->addMeta( 'Data-Cache-Time', $ts );
751 $out->addJsConfigVars( 'dataCacheTime', $ts );
752 $out->addWikiMsg( 'perfcachedts', $updated, $updateddate, $updatedtime, $maxResults );
753 } else {
754 $out->addWikiMsg( 'perfcached', $maxResults );
755 }
756
757 // If updates on this page have been disabled, let the user know
758 // that the data set won't be refreshed for now
759 $disabledQueryPages = self::getDisabledQueryPages( $this->getConfig() );
760 if ( isset( $disabledQueryPages[$this->getName()] ) ) {
761 $runMode = $disabledQueryPages[$this->getName()];
762 if ( $runMode === 'disabled' ) {
763 $out->wrapWikiMsg(
764 "<div class=\"mw-querypage-no-updates\">\n$1\n</div>",
765 'querypage-no-updates'
766 );
767 } else {
768 // Messages used here: querypage-updates-periodical
769 $out->wrapWikiMsg(
770 "<div class=\"mw-querypage-updates-" . $runMode . "\">\n$1\n</div>",
771 'querypage-updates-' . $runMode
772 );
773 }
774 }
775 }
776 }
777
778 $this->numRows = $res->numRows();
779
780 $dbr = $this->getRecacheDB();
781 $this->preprocessResults( $dbr, $res );
782
783 $out->addHTML( Xml::openElement( 'div', [ 'class' => 'mw-spcontent' ] ) );
784
785 // Top header and navigation
786 if ( $this->shownavigation ) {
787 $out->addHTML( $this->getPageHeader() );
788 if ( $this->numRows > 0 ) {
789 $out->addHTML( $this->msg( 'showingresultsinrange' )->numParams(
790 min( $this->numRows, $this->limit ), // do not show the one extra row, if exist
791 $this->offset + 1, ( min( $this->numRows, $this->limit ) + $this->offset ) )->parseAsBlock() );
792 // Disable the "next" link when we reach the end
793 $miserMaxResults = $this->getConfig()->get( MainConfigNames::MiserMode )
794 && ( $this->offset + $this->limit >= $this->getMaxResults() );
795 $atEnd = ( $this->numRows <= $this->limit ) || $miserMaxResults;
796 $paging = $this->buildPrevNextNavigation( $this->offset,
797 $this->limit, $this->linkParameters(), $atEnd, $par );
798 $out->addHTML( '<p>' . $paging . '</p>' );
799 } else {
800 // No results to show, so don't bother with "showing X of Y" etc.
801 // -- just let the user know and give up now
802 $this->showEmptyText();
803 $out->addHTML( Xml::closeElement( 'div' ) );
804 return;
805 }
806 }
807
808 // The actual results; specialist subclasses will want to handle this
809 // with more than a straight list, so we hand them the info, plus
810 // an OutputPage, and let them get on with it
811 $this->outputResults( $out,
812 $this->getSkin(),
813 $dbr, // Should use IResultWrapper for this
814 $res,
815 min( $this->numRows, $this->limit ), // do not format the one extra row, if exist
816 $this->offset );
817
818 // Repeat the paging links at the bottom
819 if ( $this->shownavigation ) {
820 // @phan-suppress-next-line PhanPossiblyUndeclaredVariable paging is set when used here
821 $out->addHTML( '<p>' . $paging . '</p>' );
822 }
823
824 $out->addHTML( Xml::closeElement( 'div' ) );
825 }
826
840 protected function outputResults( $out, $skin, $dbr, $res, $num, $offset ) {
841 if ( $num > 0 ) {
842 $html = [];
843 if ( !$this->listoutput ) {
844 $html[] = $this->openList( $offset );
845 }
846
847 // $res might contain the whole 1,000 rows, so we read up to
848 // $num [should update this to use a Pager]
849 // phpcs:ignore Generic.CodeAnalysis.AssignmentInCondition.Found
850 for ( $i = 0; $i < $num && $row = $res->fetchObject(); $i++ ) {
851 $line = $this->formatResult( $skin, $row );
852 if ( $line ) {
853 $html[] = $this->listoutput
854 ? $line
855 : "<li>{$line}</li>\n";
856 }
857 }
858
859 if ( !$this->listoutput ) {
860 $html[] = $this->closeList();
861 }
862
863 $html = $this->listoutput
864 ? $this->getContentLanguage()->listToText( $html )
865 : implode( '', $html );
866
867 $out->addHTML( $html );
868 }
869 }
870
875 protected function openList( $offset ) {
876 return "\n<ol start='" . ( $offset + 1 ) . "' class='special'>\n";
877 }
878
882 protected function closeList() {
883 return "</ol>\n";
884 }
885
892 protected function preprocessResults( $db, $res ) {
893 }
894
907 protected function executeLBFromResultWrapper( IResultWrapper $res, $ns = null ) {
908 if ( !$res->numRows() ) {
909 return;
910 }
911
912 $batch = $this->getLinkBatchFactory()->newLinkBatch();
913 foreach ( $res as $row ) {
914 $batch->add( $ns ?? (int)$row->namespace, $row->title );
915 }
916 $batch->execute();
917
918 $res->seek( 0 );
919 }
920
926 final protected function setDBLoadBalancer( ILoadBalancer $loadBalancer ) {
927 $this->loadBalancer = $loadBalancer;
928 }
929
935 final protected function getDBLoadBalancer(): ILoadBalancer {
936 if ( $this->loadBalancer === null ) {
937 // Fallback if not provided
938 // TODO Change to wfWarn in a future release
939 $this->loadBalancer = MediaWikiServices::getInstance()->getDBLoadBalancer();
940 }
941 return $this->loadBalancer;
942 }
943
948 final protected function setDatabaseProvider( IConnectionProvider $databaseProvider ) {
949 $this->databaseProvider = $databaseProvider;
950 }
951
956 final protected function getDatabaseProvider(): IConnectionProvider {
957 if ( $this->databaseProvider === null ) {
958 $this->databaseProvider = MediaWikiServices::getInstance()->getConnectionProvider();
959 }
960 return $this->databaseProvider;
961 }
962}
963
965class_alias( QueryPage::class, 'QueryPage' );
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:81
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition Html.php:240
static closeElement( $element)
Returns "</$element>".
Definition Html.php:304
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:87
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:89
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:92
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...
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.
recache( $limit, $unused=true)
Clear the cache and save new results.
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...
reallyDoQuery( $limit, $offset=false)
Run the query and return the result.
Parent class for all special pages.
Implements Special:Ancientpages.
List of redirects to non-existent pages.
List of pages that contain no links to other pages.
List of redirects to another redirecting page.
List articles with the fewest revisions.
Special:LinkSearch to search the external-links table.
List all files where the current version is a duplicate of the current version of another file.
Lists all the redirecting pages on the wiki.
List of articles with no article linking to them, thus being lonely.
Implements Special:Longpages.
Search the database for files of the requested MIME type, comparing this with the 'img_major_mime' an...
List of pages that have the highest category count.
List of the most used images.
List of pages that have the highest interwiki count.
List of categories with the most pages in them.
List of templates with a large number of transclusion links, i.e.
List of pages ordered by the number of pages linking to them.
Implements Special:Mostrevisions.
List of the shortest pages in the database.
List of file pages which haven't been categorised.
List of all uncategorised pages in the Template namespace.
List of pages that are not on anyone's watchlist.
List of the most linked non-existent files.
List of the most-linked pages that do not exist.
List of pages without any language links.
Module of static functions for generating XML.
Definition Xml.php:37
The base class for all skins.
Definition Skin.php:65
Database error base class.
Definition DBError.php:36
Build SELECT queries with a fluent interface.
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.
Interface to a relational database.
Definition IDatabase.php:48
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.
A database connection without write operations.
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...