MediaWiki  master
SpecialAllPages.php
Go to the documentation of this file.
1 <?php
26 
34 
40  protected $maxPerPage = 345;
41 
47  protected $nsfromMsg = 'allpagesfrom';
48 
50  private $loadBalancer;
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 
238  $linkRenderer = $this->getLinkRenderer();
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  '>' .
248  $linkRenderer->makeLink( $t ) .
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 
304  $linkRenderer = $this->getLinkRenderer();
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 }
SpecialAllPages\getGroupName
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Definition: SpecialAllPages.php:404
SpecialPage\$linkRenderer
LinkRenderer null $linkRenderer
Definition: SpecialPage.php:80
SpecialPage\getPageTitle
getPageTitle( $subpage=false)
Get a self-referential title object.
Definition: SpecialPage.php:744
SpecialPage\msg
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:912
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:790
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:193
SpecialAllPages\execute
execute( $par)
Entry point : initialise variables and call subfunctions.
Definition: SpecialAllPages.php:75
SpecialAllPages\$maxPerPage
int $maxPerPage
Maximum number of pages to show on single subpage.
Definition: SpecialAllPages.php:40
SpecialAllPages\showToplevel
showToplevel( $namespace=NS_MAIN, $from='', $to='', $hideredirects=false)
Definition: SpecialAllPages.php:178
SearchEngineFactory
Factory class for SearchEngine.
Definition: SearchEngineFactory.php:12
IncludableSpecialPage
Shortcut to construct an includable special page.
Definition: IncludableSpecialPage.php:29
SpecialPage\getLanguage
getLanguage()
Shortcut to get user's language.
Definition: SpecialPage.php:830
$res
$res
Definition: testCompression.php:57
NS_MAIN
const NS_MAIN
Definition: Defines.php:64
$dbr
$dbr
Definition: testCompression.php:54
SpecialPage\prefixSearchString
prefixSearchString( $search, $limit, $offset, SearchEngineFactory $searchEngineFactory=null)
Perform a regular substring search for prefixSearchSubpages.
Definition: SpecialPage.php:577
Html\closeElement
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:316
DerivativeContext
An IContextSource implementation which will inherit context from another source but allow individual ...
Definition: DerivativeContext.php:32
SpecialPage\getConfig
getConfig()
Shortcut to get main config object.
Definition: SpecialPage.php:878
SpecialAllPages\$loadBalancer
ILoadBalancer $loadBalancer
Definition: SpecialAllPages.php:50
Title\newFromRow
static newFromRow( $row)
Make a Title object from a DB row.
Definition: Title.php:579
SpecialPage\setHeaders
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
Definition: SpecialPage.php:618
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:650
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
SpecialPage\getContext
getContext()
Gets the context this SpecialPage is executed in.
Definition: SpecialPage.php:764
SpecialAllPages\$searchEngineFactory
SearchEngineFactory $searchEngineFactory
Definition: SpecialAllPages.php:53
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:676
$s
foreach( $mmfl['setupFiles'] as $fileName) if( $queue) if(empty( $mmfl['quiet'])) $s
Definition: mergeMessageFileList.php:206
SpecialAllPages\prefixSearchSubpages
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
Definition: SpecialAllPages.php:400
SpecialAllPages\outputHTMLForm
outputHTMLForm( $namespace=NS_MAIN, $from='', $to='', $hideRedirects=false)
Outputs the HTMLForm used on this page.
Definition: SpecialAllPages.php:119
SpecialAllPages\__construct
__construct(ILoadBalancer $loadBalancer=null, SearchEngineFactory $searchEngineFactory=null)
Definition: SpecialAllPages.php:59
SpecialAllPages\getNamespaceKeyAndText
getNamespaceKeyAndText( $ns, $text)
Definition: SpecialAllPages.php:369
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:780
SpecialPage\getLinkRenderer
getLinkRenderer()
Definition: SpecialPage.php:1028
$self
$self
Definition: doMaintenance.php:63
SpecialAllPages
Implements Special:Allpages.
Definition: SpecialAllPages.php:33
Html\openElement
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition: Html.php:252
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:210
SpecialAllPages\showChunk
showChunk( $namespace=NS_MAIN, $from=false, $to=false, $hideredirects=false)
Definition: SpecialAllPages.php:195
$t
$t
Definition: testCompression.php:74
Html\element
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:232
SpecialAllPages\$nsfromMsg
string $nsfromMsg
Determines, which message describes the input field 'nsfrom'.
Definition: SpecialAllPages.php:47
HTMLForm\factory
static factory( $displayFormat,... $arguments)
Construct a HTMLForm object for given display type.
Definition: HTMLForm.php:326
SpecialPage\outputHeader
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
Definition: SpecialPage.php:709
SpecialPage\including
including( $x=null)
Whether the special page is being evaluated via transclusion.
Definition: SpecialPage.php:266
Wikimedia\Rdbms\ILoadBalancer
Database cluster connection, tracking, load balancing, and transaction manager interface.
Definition: ILoadBalancer.php:81