MediaWiki master
SpecialShortPages.php
Go to the documentation of this file.
1<?php
24namespace MediaWiki\Specials;
25
33use Skin;
34use stdClass;
38
46
47 private NamespaceInfo $namespaceInfo;
48
54 public function __construct(
55 NamespaceInfo $namespaceInfo,
56 IConnectionProvider $dbProvider,
57 LinkBatchFactory $linkBatchFactory
58 ) {
59 parent::__construct( 'Shortpages' );
60 $this->namespaceInfo = $namespaceInfo;
61 $this->setDatabaseProvider( $dbProvider );
62 $this->setLinkBatchFactory( $linkBatchFactory );
63 }
64
65 public function isSyndicated() {
66 return false;
67 }
68
69 public function getQueryInfo() {
70 $config = $this->getConfig();
71 $tables = [ 'page' ];
72 $conds = [
73 'page_namespace' => array_diff(
74 $this->namespaceInfo->getContentNamespaces(),
76 ),
77 'page_is_redirect' => 0
78 ];
79 $joinConds = [];
80 $options = [ 'USE INDEX' => [ 'page' => 'page_redirect_namespace_len' ] ];
81
82 // Allow extensions to modify the query
83 $this->getHookRunner()->onShortPagesQuery( $tables, $conds, $joinConds, $options );
84
85 return [
86 'tables' => $tables,
87 'fields' => [
88 'namespace' => 'page_namespace',
89 'title' => 'page_title',
90 'value' => 'page_len'
91 ],
92 'conds' => $conds,
93 'join_conds' => $joinConds,
94 'options' => $options
95 ];
96 }
97
98 public function reallyDoQuery( $limit, $offset = false ) {
99 $fname = static::class . '::reallyDoQuery';
100 $dbr = $this->getRecacheDB();
101 $query = $this->getQueryInfo();
102 $conds = isset( $query['conds'] ) ? (array)$query['conds'] : [];
103 $namespaces = $conds['page_namespace'];
104 unset( $conds['page_namespace'] );
105
106 if ( count( $namespaces ) === 1 || !$dbr->unionSupportsOrderAndLimit() ) {
107 return parent::reallyDoQuery( $limit, $offset );
108 }
109
110 // Optimization: Fix slow query on MySQL the case of multiple content namespaces,
111 // by rewriting this as a UNION of separate single namespace queries (T168010).
112 $sqb = $dbr->newSelectQueryBuilder()
113 ->select( isset( $query['fields'] ) ? (array)$query['fields'] : [] )
114 ->tables( isset( $query['tables'] ) ? (array)$query['tables'] : [] )
115 ->where( $conds )
116 ->options( isset( $query['options'] ) ? (array)$query['options'] : [] )
117 ->joinConds( isset( $query['join_conds'] ) ? (array)$query['join_conds'] : [] );
118 if ( $limit !== false ) {
119 if ( $offset !== false ) {
120 // We need to increase the limit by the offset rather than
121 // using the offset directly, otherwise it'll skip incorrectly
122 // in the subqueries.
123 $sqb->limit( intval( $limit ) + intval( $offset ) );
124 } else {
125 $sqb->limit( intval( $limit ) );
126 }
127 }
128
129 $order = $this->getOrderFields();
130 if ( $this->sortDescending() ) {
131 foreach ( $order as &$field ) {
132 $field .= ' DESC';
133 }
134 }
135
136 $uqb = $dbr->newUnionQueryBuilder()->all();
137 foreach ( $namespaces as $namespace ) {
138 $nsSqb = clone $sqb;
139 $nsSqb->orderBy( $order );
140 $nsSqb->andWhere( [ 'page_namespace' => $namespace ] );
141 $uqb->add( $nsSqb );
142 }
143
144 if ( $limit !== false ) {
145 $uqb->limit( intval( $limit ) );
146 }
147 if ( $offset !== false ) {
148 $uqb->offset( intval( $offset ) );
149 }
150 $orderBy = 'value';
151 if ( $this->sortDescending() ) {
152 $orderBy .= ' DESC';
153 }
154 $uqb->orderBy( $orderBy );
155 return $uqb->caller( $fname )->fetchResultSet();
156 }
157
158 protected function getOrderFields() {
159 return [ 'page_len' ];
160 }
161
166 public function preprocessResults( $db, $res ) {
167 $this->executeLBFromResultWrapper( $res );
168 }
169
170 protected function sortDescending() {
171 return false;
172 }
173
179 public function formatResult( $skin, $result ) {
180 $dm = $this->getLanguage()->getDirMark();
181
182 $title = Title::makeTitleSafe( $result->namespace, $result->title );
183 if ( !$title ) {
184 return Html::element( 'span', [ 'class' => 'mw-invalidtitle' ],
185 Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) );
186 }
187
188 $linkRenderer = $this->getLinkRenderer();
189 $hlink = $linkRenderer->makeKnownLink(
190 $title,
191 $this->msg( 'hist' )->text(),
192 [],
193 [ 'action' => 'history' ]
194 );
195 $hlinkInParentheses = $this->msg( 'parentheses' )->rawParams( $hlink )->escaped();
196
197 if ( $this->isCached() ) {
198 $plink = $linkRenderer->makeLink( $title );
199 $exists = $title->exists();
200 } else {
201 $plink = $linkRenderer->makeKnownLink( $title );
202 $exists = true;
203 }
204
205 $size = $this->msg( 'nbytes' )->numParams( $result->value )->escaped();
206
207 return $exists
208 ? "{$hlinkInParentheses} {$dm}{$plink} {$dm}[{$size}]"
209 : "<del>{$hlinkInParentheses} {$dm}{$plink} {$dm}[{$size}]</del>";
210 }
211
212 protected function getGroupName() {
213 return 'maintenance';
214 }
215}
216
221class_alias( SpecialShortPages::class, 'SpecialShortPages' );
This class is a collection of static functions that serve two purposes:
Definition Html.php:56
Some internal bits split of from Skin.php.
Definition Linker.php:65
A class containing constants representing the names of configuration variables.
const ShortPagesNamespaceExclusions
Name constant for the ShortPagesNamespaceExclusions setting, for use with Config::get()
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
setDatabaseProvider(IConnectionProvider $databaseProvider)
int $offset
The offset and limit in use, as passed to the query() function.
Definition QueryPage.php:93
isCached()
Whether or not the output of the page in question is retrieved from the database cache.
executeLBFromResultWrapper(IResultWrapper $res, $ns=null)
Creates a new LinkBatch object, adds all pages from the passed result wrapper (MUST include title and...
getRecacheDB()
Get a DB connection to be used for slow recache queries.
setLinkBatchFactory(LinkBatchFactory $linkBatchFactory)
getConfig()
Shortcut to get main config object.
getContext()
Gets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getLanguage()
Shortcut to get user's language.
SpecialShortpages extends QueryPage.
getQueryInfo()
Subclasses return an SQL query here, formatted as an array with the following keys: tables => Table(s...
__construct(NamespaceInfo $namespaceInfo, IConnectionProvider $dbProvider, LinkBatchFactory $linkBatchFactory)
reallyDoQuery( $limit, $offset=false)
Run the query and return the result.
getOrderFields()
Subclasses return an array of fields to order by here.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
sortDescending()
Override to sort by increasing values.
isSyndicated()
Sometimes we don't want to build rss / atom feeds.
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Represents a title within MediaWiki.
Definition Title.php:78
The base class for all skins.
Definition Skin.php:58
Provide primary and replica IDatabase connections.
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:36
Result wrapper for grabbing data queried from an IDatabase object.
element(SerializerNode $parent, SerializerNode $node, $contents)
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...