MediaWiki REL1_37
SpecialAllPages.php
Go to the documentation of this file.
1<?php
26
34
40 protected $maxPerPage = 345;
41
47 protected $nsfromMsg = 'allpagesfrom';
48
51
54
59 public function __construct(
62 ) {
63 parent::__construct( 'Allpages' );
64 // This class is extended and therefore falls back to global state - T265309
65 $services = MediaWikiServices::getInstance();
66 $this->loadBalancer = $loadBalancer ?? $services->getDBLoadBalancer();
67 $this->searchEngineFactory = $searchEngineFactory ?? $services->getSearchEngineFactory();
68 }
69
75 public function execute( $par ) {
76 $request = $this->getRequest();
77 $out = $this->getOutput();
78
79 $this->setHeaders();
80 $this->outputHeader();
81 $out->allowClickjacking();
82
83 # GET values
84 $from = $request->getVal( 'from', null );
85 $to = $request->getVal( 'to', null );
86 $namespace = $request->getInt( 'namespace' );
87
88 $miserMode = (bool)$this->getConfig()->get( 'MiserMode' );
89
90 // Redirects filter is disabled in MiserMode
91 $hideredirects = $request->getBool( 'hideredirects', false ) && !$miserMode;
92
93 $namespaces = $this->getLanguage()->getNamespaces();
94
95 $out->setPageTitle(
96 ( $namespace > 0 && array_key_exists( $namespace, $namespaces ) ) ?
97 $this->msg( 'allinnamespace', str_replace( '_', ' ', $namespaces[$namespace] ) ) :
98 $this->msg( 'allarticles' )
99 );
100 $out->addModuleStyles( 'mediawiki.special' );
101
102 if ( $par !== null ) {
103 $this->showChunk( $namespace, $par, $to, $hideredirects );
104 } elseif ( $from !== null && $to === null ) {
105 $this->showChunk( $namespace, $from, $to, $hideredirects );
106 } else {
107 $this->showToplevel( $namespace, $from, $to, $hideredirects );
108 }
109 }
110
119 protected function outputHTMLForm( $namespace = NS_MAIN,
120 $from = '', $to = '', $hideRedirects = false
121 ) {
122 $miserMode = (bool)$this->getConfig()->get( 'MiserMode' );
123 $formDescriptor = [
124 'from' => [
125 'type' => 'text',
126 'name' => 'from',
127 'id' => 'nsfrom',
128 'size' => 30,
129 'label-message' => 'allpagesfrom',
130 'default' => str_replace( '_', ' ', $from ),
131 ],
132 'to' => [
133 'type' => 'text',
134 'name' => 'to',
135 'id' => 'nsto',
136 'size' => 30,
137 'label-message' => 'allpagesto',
138 'default' => str_replace( '_', ' ', $to ),
139 ],
140 'namespace' => [
141 'type' => 'namespaceselect',
142 'name' => 'namespace',
143 'id' => 'namespace',
144 'label-message' => 'namespace',
145 'all' => null,
146 'default' => $namespace,
147 ],
148 'hideredirects' => [
149 'type' => 'check',
150 'name' => 'hideredirects',
151 'id' => 'hidredirects',
152 'label-message' => 'allpages-hide-redirects',
153 'value' => $hideRedirects,
154 ],
155 ];
156
157 if ( $miserMode ) {
158 unset( $formDescriptor['hideredirects'] );
159 }
160
161 $context = new DerivativeContext( $this->getContext() );
162 $context->setTitle( $this->getPageTitle() ); // Remove subpage
163 $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $context );
164 $htmlForm
165 ->setMethod( 'get' )
166 ->setWrapperLegendMsg( 'allpages' )
167 ->setSubmitTextMsg( 'allpagessubmit' )
168 ->prepareForm()
169 ->displayForm( false );
170 }
171
178 private function showToplevel(
179 $namespace = NS_MAIN, $from = '', $to = '', $hideredirects = false
180 ) {
181 $from = Title::makeTitleSafe( $namespace, $from );
182 $to = Title::makeTitleSafe( $namespace, $to );
183 $from = ( $from && $from->isLocal() ) ? $from->getDBkey() : null;
184 $to = ( $to && $to->isLocal() ) ? $to->getDBkey() : null;
185
186 $this->showChunk( $namespace, $from, $to, $hideredirects );
187 }
188
195 private function showChunk(
196 $namespace = NS_MAIN, $from = false, $to = false, $hideredirects = false
197 ) {
198 $output = $this->getOutput();
199
200 $fromList = $this->getNamespaceKeyAndText( $namespace, $from );
201 $toList = $this->getNamespaceKeyAndText( $namespace, $to );
202 $namespaces = $this->getContext()->getLanguage()->getNamespaces();
203 $n = 0;
204 $prevTitle = null;
205
206 if ( !$fromList || !$toList ) {
207 $out = $this->msg( 'allpagesbadtitle' )->parseAsBlock();
208 } elseif ( !array_key_exists( $namespace, $namespaces ) ) {
209 // Show errormessage and reset to NS_MAIN
210 $out = $this->msg( 'allpages-bad-ns', $namespace )->parse();
211 $namespace = NS_MAIN;
212 } else {
213 list( $namespace, $fromKey, $from ) = $fromList;
214 list( , $toKey, $to ) = $toList;
215
216 $dbr = $this->loadBalancer->getConnectionRef( ILoadBalancer::DB_REPLICA );
217 $filterConds = [ 'page_namespace' => $namespace ];
218 if ( $hideredirects ) {
219 $filterConds['page_is_redirect'] = 0;
220 }
221
222 $conds = $filterConds;
223 $conds[] = 'page_title >= ' . $dbr->addQuotes( $fromKey );
224 if ( $toKey !== "" ) {
225 $conds[] = 'page_title <= ' . $dbr->addQuotes( $toKey );
226 }
227 $res = $dbr->select( 'page',
228 [ 'page_namespace', 'page_title', 'page_is_redirect', 'page_id' ],
229 $conds,
230 __METHOD__,
231 [
232 'ORDER BY' => 'page_title',
233 'LIMIT' => $this->maxPerPage + 1,
234 'USE INDEX' => 'page_name_title',
235 ]
236 );
237
239 if ( $res->numRows() > 0 ) {
240 $out = Html::openElement( 'ul', [ 'class' => 'mw-allpages-chunk' ] );
241
242 while ( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
243 $t = Title::newFromRow( $s );
244 if ( $t ) {
245 $out .= '<li' .
246 ( $s->page_is_redirect ? ' class="allpagesredirect"' : '' ) .
247 '>' .
249 "</li>\n";
250 } else {
251 $out .= '<li>[[' . htmlspecialchars( $s->page_title ) . "]]</li>\n";
252 }
253 $n++;
254 }
255 $out .= Html::closeElement( 'ul' );
256
257 if ( $res->numRows() > 2 ) {
258 // Only apply CSS column styles if there's more than 2 entries.
259 // Otherwise, rendering is broken as "mw-allpages-body"'s CSS column count is 3.
260 $out = Html::rawElement( 'div', [ 'class' => 'mw-allpages-body' ], $out );
261 }
262 } else {
263 $out = '';
264 }
265
266 if ( $fromKey !== '' && !$this->including() ) {
267 # Get the first title from previous chunk
268 $prevConds = $filterConds;
269 $prevConds[] = 'page_title < ' . $dbr->addQuotes( $fromKey );
270 $prevKey = $dbr->selectField(
271 'page',
272 'page_title',
273 $prevConds,
274 __METHOD__,
275 [ 'ORDER BY' => 'page_title DESC', 'OFFSET' => $this->maxPerPage - 1 ]
276 );
277
278 if ( $prevKey === false ) {
279 # The previous chunk is not complete, need to link to the very first title
280 # available in the database
281 $prevKey = $dbr->selectField(
282 'page',
283 'page_title',
284 $prevConds,
285 __METHOD__,
286 [ 'ORDER BY' => 'page_title' ]
287 );
288 }
289
290 if ( $prevKey !== false ) {
291 $prevTitle = Title::makeTitle( $namespace, $prevKey );
292 }
293 }
294 }
295
296 if ( $this->including() ) {
297 $output->addHTML( $out );
298 return;
299 }
300
301 $navLinks = [];
302 $self = $this->getPageTitle();
303
305 // Generate a "previous page" link if needed
306 if ( $prevTitle ) {
307 $query = [ 'from' => $prevTitle->getText() ];
308
309 if ( $namespace ) {
310 $query['namespace'] = $namespace;
311 }
312
313 if ( $hideredirects ) {
314 $query['hideredirects'] = $hideredirects;
315 }
316
317 $navLinks[] = $linkRenderer->makeKnownLink(
318 $self,
319 $this->msg( 'prevpage', $prevTitle->getText() )->text(),
320 [],
321 $query
322 );
323
324 }
325
326 // Generate a "next page" link if needed
327 if ( $n == $this->maxPerPage && $s = $res->fetchObject() ) {
328 # $s is the first link of the next chunk
329 $t = Title::makeTitle( $namespace, $s->page_title );
330 $query = [ 'from' => $t->getText() ];
331
332 if ( $namespace ) {
333 $query['namespace'] = $namespace;
334 }
335
336 if ( $hideredirects ) {
337 $query['hideredirects'] = $hideredirects;
338 }
339
340 $navLinks[] = $linkRenderer->makeKnownLink(
341 $self,
342 $this->msg( 'nextpage', $t->getText() )->text(),
343 [],
344 $query
345 );
346 }
347
348 $this->outputHTMLForm( $namespace, $from, $to, $hideredirects );
349
350 if ( count( $navLinks ) ) {
351 // Add pagination links
352 $pagination = Html::rawElement( 'div',
353 [ 'class' => 'mw-allpages-nav' ],
354 $this->getLanguage()->pipeList( $navLinks )
355 );
356
357 $output->addHTML( $pagination );
358 $out .= Html::element( 'hr' ) . $pagination; // Footer
359 }
360
361 $output->addHTML( $out );
362 }
363
369 protected function getNamespaceKeyAndText( $ns, $text ) {
370 if ( $text == '' ) {
371 # shortcut for common case
372 return [ $ns, '', '' ];
373 }
374
375 $t = Title::makeTitleSafe( $ns, $text );
376 if ( $t && $t->isLocal() ) {
377 return [ $t->getNamespace(), $t->getDBkey(), $t->getText() ];
378 } elseif ( $t ) {
379 return null;
380 }
381
382 # try again, in case the problem was an empty pagename
383 $text = preg_replace( '/(#|$)/', 'X$1', $text );
384 $t = Title::makeTitleSafe( $ns, $text );
385 if ( $t && $t->isLocal() ) {
386 return [ $t->getNamespace(), '', '' ];
387 } else {
388 return null;
389 }
390 }
391
400 public function prefixSearchSubpages( $search, $limit, $offset ) {
401 return $this->prefixSearchString( $search, $limit, $offset, $this->searchEngineFactory );
402 }
403
404 protected function getGroupName() {
405 return 'pages';
406 }
407}
const NS_MAIN
Definition Defines.php:64
An IContextSource implementation which will inherit context from another source but allow individual ...
Shortcut to construct an includable special page.
makeKnownLink( $target, $text=null, array $extraAttribs=[], array $query=[])
makeLink( $target, $text=null, array $extraAttribs=[], array $query=[])
MediaWikiServices is the service locator for the application scope of MediaWiki.
Factory class for SearchEngine.
Implements Special:Allpages.
int $maxPerPage
Maximum number of pages to show on single subpage.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
showToplevel( $namespace=NS_MAIN, $from='', $to='', $hideredirects=false)
execute( $par)
Entry point : initialise variables and call subfunctions.
ILoadBalancer $loadBalancer
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
showChunk( $namespace=NS_MAIN, $from=false, $to=false, $hideredirects=false)
string $nsfromMsg
Determines, which message describes the input field 'nsfrom'.
__construct(ILoadBalancer $loadBalancer=null, SearchEngineFactory $searchEngineFactory=null)
outputHTMLForm( $namespace=NS_MAIN, $from='', $to='', $hideRedirects=false)
Outputs the HTMLForm used on this page.
SearchEngineFactory $searchEngineFactory
getNamespaceKeyAndText( $ns, $text)
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getOutput()
Get the OutputPage being used for this instance.
getContext()
Gets the context this SpecialPage is executed in.
LinkRenderer null $linkRenderer
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getConfig()
Shortcut to get main config object.
getRequest()
Get the WebRequest being used for this instance.
prefixSearchString( $search, $limit, $offset, SearchEngineFactory $searchEngineFactory=null)
Perform a regular substring search for prefixSearchSubpages.
getPageTitle( $subpage=false)
Get a self-referential title object.
getLanguage()
Shortcut to get user's language.
including( $x=null)
Whether the special page is being evaluated via transclusion.
Database cluster connection, tracking, load balancing, and transaction manager interface.
foreach( $mmfl['setupFiles'] as $fileName) if($queue) if(empty( $mmfl['quiet'])) $s