MediaWiki  master
QueryPage.php
Go to the documentation of this file.
1 <?php
24 namespace MediaWiki\SpecialPage;
25 
26 use Exception;
67 use MWDebug;
68 use MWException;
69 use Skin;
70 use stdClass;
77 use Xml;
78 
88 abstract 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 
274  protected function getSQL() {
275  wfDeprecated( __METHOD__, '1.39' );
276  throw new MWException( "Bug in a QueryPage: doesn't implement getQueryInfo() nor "
277  . "getQuery() properly" );
278  }
279 
288  protected function getOrderFields() {
289  return [ 'value' ];
290  }
291 
303  public function usesTimestamps() {
304  return false;
305  }
306 
313  protected function sortDescending() {
314  return true;
315  }
316 
337  public function isExpensive() {
338  return $this->getConfig()->get( MainConfigNames::DisableQueryPages );
339  }
340 
349  public function isCacheable() {
350  return true;
351  }
352 
360  public function isCached() {
361  return $this->isExpensive() && $this->getConfig()->get( MainConfigNames::MiserMode );
362  }
363 
370  public function isSyndicated() {
371  return true;
372  }
373 
383  abstract protected function formatResult( $skin, $result );
384 
391  protected function getPageHeader() {
392  return '';
393  }
394 
402  protected function showEmptyText() {
403  $this->getOutput()->addWikiMsg( 'specialpage-empty' );
404  }
405 
414  protected function linkParameters() {
415  return [];
416  }
417 
428  public function recache( $limit, $ignoreErrors = true ) {
429  if ( !$this->isCacheable() ) {
430  return 0;
431  }
432 
433  $fname = static::class . '::recache';
434  $dbw = $this->getDatabaseProvider()->getPrimaryDatabase();
435 
436  try {
437  // Do query
438  $res = $this->reallyDoQuery( $limit, false );
439  $num = false;
440  if ( $res ) {
441  $num = $res->numRows();
442  // Fetch results
443  $vals = [];
444  foreach ( $res as $i => $row ) {
445  if ( isset( $row->value ) ) {
446  if ( $this->usesTimestamps() ) {
447  $value = (int)wfTimestamp( TS_UNIX, $row->value );
448  } else {
449  $value = intval( $row->value ); // T16414
450  }
451  } else {
452  $value = $i;
453  }
454 
455  $vals[] = [
456  'qc_type' => $this->getName(),
457  'qc_namespace' => $row->namespace,
458  'qc_title' => $row->title,
459  'qc_value' => $value
460  ];
461  }
462 
463  $dbw->doAtomicSection(
464  $fname,
465  function ( IDatabase $dbw, $fname ) use ( $vals ) {
466  // Clear out any old cached data
467  $dbw->newDeleteQueryBuilder()
468  ->deleteFrom( 'querycache' )
469  ->where( [ 'qc_type' => $this->getName() ] )
470  ->caller( $fname )->execute();
471  // Update the querycache_info record for the page
472  $dbw->newInsertQueryBuilder()
473  ->insertInto( 'querycache_info' )
474  ->row( [ 'qci_type' => $this->getName(), 'qci_timestamp' => $dbw->timestamp() ] )
475  ->onDuplicateKeyUpdate()
476  ->uniqueIndexFields( [ 'qci_type' ] )
477  ->set( [ 'qci_timestamp' => $dbw->timestamp() ] )
478  ->caller( $fname )->execute();
479  }
480  );
481  // Save results into the querycache table on the primary DB
482  if ( count( $vals ) ) {
483  foreach ( array_chunk( $vals, 500 ) as $chunk ) {
484  $dbw->newInsertQueryBuilder()
485  ->insertInto( 'querycache' )
486  ->rows( $chunk )
487  ->caller( $fname )->execute();
488  }
489  }
490  }
491  } catch ( DBError $e ) {
492  if ( !$ignoreErrors ) {
493  throw $e; // report query error
494  }
495  $num = false; // set result to false to indicate error
496  }
497 
498  return $num;
499  }
500 
506  protected function getRecacheDB() {
507  return $this->getDBLoadBalancer()
508  ->getConnectionRef( ILoadBalancer::DB_REPLICA, 'vslow' );
509  }
510 
517  public function delete( LinkTarget $title ) {
518  if ( $this->isCached() ) {
519  $dbw = $this->getDatabaseProvider()->getPrimaryDatabase();
520  $dbw->newDeleteQueryBuilder()
521  ->deleteFrom( 'querycache' )
522  ->where( [
523  'qc_type' => $this->getName(),
524  'qc_namespace' => $title->getNamespace(),
525  'qc_title' => $title->getDBkey(),
526  ] )
527  ->caller( __METHOD__ )->execute();
528  }
529  }
530 
536  public function deleteAllCachedData() {
537  $fname = static::class . '::' . __FUNCTION__;
538  $dbw = $this->getDatabaseProvider()->getPrimaryDatabase();
539  $dbw->newDeleteQueryBuilder()
540  ->deleteFrom( 'querycache' )
541  ->where( [ 'qc_type' => $this->getName() ] )
542  ->caller( $fname )->execute();
543  $dbw->newDeleteQueryBuilder()
544  ->deleteFrom( 'querycachetwo' )
545  ->where( [ 'qcc_type' => $this->getName() ] )
546  ->caller( $fname )->execute();
547  $dbw->newDeleteQueryBuilder()
548  ->deleteFrom( 'querycache_info' )
549  ->where( [ 'qci_type' => $this->getName() ] )
550  ->caller( $fname )->execute();
551  }
552 
561  public function reallyDoQuery( $limit, $offset = false ) {
562  $fname = static::class . '::reallyDoQuery';
563  $dbr = $this->getRecacheDB();
564  $query = $this->getQueryInfo();
565  $order = $this->getOrderFields();
566 
567  if ( $this->sortDescending() ) {
568  foreach ( $order as &$field ) {
569  $field .= ' DESC';
570  }
571  }
572 
573  if ( is_array( $query ) ) {
574  $tables = isset( $query['tables'] ) ? (array)$query['tables'] : [];
575  $fields = isset( $query['fields'] ) ? (array)$query['fields'] : [];
576  $conds = isset( $query['conds'] ) ? (array)$query['conds'] : [];
577  $options = isset( $query['options'] ) ? (array)$query['options'] : [];
578  $join_conds = isset( $query['join_conds'] ) ? (array)$query['join_conds'] : [];
579 
580  if ( $order ) {
581  $options['ORDER BY'] = $order;
582  }
583 
584  if ( $limit !== false ) {
585  $options['LIMIT'] = intval( $limit );
586  }
587 
588  if ( $offset !== false ) {
589  $options['OFFSET'] = intval( $offset );
590  }
591 
592  $res = $dbr->select( $tables, $fields, $conds, $fname,
593  $options, $join_conds
594  );
595  } else {
596  // Old-fashioned raw SQL style, deprecated
598  $this,
599  __CLASS__,
600  'getSQL',
601  '1.39'
602  );
603  $sql = $this->getSQL();
604  $sql .= ' ORDER BY ' . implode( ', ', $order );
605  $sql = $dbr->limitResult( $sql, $limit, $offset );
606  // phpcs:ignore MediaWiki.Usage.DbrQueryUsage.DbrQueryFound
607  $res = $dbr->query( $sql, $fname );
608  }
609 
610  return $res;
611  }
612 
619  public function doQuery( $offset = false, $limit = false ) {
620  if ( $this->isCached() && $this->isCacheable() ) {
621  return $this->fetchFromCache( $limit, $offset );
622  } else {
623  return $this->reallyDoQuery( $limit, $offset );
624  }
625  }
626 
636  public function fetchFromCache( $limit, $offset = false ) {
637  $dbr = $this->getDatabaseProvider()->getReplicaDatabase();
638  $queryBuilder = $dbr->newSelectQueryBuilder()
639  ->select( [ 'qc_type', 'namespace' => 'qc_namespace', 'title' => 'qc_title', 'value' => 'qc_value' ] )
640  ->from( 'querycache' )
641  ->where( [ 'qc_type' => $this->getName() ] );
642 
643  if ( $limit !== false ) {
644  $queryBuilder->limit( intval( $limit ) );
645  }
646 
647  if ( $offset !== false ) {
648  $queryBuilder->offset( intval( $offset ) );
649  }
650 
651  $order = $this->getCacheOrderFields();
652  if ( $this->sortDescending() ) {
653  $queryBuilder->orderBy( $order, SelectQueryBuilder::SORT_DESC );
654  } else {
655  $queryBuilder->orderBy( $order );
656  }
657 
658  return $queryBuilder->caller( __METHOD__ )->fetchResultSet();
659  }
660 
668  protected function getCacheOrderFields() {
669  return [ 'value' ];
670  }
671 
675  public function getCachedTimestamp() {
676  if ( $this->cachedTimestamp === null ) {
677  $dbr = $this->getDatabaseProvider()->getReplicaDatabase();
678  $fname = static::class . '::getCachedTimestamp';
679  $this->cachedTimestamp = $dbr->newSelectQueryBuilder()
680  ->select( 'qci_timestamp' )
681  ->from( 'querycache_info' )
682  ->where( [ 'qci_type' => $this->getName() ] )
683  ->caller( $fname )->fetchField();
684  }
685  return $this->cachedTimestamp;
686  }
687 
700  protected function getLimitOffset() {
701  [ $limit, $offset ] = $this->getRequest()
702  ->getLimitOffsetForUser( $this->getUser() );
703  if ( $this->getConfig()->get( MainConfigNames::MiserMode ) ) {
704  $maxResults = $this->getMaxResults();
705  // Can't display more than max results on a page
706  $limit = min( $limit, $maxResults );
707  // Can't skip over more than the end of $maxResults
708  $offset = min( $offset, $maxResults + 1 );
709  }
710  return [ $limit, $offset ];
711  }
712 
721  protected function getDBLimit( $uiLimit, $uiOffset ) {
722  $maxResults = $this->getMaxResults();
723  if ( $this->getConfig()->get( MainConfigNames::MiserMode ) ) {
724  $limit = min( $uiLimit + 1, $maxResults - $uiOffset );
725  return max( $limit, 0 );
726  } else {
727  return $uiLimit + 1;
728  }
729  }
730 
741  protected function getMaxResults() {
742  // Max of 10000, unless we store more than 10000 in query cache.
743  return max( $this->getConfig()->get( MainConfigNames::QueryCacheLimit ), 10000 );
744  }
745 
752  public function execute( $par ) {
753  $this->checkPermissions();
754 
755  $this->setHeaders();
756  $this->outputHeader();
757 
758  $out = $this->getOutput();
759 
760  if ( $this->isCached() && !$this->isCacheable() ) {
761  $out->addWikiMsg( 'querypage-disabled' );
762  return;
763  }
764 
765  $out->setSyndicated( $this->isSyndicated() );
766 
767  if ( $this->limit == 0 && $this->offset == 0 ) {
768  [ $this->limit, $this->offset ] = $this->getLimitOffset();
769  }
770  $dbLimit = $this->getDBLimit( $this->limit, $this->offset );
771  // @todo Use doQuery()
772  if ( !$this->isCached() ) {
773  // select one extra row for navigation
774  $res = $this->reallyDoQuery( $dbLimit, $this->offset );
775  } else {
776  // Get the cached result, select one extra row for navigation
777  $res = $this->fetchFromCache( $dbLimit, $this->offset );
778  if ( !$this->listoutput ) {
779  // Fetch the timestamp of this update
780  $ts = $this->getCachedTimestamp();
781  $lang = $this->getLanguage();
782  $maxResults = $lang->formatNum( $this->getConfig()->get(
784 
785  if ( $ts ) {
786  $user = $this->getUser();
787  $updated = $lang->userTimeAndDate( $ts, $user );
788  $updateddate = $lang->userDate( $ts, $user );
789  $updatedtime = $lang->userTime( $ts, $user );
790  $out->addMeta( 'Data-Cache-Time', $ts );
791  $out->addJsConfigVars( 'dataCacheTime', $ts );
792  $out->addWikiMsg( 'perfcachedts', $updated, $updateddate, $updatedtime, $maxResults );
793  } else {
794  $out->addWikiMsg( 'perfcached', $maxResults );
795  }
796 
797  // If updates on this page have been disabled, let the user know
798  // that the data set won't be refreshed for now
799  $disabledQueryPages = self::getDisabledQueryPages( $this->getConfig() );
800  if ( isset( $disabledQueryPages[$this->getName()] ) ) {
801  $runMode = $disabledQueryPages[$this->getName()];
802  if ( $runMode === 'disabled' ) {
803  $out->wrapWikiMsg(
804  "<div class=\"mw-querypage-no-updates\">\n$1\n</div>",
805  'querypage-no-updates'
806  );
807  } else {
808  // Messages used here: querypage-updates-periodical
809  $out->wrapWikiMsg(
810  "<div class=\"mw-querypage-updates-" . $runMode . "\">\n$1\n</div>",
811  'querypage-updates-' . $runMode
812  );
813  }
814  }
815  }
816  }
817 
818  $this->numRows = $res->numRows();
819 
820  $dbr = $this->getRecacheDB();
821  $this->preprocessResults( $dbr, $res );
822 
823  $out->addHTML( Xml::openElement( 'div', [ 'class' => 'mw-spcontent' ] ) );
824 
825  // Top header and navigation
826  if ( $this->shownavigation ) {
827  $out->addHTML( $this->getPageHeader() );
828  if ( $this->numRows > 0 ) {
829  $out->addHTML( $this->msg( 'showingresultsinrange' )->numParams(
830  min( $this->numRows, $this->limit ), // do not show the one extra row, if exist
831  $this->offset + 1, ( min( $this->numRows, $this->limit ) + $this->offset ) )->parseAsBlock() );
832  // Disable the "next" link when we reach the end
833  $miserMaxResults = $this->getConfig()->get( MainConfigNames::MiserMode )
834  && ( $this->offset + $this->limit >= $this->getMaxResults() );
835  $atEnd = ( $this->numRows <= $this->limit ) || $miserMaxResults;
836  $paging = $this->buildPrevNextNavigation( $this->offset,
837  $this->limit, $this->linkParameters(), $atEnd, $par );
838  $out->addHTML( '<p>' . $paging . '</p>' );
839  } else {
840  // No results to show, so don't bother with "showing X of Y" etc.
841  // -- just let the user know and give up now
842  $this->showEmptyText();
843  $out->addHTML( Xml::closeElement( 'div' ) );
844  return;
845  }
846  }
847 
848  // The actual results; specialist subclasses will want to handle this
849  // with more than a straight list, so we hand them the info, plus
850  // an OutputPage, and let them get on with it
851  $this->outputResults( $out,
852  $this->getSkin(),
853  $dbr, // Should use IResultWrapper for this
854  $res,
855  min( $this->numRows, $this->limit ), // do not format the one extra row, if exist
856  $this->offset );
857 
858  // Repeat the paging links at the bottom
859  if ( $this->shownavigation ) {
860  // @phan-suppress-next-line PhanPossiblyUndeclaredVariable paging is set when used here
861  $out->addHTML( '<p>' . $paging . '</p>' );
862  }
863 
864  $out->addHTML( Xml::closeElement( 'div' ) );
865  }
866 
880  protected function outputResults( $out, $skin, $dbr, $res, $num, $offset ) {
881  if ( $num > 0 ) {
882  $html = [];
883  if ( !$this->listoutput ) {
884  $html[] = $this->openList( $offset );
885  }
886 
887  // $res might contain the whole 1,000 rows, so we read up to
888  // $num [should update this to use a Pager]
889  for ( $i = 0; $i < $num && $row = $res->fetchObject(); $i++ ) {
890  $line = $this->formatResult( $skin, $row );
891  if ( $line ) {
892  $html[] = $this->listoutput
893  ? $line
894  : "<li>{$line}</li>\n";
895  }
896  }
897 
898  if ( !$this->listoutput ) {
899  $html[] = $this->closeList();
900  }
901 
902  $html = $this->listoutput
903  ? $this->getContentLanguage()->listToText( $html )
904  : implode( '', $html );
905 
906  $out->addHTML( $html );
907  }
908  }
909 
914  protected function openList( $offset ) {
915  return "\n<ol start='" . ( $offset + 1 ) . "' class='special'>\n";
916  }
917 
921  protected function closeList() {
922  return "</ol>\n";
923  }
924 
931  protected function preprocessResults( $db, $res ) {
932  }
933 
946  protected function executeLBFromResultWrapper( IResultWrapper $res, $ns = null ) {
947  if ( !$res->numRows() ) {
948  return;
949  }
950 
951  $batch = $this->getLinkBatchFactory()->newLinkBatch();
952  foreach ( $res as $row ) {
953  $batch->add( $ns ?? (int)$row->namespace, $row->title );
954  }
955  $batch->execute();
956 
957  $res->seek( 0 );
958  }
959 
964  final protected function setDBLoadBalancer( ILoadBalancer $loadBalancer ) {
965  $this->loadBalancer = $loadBalancer;
966  }
967 
972  final protected function getDBLoadBalancer(): ILoadBalancer {
973  if ( $this->loadBalancer === null ) {
974  // Fallback if not provided
975  // TODO Change to wfWarn in a future release
976  $this->loadBalancer = MediaWikiServices::getInstance()->getDBLoadBalancer();
977  }
978  return $this->loadBalancer;
979  }
980 
985  final protected function setDatabaseProvider( IConnectionProvider $databaseProvider ) {
986  $this->databaseProvider = $databaseProvider;
987  }
988 
993  final protected function getDatabaseProvider(): IConnectionProvider {
994  if ( $this->databaseProvider === null ) {
995  $this->databaseProvider = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
996  }
997  return $this->databaseProvider;
998  }
999 }
1000 
1005 class_alias( QueryPage::class, 'QueryPage' );
getUser()
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:88
New debugger system that outputs a toolbar on page view.
Definition: MWDebug.php:40
static detectDeprecatedOverride( $instance, $class, $method, $version=false, $component=false, $callerOffset=2)
Show a warning if $method declared in $class is overridden in $instance.
Definition: MWDebug.php:262
MediaWiki exception.
Definition: MWException.php:33
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Definition: HookRunner.php:568
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.
Definition: OutputPage.php:93
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.
Definition: QueryPage.php:391
linkParameters()
If using extra form wheely-dealies, return a set of parameters here as an associative array.
Definition: QueryPage.php:414
bool $shownavigation
Whether to show prev/next links.
Definition: QueryPage.php:115
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.
Definition: QueryPage.php:288
preprocessResults( $db, $res)
Do any necessary preprocessing of the result object.
Definition: QueryPage.php:931
setDatabaseProvider(IConnectionProvider $databaseProvider)
Definition: QueryPage.php:985
getLimitOffset()
Returns limit and offset, as returned by $this->getRequest()->getLimitOffsetForUser().
Definition: QueryPage.php:700
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.
Definition: QueryPage.php:721
isCached()
Whether or not the output of the page in question is retrieved from the database cache.
Definition: QueryPage.php:360
execute( $par)
This is the actual workhorse.
Definition: QueryPage.php:752
setListoutput( $bool)
A mutator for $this->listoutput;.
Definition: QueryPage.php:231
executeLBFromResultWrapper(IResultWrapper $res, $ns=null)
Creates a new LinkBatch object, adds all pages from the passed result wrapper (MUST include title and...
Definition: QueryPage.php:946
getMaxResults()
Get max number of results we can return in miser mode.
Definition: QueryPage.php:741
isExpensive()
Should this query page only be updated offline on large wikis?
Definition: QueryPage.php:337
static getPages()
Get a list of query page classes and their associated special pages, for periodic updates.
Definition: QueryPage.php:136
fetchFromCache( $limit, $offset=false)
Fetch the query results from the query cache.
Definition: QueryPage.php:636
setDBLoadBalancer(ILoadBalancer $loadBalancer)
Definition: QueryPage.php:964
string null false $cachedTimestamp
Definition: QueryPage.php:110
deleteAllCachedData()
Remove all cached value This is needed when the page is no longer using the cache.
Definition: QueryPage.php:536
showEmptyText()
Outputs some kind of an informative message (via OutputPage) to let the user know that the query retu...
Definition: QueryPage.php:402
recache( $limit, $ignoreErrors=true)
Clear the cache and save new results.
Definition: QueryPage.php:428
doQuery( $offset=false, $limit=false)
Somewhat deprecated, you probably want to be using execute()
Definition: QueryPage.php:619
outputResults( $out, $skin, $dbr, $res, $num, $offset)
Format and output report results using the given information plus OutputPage.
Definition: QueryPage.php:880
getRecacheDB()
Get a DB connection to be used for slow recache queries.
Definition: QueryPage.php:506
static getDisabledQueryPages(Config $config)
Get a list of disabled query pages and their run mode.
Definition: QueryPage.php:207
sortDescending()
Override to sort by increasing values.
Definition: QueryPage.php:313
int $numRows
The number of rows returned by the query.
Definition: QueryPage.php:105
usesTimestamps()
Does this query return timestamps rather than integers in its 'value' field? If true,...
Definition: QueryPage.php:303
isSyndicated()
Sometimes we don't want to build rss / atom feeds.
Definition: QueryPage.php:370
getQueryInfo()
Subclasses return an SQL query here, formatted as an array with the following keys: tables => Table(s...
Definition: QueryPage.php:262
setLinkBatchFactory(LinkBatchFactory $linkBatchFactory)
Definition: QueryPage.php:185
formatResult( $skin, $result)
Formats the results of the query for display.
getCacheOrderFields()
Return the order fields for fetchFromCache.
Definition: QueryPage.php:668
isCacheable()
Is the output of this query cacheable? Non-cacheable expensive pages will be disabled in miser mode a...
Definition: QueryPage.php:349
getSQL()
For back-compat, subclasses may return a raw SQL query here, as a string.
Definition: QueryPage.php:274
reallyDoQuery( $limit, $offset=false)
Run the query and return the result.
Definition: QueryPage.php:561
Parent class for all special pages.
Definition: SpecialPage.php:65
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:60
Database error base class.
Definition: DBError.php:37
Build SELECT queries with a fluent interface.
Module of static functions for generating XML.
Definition: Xml.php:33
static closeElement( $element)
Shortcut to close an XML element.
Definition: Xml.php:124
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:115
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.
Definition: LinkTarget.php:30
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.
const DB_REPLICA
Request a replica DB connection.
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...